Import static file tests from Katana.
This commit is contained in:
parent
b49b46c5b6
commit
2c4811f201
|
|
@ -1,7 +1,7 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 14
|
||||
VisualStudioVersion = 14.0.21628.1
|
||||
VisualStudioVersion = 14.0.21916.0
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{40EE0889-960E-41B4-A3D3-9CE963EB0797}"
|
||||
EndProject
|
||||
|
|
@ -11,6 +11,15 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.StaticFile
|
|||
EndProject
|
||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "StaticFileSample", "samples\StaticFileSample\StaticFileSample.kproj", "{092141D9-305A-4FC5-AE74-CB23982CA8D4}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{EF02AFE8-7C15-4DDB-8B2C-58A676112A98}"
|
||||
EndProject
|
||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.StaticFiles.Tests", "test\Microsoft.AspNet.StaticFiles.Tests\Microsoft.AspNet.StaticFiles.Tests.kproj", "{CC87FE7D-8F42-4BE9-A152-9625E837C1E5}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{5EE39BF7-6457-432B-B26B-53B77A1C03D9}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
global.json = global.json
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
|
@ -21,27 +30,36 @@ Global
|
|||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{8D7BC5A4-F19C-4184-8338-A6B42997218C}.Debug|Any CPU.ActiveCfg = Debug|x86
|
||||
{8D7BC5A4-F19C-4184-8338-A6B42997218C}.Debug|Any CPU.Build.0 = Debug|x86
|
||||
{8D7BC5A4-F19C-4184-8338-A6B42997218C}.Debug|Mixed Platforms.ActiveCfg = Debug|x86
|
||||
{8D7BC5A4-F19C-4184-8338-A6B42997218C}.Debug|Mixed Platforms.Build.0 = Debug|x86
|
||||
{8D7BC5A4-F19C-4184-8338-A6B42997218C}.Debug|x86.ActiveCfg = Debug|x86
|
||||
{8D7BC5A4-F19C-4184-8338-A6B42997218C}.Debug|x86.Build.0 = Debug|x86
|
||||
{8D7BC5A4-F19C-4184-8338-A6B42997218C}.Release|Any CPU.ActiveCfg = Release|x86
|
||||
{8D7BC5A4-F19C-4184-8338-A6B42997218C}.Release|Mixed Platforms.ActiveCfg = Release|x86
|
||||
{8D7BC5A4-F19C-4184-8338-A6B42997218C}.Release|Mixed Platforms.Build.0 = Release|x86
|
||||
{8D7BC5A4-F19C-4184-8338-A6B42997218C}.Release|x86.ActiveCfg = Release|x86
|
||||
{8D7BC5A4-F19C-4184-8338-A6B42997218C}.Release|x86.Build.0 = Release|x86
|
||||
{092141D9-305A-4FC5-AE74-CB23982CA8D4}.Debug|Any CPU.ActiveCfg = Debug|x86
|
||||
{092141D9-305A-4FC5-AE74-CB23982CA8D4}.Debug|Any CPU.Build.0 = Debug|x86
|
||||
{092141D9-305A-4FC5-AE74-CB23982CA8D4}.Debug|Mixed Platforms.ActiveCfg = Debug|x86
|
||||
{092141D9-305A-4FC5-AE74-CB23982CA8D4}.Debug|x86.ActiveCfg = Debug|x86
|
||||
{092141D9-305A-4FC5-AE74-CB23982CA8D4}.Debug|x86.Build.0 = Debug|x86
|
||||
{092141D9-305A-4FC5-AE74-CB23982CA8D4}.Release|Any CPU.ActiveCfg = Release|x86
|
||||
{092141D9-305A-4FC5-AE74-CB23982CA8D4}.Release|Mixed Platforms.ActiveCfg = Release|x86
|
||||
{092141D9-305A-4FC5-AE74-CB23982CA8D4}.Release|Mixed Platforms.Build.0 = Release|x86
|
||||
{092141D9-305A-4FC5-AE74-CB23982CA8D4}.Release|x86.ActiveCfg = Release|x86
|
||||
{092141D9-305A-4FC5-AE74-CB23982CA8D4}.Release|x86.Build.0 = Release|x86
|
||||
{8D7BC5A4-F19C-4184-8338-A6B42997218C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{8D7BC5A4-F19C-4184-8338-A6B42997218C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{8D7BC5A4-F19C-4184-8338-A6B42997218C}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||
{8D7BC5A4-F19C-4184-8338-A6B42997218C}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||
{8D7BC5A4-F19C-4184-8338-A6B42997218C}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{8D7BC5A4-F19C-4184-8338-A6B42997218C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{8D7BC5A4-F19C-4184-8338-A6B42997218C}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{8D7BC5A4-F19C-4184-8338-A6B42997218C}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||
{8D7BC5A4-F19C-4184-8338-A6B42997218C}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{8D7BC5A4-F19C-4184-8338-A6B42997218C}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{092141D9-305A-4FC5-AE74-CB23982CA8D4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{092141D9-305A-4FC5-AE74-CB23982CA8D4}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{092141D9-305A-4FC5-AE74-CB23982CA8D4}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||
{092141D9-305A-4FC5-AE74-CB23982CA8D4}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||
{092141D9-305A-4FC5-AE74-CB23982CA8D4}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{092141D9-305A-4FC5-AE74-CB23982CA8D4}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{092141D9-305A-4FC5-AE74-CB23982CA8D4}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{092141D9-305A-4FC5-AE74-CB23982CA8D4}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||
{092141D9-305A-4FC5-AE74-CB23982CA8D4}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{092141D9-305A-4FC5-AE74-CB23982CA8D4}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{CC87FE7D-8F42-4BE9-A152-9625E837C1E5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{CC87FE7D-8F42-4BE9-A152-9625E837C1E5}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{CC87FE7D-8F42-4BE9-A152-9625E837C1E5}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||
{CC87FE7D-8F42-4BE9-A152-9625E837C1E5}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||
{CC87FE7D-8F42-4BE9-A152-9625E837C1E5}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{CC87FE7D-8F42-4BE9-A152-9625E837C1E5}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{CC87FE7D-8F42-4BE9-A152-9625E837C1E5}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{CC87FE7D-8F42-4BE9-A152-9625E837C1E5}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||
{CC87FE7D-8F42-4BE9-A152-9625E837C1E5}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{CC87FE7D-8F42-4BE9-A152-9625E837C1E5}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
@ -49,5 +67,6 @@ Global
|
|||
GlobalSection(NestedProjects) = preSolution
|
||||
{8D7BC5A4-F19C-4184-8338-A6B42997218C} = {40EE0889-960E-41B4-A3D3-9CE963EB0797}
|
||||
{092141D9-305A-4FC5-AE74-CB23982CA8D4} = {8B21A3A9-9CA6-4857-A6E0-1A3203404B60}
|
||||
{CC87FE7D-8F42-4BE9-A152-9625E837C1E5} = {EF02AFE8-7C15-4DDB-8B2C-58A676112A98}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ namespace Microsoft.AspNet.StaticFiles
|
|||
if (!Helpers.PathEndsInSlash(context.Request.Path))
|
||||
{
|
||||
context.Response.StatusCode = 301;
|
||||
context.Response.Headers[Constants.Location] = context.Request.PathBase + context.Request.Path + "/";
|
||||
context.Response.Headers[Constants.Location] = context.Request.PathBase + context.Request.Path + "/" + context.Request.QueryString;
|
||||
return Constants.CompletedTask;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ namespace Microsoft.AspNet.StaticFiles
|
|||
if (!Helpers.PathEndsInSlash(context.Request.Path))
|
||||
{
|
||||
context.Response.StatusCode = 301;
|
||||
context.Response.Headers[Constants.Location] = context.Request.PathBase + context.Request.Path + "/";
|
||||
context.Response.Headers[Constants.Location] = context.Request.PathBase + context.Request.Path + "/" + context.Request.QueryString;
|
||||
return Constants.CompletedTask;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,253 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Builder;
|
||||
using Microsoft.AspNet.TestHost;
|
||||
using Shouldly;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.StaticFiles
|
||||
{
|
||||
public class CacheHeaderTests
|
||||
{
|
||||
[Fact]
|
||||
public async Task ServerShouldReturnETag()
|
||||
{
|
||||
TestServer server = TestServer.Create(app => app.UseFileServer());
|
||||
|
||||
HttpResponseMessage response = await server.CreateClient().GetAsync("http://localhost/SubFolder/Extra.xml");
|
||||
response.Headers.ETag.ShouldNotBe(null);
|
||||
response.Headers.ETag.Tag.ShouldNotBe(null);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SameETagShouldBeReturnedAgain()
|
||||
{
|
||||
TestServer server = TestServer.Create(app => app.UseFileServer());
|
||||
|
||||
HttpResponseMessage response1 = await server.CreateClient().GetAsync("http://localhost/SubFolder/Extra.xml");
|
||||
HttpResponseMessage response2 = await server.CreateClient().GetAsync("http://localhost/SubFolder/Extra.xml");
|
||||
response1.Headers.ETag.ShouldBe(response2.Headers.ETag);
|
||||
}
|
||||
|
||||
// 14.24 If-Match
|
||||
// If none of the entity tags match, or if "*" is given and no current
|
||||
// entity exists, the server MUST NOT perform the requested method, and
|
||||
// MUST return a 412 (Precondition Failed) response. This behavior is
|
||||
// most useful when the client wants to prevent an updating method, such
|
||||
// as PUT, from modifying a resource that has changed since the client
|
||||
// last retrieved it.
|
||||
|
||||
[Fact]
|
||||
public async Task IfMatchShouldReturn412WhenNotListed()
|
||||
{
|
||||
TestServer server = TestServer.Create(app => app.UseFileServer());
|
||||
var req = new HttpRequestMessage(HttpMethod.Get, "http://localhost/SubFolder/Extra.xml");
|
||||
req.Headers.Add("If-Match", "\"fake\"");
|
||||
HttpResponseMessage resp = await server.CreateClient().SendAsync(req);
|
||||
resp.StatusCode.ShouldBe(HttpStatusCode.PreconditionFailed);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task IfMatchShouldBeServedWhenListed()
|
||||
{
|
||||
TestServer server = TestServer.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");
|
||||
req.Headers.Add("If-Match", original.Headers.ETag.ToString());
|
||||
HttpResponseMessage resp = await server.CreateClient().SendAsync(req);
|
||||
resp.StatusCode.ShouldBe(HttpStatusCode.OK);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task IfMatchShouldBeServedForAstrisk()
|
||||
{
|
||||
TestServer server = TestServer.Create(app => app.UseFileServer());
|
||||
var req = new HttpRequestMessage(HttpMethod.Get, "http://localhost/SubFolder/Extra.xml");
|
||||
req.Headers.Add("If-Match", "*");
|
||||
HttpResponseMessage resp = await server.CreateClient().SendAsync(req);
|
||||
resp.StatusCode.ShouldBe(HttpStatusCode.OK);
|
||||
}
|
||||
|
||||
// 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
|
||||
// (without the If-None-Match header) on that resource, or if "*" is
|
||||
// given and any current entity exists for that resource, then the
|
||||
// server MUST NOT perform the requested method, unless required to do
|
||||
// so because the resource's modification date fails to match that
|
||||
// supplied in an If-Modified-Since header field in the request.
|
||||
// Instead, if the request method was GET or HEAD, the server SHOULD
|
||||
// respond with a 304 (Not Modified) response, including the cache-
|
||||
// related header fields (particularly ETag) of one of the entities that
|
||||
// matched. For all other request methods, the server MUST respond with
|
||||
// a status of 412 (Precondition Failed).
|
||||
|
||||
[Fact]
|
||||
public async Task IfNoneMatchShouldReturn304ForMatchingOnGetAndHeadMethod()
|
||||
{
|
||||
TestServer server = TestServer.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");
|
||||
req2.Headers.Add("If-None-Match", resp1.Headers.ETag.ToString());
|
||||
HttpResponseMessage resp2 = await server.CreateClient().SendAsync(req2);
|
||||
resp2.StatusCode.ShouldBe(HttpStatusCode.NotModified);
|
||||
|
||||
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);
|
||||
resp3.StatusCode.ShouldBe(HttpStatusCode.NotModified);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task IfNoneMatchShouldBeIgnoredForNonTwoHundredAnd304Responses()
|
||||
{
|
||||
TestServer server = TestServer.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");
|
||||
req2.Headers.Add("If-None-Match", resp1.Headers.ETag.ToString());
|
||||
HttpResponseMessage resp2 = await server.CreateClient().SendAsync(req2);
|
||||
resp2.StatusCode.ShouldBe(HttpStatusCode.NotFound);
|
||||
|
||||
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);
|
||||
resp3.StatusCode.ShouldBe(HttpStatusCode.NotFound);
|
||||
}
|
||||
|
||||
// 14.26 If-None-Match
|
||||
// If none of the entity tags match, then the server MAY perform the
|
||||
// requested method as if the If-None-Match header field did not exist,
|
||||
// but MUST also ignore any If-Modified-Since header field(s) in the
|
||||
// request. That is, if no entity tags match, then the server MUST NOT
|
||||
// return a 304 (Not Modified) response.
|
||||
|
||||
// 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()
|
||||
{
|
||||
TestServer server = TestServer.Create(app => app.UseFileServer());
|
||||
|
||||
HttpResponseMessage response = await server.CreateClient().GetAsync("http://localhost/SubFolder/Extra.xml");
|
||||
response.Content.Headers.LastModified.ShouldNotBe(null);
|
||||
}
|
||||
|
||||
// 13.3.4
|
||||
// An HTTP/1.1 origin server, upon receiving a conditional request that
|
||||
// includes both a Last-Modified date (e.g., in an If-Modified-Since or
|
||||
// If-Unmodified-Since header field) and one or more entity tags (e.g.,
|
||||
// in an If-Match, If-None-Match, or If-Range header field) as cache
|
||||
// validators, MUST NOT return a response status of 304 (Not Modified)
|
||||
// unless doing so is consistent with all of the conditional header
|
||||
// fields in the request.
|
||||
|
||||
[Fact]
|
||||
public async Task MatchingBothConditionsReturnsNotModified()
|
||||
{
|
||||
TestServer server = TestServer.Create(app => app.UseFileServer());
|
||||
HttpResponseMessage resp1 = await server
|
||||
.CreateRequest("/SubFolder/Extra.xml")
|
||||
.GetAsync();
|
||||
|
||||
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();
|
||||
|
||||
resp2.StatusCode.ShouldBe(HttpStatusCode.NotModified);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task MissingEitherOrBothConditionsReturnsNormally()
|
||||
{
|
||||
TestServer server = TestServer.Create(app => app.UseFileServer());
|
||||
HttpResponseMessage resp1 = await server
|
||||
.CreateRequest("/SubFolder/Extra.xml")
|
||||
.GetAsync();
|
||||
|
||||
DateTimeOffset lastModified = resp1.Content.Headers.LastModified.Value;
|
||||
DateTimeOffset pastDate = lastModified.AddHours(-1);
|
||||
DateTimeOffset furtureDate = lastModified.AddHours(1);
|
||||
|
||||
HttpResponseMessage resp2 = await server
|
||||
.CreateRequest("/SubFolder/Extra.xml")
|
||||
.AddHeader("If-None-Match", "\"fake\"")
|
||||
.And(req => req.Headers.IfModifiedSince = lastModified)
|
||||
.GetAsync();
|
||||
|
||||
HttpResponseMessage resp3 = await server
|
||||
.CreateRequest("/SubFolder/Extra.xml")
|
||||
.AddHeader("If-None-Match", resp1.Headers.ETag.ToString())
|
||||
.And(req => req.Headers.IfModifiedSince = pastDate)
|
||||
.GetAsync();
|
||||
|
||||
HttpResponseMessage resp4 = await server
|
||||
.CreateRequest("/SubFolder/Extra.xml")
|
||||
.AddHeader("If-None-Match", "\"fake\"")
|
||||
.And(req => req.Headers.IfModifiedSince = furtureDate)
|
||||
.GetAsync();
|
||||
|
||||
resp2.StatusCode.ShouldBe(HttpStatusCode.OK);
|
||||
resp3.StatusCode.ShouldBe(HttpStatusCode.OK);
|
||||
resp4.StatusCode.ShouldBe(HttpStatusCode.OK);
|
||||
}
|
||||
|
||||
// 14.25 If-Modified-Since
|
||||
// The If-Modified-Since request-header field is used with a method to
|
||||
// make it conditional: if the requested variant has not been modified
|
||||
// since the time specified in this field, an entity will not be
|
||||
// returned from the server; instead, a 304 (not modified) response will
|
||||
// be returned without any message-body.
|
||||
|
||||
// a) If the request would normally result in anything other than a
|
||||
// 200 (OK) status, or if the passed If-Modified-Since date is
|
||||
// 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()
|
||||
{
|
||||
TestServer server = TestServer.Create(app => app.UseFileServer());
|
||||
|
||||
HttpResponseMessage res = await server
|
||||
.CreateRequest("/SubFolder/Extra.xml")
|
||||
.AddHeader("If-Modified-Since", "bad-date")
|
||||
.GetAsync();
|
||||
|
||||
res.StatusCode.ShouldBe(HttpStatusCode.OK);
|
||||
}
|
||||
|
||||
// b) If the variant has been modified since the If-Modified-Since
|
||||
// date, the response is exactly the same as for a normal GET.
|
||||
|
||||
// c) If the variant has not been modified since a valid If-
|
||||
// Modified-Since date, the server SHOULD return a 304 (Not
|
||||
// Modified) response.
|
||||
|
||||
[Fact]
|
||||
public async Task IfModifiedSinceDateEqualsLastModifiedShouldReturn304()
|
||||
{
|
||||
TestServer server = TestServer.Create(app => app.UseFileServer());
|
||||
|
||||
HttpResponseMessage res1 = await server
|
||||
.CreateRequest("/SubFolder/Extra.xml")
|
||||
.GetAsync();
|
||||
|
||||
HttpResponseMessage res2 = await server
|
||||
.CreateRequest("/SubFolder/Extra.xml")
|
||||
.And(req => req.Headers.IfModifiedSince = res1.Content.Headers.LastModified)
|
||||
.GetAsync();
|
||||
|
||||
res2.StatusCode.ShouldBe(HttpStatusCode.NotModified);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
|
||||
|
||||
using Shouldly;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.StaticFiles
|
||||
{
|
||||
public class DefaultContentTypeProviderTests
|
||||
{
|
||||
[Fact]
|
||||
public void UnknownExtensionsReturnFalse()
|
||||
{
|
||||
var provider = new FileExtensionContentTypeProvider();
|
||||
string contentType;
|
||||
provider.TryGetContentType("unknown.ext", out contentType).ShouldBe(false);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void KnownExtensionsReturnTrye()
|
||||
{
|
||||
var provider = new FileExtensionContentTypeProvider();
|
||||
string contentType;
|
||||
provider.TryGetContentType("known.txt", out contentType).ShouldBe(true);
|
||||
contentType.ShouldBe("text/plain");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DoubleDottedExtensionsAreNotSupported()
|
||||
{
|
||||
var provider = new FileExtensionContentTypeProvider();
|
||||
string contentType;
|
||||
provider.TryGetContentType("known.exe.config", out contentType).ShouldBe(false);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DashedExtensionsShouldBeMatched()
|
||||
{
|
||||
var provider = new FileExtensionContentTypeProvider();
|
||||
string contentType;
|
||||
provider.TryGetContentType("known.dvr-ms", out contentType).ShouldBe(true);
|
||||
contentType.ShouldBe("video/x-ms-dvr");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BothSlashFormatsAreUnderstood()
|
||||
{
|
||||
var provider = new FileExtensionContentTypeProvider();
|
||||
string contentType;
|
||||
provider.TryGetContentType(@"/first/example.txt", out contentType).ShouldBe(true);
|
||||
contentType.ShouldBe("text/plain");
|
||||
provider.TryGetContentType(@"\second\example.txt", out contentType).ShouldBe(true);
|
||||
contentType.ShouldBe("text/plain");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DotsInDirectoryAreIgnored()
|
||||
{
|
||||
var provider = new FileExtensionContentTypeProvider();
|
||||
string contentType;
|
||||
provider.TryGetContentType(@"/first.css/example.txt", out contentType).ShouldBe(true);
|
||||
contentType.ShouldBe("text/plain");
|
||||
provider.TryGetContentType(@"\second.css\example.txt", out contentType).ShouldBe(true);
|
||||
contentType.ShouldBe("text/plain");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,118 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Builder;
|
||||
using Microsoft.AspNet.FileSystems;
|
||||
using Microsoft.AspNet.Http;
|
||||
using Microsoft.AspNet.PipelineCore;
|
||||
using Microsoft.AspNet.TestHost;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.StaticFiles
|
||||
{
|
||||
public class DefaultFilesMiddlewareTests
|
||||
{
|
||||
[Fact]
|
||||
public async Task NullArguments()
|
||||
{
|
||||
Assert.Throws<ArgumentNullException>(() => TestServer.Create(app => app.UseDefaultFiles((DefaultFilesOptions)null)));
|
||||
|
||||
// No exception, default provided
|
||||
TestServer.Create(app => app.UseDefaultFiles(new DefaultFilesOptions() { FileSystem = null }));
|
||||
|
||||
// PathString(null) is OK.
|
||||
TestServer server = TestServer.Create(app => app.UseDefaultFiles((string)null));
|
||||
var response = await server.CreateClient().GetAsync("/");
|
||||
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("", @"", "/missing.dir")]
|
||||
[InlineData("", @".", "/missing.dir/")]
|
||||
[InlineData("/subdir", @".", "/subdir/missing.dir")]
|
||||
[InlineData("/subdir", @"", "/subdir/missing.dir/")]
|
||||
[InlineData("", @"\", "/missing.dir")]
|
||||
public async Task NoMatch_PassesThrough(string baseUrl, string baseDir, string requestUrl)
|
||||
{
|
||||
TestServer server = TestServer.Create(app =>
|
||||
{
|
||||
app.UseDefaultFiles(new DefaultFilesOptions()
|
||||
{
|
||||
RequestPath = new PathString(baseUrl),
|
||||
FileSystem = new PhysicalFileSystem(baseDir)
|
||||
});
|
||||
app.Run(context => context.Response.WriteAsync(context.Request.Path.Value));
|
||||
});
|
||||
|
||||
var response = await server.CreateClient().GetAsync(requestUrl);
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.Equal(requestUrl, await response.Content.ReadAsStringAsync()); // Should not be modified
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("", @"", "/SubFolder/")]
|
||||
[InlineData("", @".", "/SubFolder/")]
|
||||
[InlineData("", @".\", "/SubFolder/")]
|
||||
[InlineData("", @"SubFolder", "/")]
|
||||
[InlineData("", @".\SubFolder", "/")]
|
||||
public async Task FoundDirectoryWithDefaultFile_PathModified(string baseUrl, string baseDir, string requestUrl)
|
||||
{
|
||||
TestServer server = TestServer.Create(app =>
|
||||
{
|
||||
app.UseDefaultFiles(new DefaultFilesOptions()
|
||||
{
|
||||
RequestPath = new PathString(baseUrl),
|
||||
FileSystem = new PhysicalFileSystem(baseDir)
|
||||
});
|
||||
app.Run(context => context.Response.WriteAsync(context.Request.Path.Value));
|
||||
});
|
||||
|
||||
var response = await server.CreateClient().GetAsync(requestUrl);
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.Equal(requestUrl + "default.html", await response.Content.ReadAsStringAsync()); // Should be modified
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("", @"", "/SubFolder", "")]
|
||||
[InlineData("", @".", "/SubFolder", "")]
|
||||
[InlineData("", @".\", "/SubFolder", "")]
|
||||
[InlineData("", @".\", "/SubFolder", "?a=b")]
|
||||
[InlineData("", @".\", "/SubFolder", "?a=b")]
|
||||
[InlineData("", @".\", "/SubFolder", "?a=b")]
|
||||
public async Task NearMatch_RedirectAddSlash(string baseUrl, string baseDir, string requestUrl, string queryString)
|
||||
{
|
||||
TestServer server = TestServer.Create(app => app.UseDefaultFiles(new DefaultFilesOptions()
|
||||
{
|
||||
RequestPath = new PathString(baseUrl),
|
||||
FileSystem = new PhysicalFileSystem(baseDir)
|
||||
}));
|
||||
HttpResponseMessage response = await server.CreateRequest(requestUrl + queryString).GetAsync();
|
||||
|
||||
Assert.Equal(HttpStatusCode.Moved, response.StatusCode);
|
||||
Assert.Equal(requestUrl + "/" + queryString, response.Headers.Location.ToString());
|
||||
Assert.Equal(0, (await response.Content.ReadAsByteArrayAsync()).Length);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("/SubFolder", @"\", "/SubFolder/")]
|
||||
[InlineData("/SubFolder", @"", "/somedir/")]
|
||||
[InlineData("", @".\SubFolder", "/")]
|
||||
[InlineData("", @".\SubFolder\", "/")]
|
||||
public async Task PostDirectory_PassesThrough(string baseUrl, string baseDir, string requestUrl)
|
||||
{
|
||||
TestServer server = TestServer.Create(app => app.UseDefaultFiles(new DefaultFilesOptions()
|
||||
{
|
||||
RequestPath = new PathString(baseUrl),
|
||||
FileSystem = new PhysicalFileSystem(baseDir)
|
||||
}));
|
||||
HttpResponseMessage response = await server.CreateRequest(requestUrl).GetAsync();
|
||||
|
||||
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode); // Passed through
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,135 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Builder;
|
||||
using Microsoft.AspNet.FileSystems;
|
||||
using Microsoft.AspNet.Http;
|
||||
using Microsoft.AspNet.TestHost;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.StaticFiles
|
||||
{
|
||||
public class DirectoryBrowserMiddlewareTests
|
||||
{
|
||||
[Fact]
|
||||
public async Task NullArguments()
|
||||
{
|
||||
Assert.Throws<ArgumentNullException>(() => TestServer.Create(app => app.UseDirectoryBrowser((DirectoryBrowserOptions)null)));
|
||||
Assert.Throws<ArgumentException>(() => TestServer.Create(app => app.UseDirectoryBrowser(new DirectoryBrowserOptions() { Formatter = null })));
|
||||
|
||||
// No exception, default provided
|
||||
TestServer.Create(app => app.UseDirectoryBrowser(new DirectoryBrowserOptions() { FileSystem = null }));
|
||||
|
||||
// PathString(null) is OK.
|
||||
TestServer server = TestServer.Create(app => app.UseDirectoryBrowser((string)null));
|
||||
var response = await server.CreateClient().GetAsync("/");
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("", @"", "/missing.dir")]
|
||||
[InlineData("", @".", "/missing.dir/")]
|
||||
[InlineData("/subdir", @".", "/subdir/missing.dir")]
|
||||
[InlineData("/subdir", @"", "/subdir/missing.dir/")]
|
||||
[InlineData("", @"\", "/missing.dir")]
|
||||
public async Task NoMatch_PassesThrough(string baseUrl, string baseDir, string requestUrl)
|
||||
{
|
||||
TestServer server = TestServer.Create(app => app.UseDirectoryBrowser(new DirectoryBrowserOptions()
|
||||
{
|
||||
RequestPath = new PathString(baseUrl),
|
||||
FileSystem = new PhysicalFileSystem(baseDir)
|
||||
}));
|
||||
HttpResponseMessage response = await server.CreateRequest(requestUrl).GetAsync();
|
||||
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("", @"", "/")]
|
||||
[InlineData("", @".", "/")]
|
||||
[InlineData("", @"", "/SubFolder/")]
|
||||
[InlineData("", @".", "/SubFolder/")]
|
||||
[InlineData("/somedir", @"", "/somedir/")]
|
||||
[InlineData("/somedir", @"\", "/somedir/")]
|
||||
[InlineData("/somedir", @".", "/somedir/subfolder/")]
|
||||
public async Task FoundDirectory_Served(string baseUrl, string baseDir, string requestUrl)
|
||||
{
|
||||
TestServer server = TestServer.Create(app => app.UseDirectoryBrowser(new DirectoryBrowserOptions()
|
||||
{
|
||||
RequestPath = new PathString(baseUrl),
|
||||
FileSystem = new PhysicalFileSystem(baseDir)
|
||||
}));
|
||||
HttpResponseMessage response = await server.CreateRequest(requestUrl).GetAsync();
|
||||
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.Equal("text/html; charset=utf-8", response.Content.Headers.ContentType.ToString());
|
||||
Assert.True(response.Content.Headers.ContentLength > 0);
|
||||
Assert.Equal(response.Content.Headers.ContentLength, (await response.Content.ReadAsByteArrayAsync()).Length);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("", @"", "/SubFolder", "")]
|
||||
[InlineData("", @".", "/SubFolder", "")]
|
||||
[InlineData("/somedir", @"", "/somedir", "")]
|
||||
[InlineData("/somedir", @".", "/somedir/subfolder", "")]
|
||||
[InlineData("", @"", "/SubFolder", "?a=b")]
|
||||
[InlineData("", @".", "/SubFolder", "?a=b")]
|
||||
[InlineData("/somedir", @"", "/somedir", "?a=b")]
|
||||
[InlineData("/somedir", @".", "/somedir/subfolder", "?a=b")]
|
||||
public async Task NearMatch_RedirectAddSlash(string baseUrl, string baseDir, string requestUrl, string queryString)
|
||||
{
|
||||
TestServer server = TestServer.Create(app => app.UseDirectoryBrowser(new DirectoryBrowserOptions()
|
||||
{
|
||||
RequestPath = new PathString(baseUrl),
|
||||
FileSystem = new PhysicalFileSystem(baseDir)
|
||||
}));
|
||||
HttpResponseMessage response = await server.CreateRequest(requestUrl + queryString).GetAsync();
|
||||
|
||||
Assert.Equal(HttpStatusCode.Moved, response.StatusCode);
|
||||
Assert.Equal(requestUrl + "/" + queryString, response.Headers.Location.ToString());
|
||||
Assert.Equal(0, (await response.Content.ReadAsByteArrayAsync()).Length);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("", @"", "/")]
|
||||
[InlineData("", @".", "/")]
|
||||
[InlineData("", @"", "/SubFolder/")]
|
||||
[InlineData("", @".", "/SubFolder/")]
|
||||
[InlineData("/somedir", @"", "/somedir/")]
|
||||
[InlineData("/somedir", @".", "/somedir/subfolder/")]
|
||||
public async Task PostDirectory_PassesThrough(string baseUrl, string baseDir, string requestUrl)
|
||||
{
|
||||
TestServer server = TestServer.Create(app => app.UseDirectoryBrowser(new DirectoryBrowserOptions()
|
||||
{
|
||||
RequestPath = new PathString(baseUrl),
|
||||
FileSystem = new PhysicalFileSystem(baseDir)
|
||||
}));
|
||||
HttpResponseMessage response = await server.CreateRequest(requestUrl).PostAsync();
|
||||
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("", @"", "/")]
|
||||
[InlineData("", @".", "/")]
|
||||
[InlineData("", @"", "/SubFolder/")]
|
||||
[InlineData("", @".", "/SubFolder/")]
|
||||
[InlineData("/somedir", @"", "/somedir/")]
|
||||
[InlineData("/somedir", @".", "/somedir/subfolder/")]
|
||||
public async Task HeadDirectory_HeadersButNotBodyServed(string baseUrl, string baseDir, string requestUrl)
|
||||
{
|
||||
TestServer server = TestServer.Create(app => app.UseDirectoryBrowser(new DirectoryBrowserOptions()
|
||||
{
|
||||
RequestPath = new PathString(baseUrl),
|
||||
FileSystem = new PhysicalFileSystem(baseDir)
|
||||
}));
|
||||
HttpResponseMessage response = await server.CreateRequest(requestUrl).SendAsync("HEAD");
|
||||
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.Equal("text/html; charset=utf-8", response.Content.Headers.ContentType.ToString());
|
||||
Assert.True(response.Content.Headers.ContentLength == 0);
|
||||
Assert.Equal(0, (await response.Content.ReadAsByteArrayAsync()).Length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="__ToolsVersion__" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">12.0</VisualStudioVersion>
|
||||
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VSToolsPath)\AspNet\Microsoft.Web.AspNet.Props" Condition="'$(VSToolsPath)' != ''" />
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>cc87fe7d-8f42-4be9-a152-9625e837c1e5</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="$(OutputType) == 'Console'">
|
||||
<DebuggerFlavor>ConsoleDebugger</DebuggerFlavor>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="$(OutputType) == 'Web'">
|
||||
<DebuggerFlavor>WebDebugger</DebuggerFlavor>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x86'" Label="Configuration">
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x86'" Label="Configuration">
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="Project.json" />
|
||||
<Content Include="SubFolder\Default.html" />
|
||||
<Content Include="SubFolder\Extra.xml" />
|
||||
<Content Include="SubFolder\Ranges.txt" />
|
||||
<Content Include="TestDocument.txt" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="CacheHeaderTests.cs" />
|
||||
<Compile Include="DefaultContentTypeProviderTests.cs" />
|
||||
<Compile Include="DefaultFilesMiddlewareTests.cs" />
|
||||
<Compile Include="DirectoryBrowserMiddlewareTests.cs" />
|
||||
<Compile Include="RangeHeaderTests.cs" />
|
||||
<Compile Include="SendFileResponseExtensionsTests.cs" />
|
||||
<Compile Include="StaticFileMiddlewareTests.cs" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VSToolsPath)\AspNet\Microsoft.Web.AspNet.targets" Condition="'$(VSToolsPath)' != ''" />
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
"dependencies": {
|
||||
"Microsoft.AspNet.PipelineCore": "1.0.0-*",
|
||||
"Microsoft.AspNet.Http": "1.0.0-*",
|
||||
"Microsoft.AspNet.HttpFeature": "1.0.0-*",
|
||||
"Microsoft.AspNet.StaticFiles": "",
|
||||
"Microsoft.AspNet.TestHost": "1.0.0-*",
|
||||
"Xunit.KRunner": "1.0.0-*"
|
||||
},
|
||||
"commands": {
|
||||
"test": "Xunit.KRunner"
|
||||
},
|
||||
"frameworks": {
|
||||
"net45": {
|
||||
"dependencies": {
|
||||
"Shouldly": "1.1.1.1",
|
||||
"System.Runtime": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,359 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Builder;
|
||||
using Microsoft.AspNet.TestHost;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.StaticFiles
|
||||
{
|
||||
public class RangeHeaderTests
|
||||
{
|
||||
// 14.27 If-Range
|
||||
// If the entity tag given in the If-Range header matches the current entity tag for the entity, then the server SHOULD
|
||||
// provide the specified sub-range of the entity using a 206 (Partial content) response.
|
||||
[Fact]
|
||||
public async Task IfRangeWithCurrentEtagShouldServePartialContent()
|
||||
{
|
||||
TestServer server = TestServer.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-Range", original.Headers.ETag.ToString());
|
||||
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());
|
||||
}
|
||||
|
||||
// 14.27 If-Range
|
||||
// If the entity tag given in the If-Range header matches the current entity tag for the entity, then the server SHOULD
|
||||
// provide the specified sub-range of the entity using a 206 (Partial content) response.
|
||||
// HEAD requests should ignore the Range header
|
||||
[Fact]
|
||||
public async Task HEADIfRangeWithCurrentEtagShouldReturn200Ok()
|
||||
{
|
||||
TestServer server = TestServer.Create(app => app.UseFileServer());
|
||||
HttpResponseMessage original = await server.CreateClient().GetAsync("http://localhost/SubFolder/Ranges.txt");
|
||||
|
||||
var req = new HttpRequestMessage(HttpMethod.Head, "http://localhost/SubFolder/Ranges.txt");
|
||||
req.Headers.Add("If-Range", original.Headers.ETag.ToString());
|
||||
req.Headers.Add("Range", "bytes=0-10");
|
||||
HttpResponseMessage resp = await server.CreateClient().SendAsync(req);
|
||||
|
||||
Assert.Equal(HttpStatusCode.OK, resp.StatusCode);
|
||||
Assert.Equal(original.Headers.ETag, resp.Headers.ETag);
|
||||
Assert.Null(resp.Content.Headers.ContentRange);
|
||||
Assert.Equal(62, resp.Content.Headers.ContentLength);
|
||||
Assert.Equal(string.Empty, await resp.Content.ReadAsStringAsync());
|
||||
}
|
||||
|
||||
// 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.
|
||||
[Fact]
|
||||
public async Task IfRangeWithCurrentDateShouldServePartialContent()
|
||||
{
|
||||
TestServer server = TestServer.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-Range", original.Content.Headers.LastModified.Value.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());
|
||||
}
|
||||
|
||||
// 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
|
||||
[Fact]
|
||||
public async Task HEADIfRangeWithCurrentDateShouldReturn200Ok()
|
||||
{
|
||||
TestServer server = TestServer.Create(app => app.UseFileServer());
|
||||
HttpResponseMessage original = await server.CreateClient().GetAsync("http://localhost/SubFolder/Ranges.txt");
|
||||
|
||||
var req = new HttpRequestMessage(HttpMethod.Head, "http://localhost/SubFolder/Ranges.txt");
|
||||
req.Headers.Add("If-Range", original.Content.Headers.LastModified.Value.ToString("r"));
|
||||
req.Headers.Add("Range", "bytes=0-10");
|
||||
HttpResponseMessage resp = await server.CreateClient().SendAsync(req);
|
||||
|
||||
Assert.Equal(HttpStatusCode.OK, resp.StatusCode);
|
||||
Assert.Equal(original.Content.Headers.LastModified, resp.Content.Headers.LastModified);
|
||||
Assert.Null(resp.Content.Headers.ContentRange);
|
||||
Assert.Equal(62, resp.Content.Headers.ContentLength);
|
||||
Assert.Equal(string.Empty, await resp.Content.ReadAsStringAsync());
|
||||
}
|
||||
|
||||
// 14.27 If-Range
|
||||
// If the entity tag does not match, then the server SHOULD return the entire entity using a 200 (OK) response.
|
||||
[Fact]
|
||||
public async Task IfRangeWithOldEtagShouldServeFullContent()
|
||||
{
|
||||
TestServer server = TestServer.Create(app => app.UseFileServer());
|
||||
var req = new HttpRequestMessage(HttpMethod.Get, "http://localhost/SubFolder/Ranges.txt");
|
||||
req.Headers.Add("If-Range", "\"OldEtag\"");
|
||||
req.Headers.Add("Range", "bytes=0-10");
|
||||
HttpResponseMessage resp = await server.CreateClient().SendAsync(req);
|
||||
Assert.Equal(HttpStatusCode.OK, resp.StatusCode);
|
||||
Assert.Null(resp.Content.Headers.ContentRange);
|
||||
Assert.Equal(62, resp.Content.Headers.ContentLength);
|
||||
Assert.Equal("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", await resp.Content.ReadAsStringAsync());
|
||||
}
|
||||
|
||||
// 14.27 If-Range
|
||||
// If the entity tag does not match, then the server SHOULD return the entire entity using a 200 (OK) response.
|
||||
[Fact]
|
||||
public async Task HEADIfRangeWithOldEtagShouldServeFullContent()
|
||||
{
|
||||
TestServer server = TestServer.Create(app => app.UseFileServer());
|
||||
var req = new HttpRequestMessage(HttpMethod.Head, "http://localhost/SubFolder/Ranges.txt");
|
||||
req.Headers.Add("If-Range", "\"OldEtag\"");
|
||||
req.Headers.Add("Range", "bytes=0-10");
|
||||
HttpResponseMessage resp = await server.CreateClient().SendAsync(req);
|
||||
Assert.Equal(HttpStatusCode.OK, resp.StatusCode);
|
||||
Assert.Null(resp.Content.Headers.ContentRange);
|
||||
Assert.Equal(62, resp.Content.Headers.ContentLength);
|
||||
Assert.Equal(string.Empty, await resp.Content.ReadAsStringAsync());
|
||||
}
|
||||
|
||||
// 14.27 If-Range
|
||||
// If the entity tag/date does not match, then the server SHOULD return the entire entity using a 200 (OK) response.
|
||||
[Fact]
|
||||
public async Task IfRangeWithOldDateShouldServeFullContent()
|
||||
{
|
||||
TestServer server = TestServer.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-Range", original.Content.Headers.LastModified.Value.Subtract(TimeSpan.FromDays(1)).ToString("r"));
|
||||
req.Headers.Add("Range", "bytes=0-10");
|
||||
HttpResponseMessage resp = await server.CreateClient().SendAsync(req);
|
||||
Assert.Equal(HttpStatusCode.OK, resp.StatusCode);
|
||||
Assert.Null(resp.Content.Headers.ContentRange);
|
||||
Assert.Equal(62, resp.Content.Headers.ContentLength);
|
||||
Assert.Equal("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", await resp.Content.ReadAsStringAsync());
|
||||
}
|
||||
|
||||
// 14.27 If-Range
|
||||
// If the entity tag/date does not match, then the server SHOULD return the entire entity using a 200 (OK) response.
|
||||
[Fact]
|
||||
public async Task HEADIfRangeWithOldDateShouldServeFullContent()
|
||||
{
|
||||
TestServer server = TestServer.Create(app => app.UseFileServer());
|
||||
HttpResponseMessage original = await server.CreateClient().GetAsync("http://localhost/SubFolder/Ranges.txt");
|
||||
|
||||
var req = new HttpRequestMessage(HttpMethod.Head, "http://localhost/SubFolder/Ranges.txt");
|
||||
req.Headers.Add("If-Range", original.Content.Headers.LastModified.Value.Subtract(TimeSpan.FromDays(1)).ToString("r"));
|
||||
req.Headers.Add("Range", "bytes=0-10");
|
||||
HttpResponseMessage resp = await server.CreateClient().SendAsync(req);
|
||||
Assert.Equal(HttpStatusCode.OK, resp.StatusCode);
|
||||
Assert.Null(resp.Content.Headers.ContentRange);
|
||||
Assert.Equal(62, resp.Content.Headers.ContentLength);
|
||||
Assert.Equal(string.Empty, await resp.Content.ReadAsStringAsync());
|
||||
}
|
||||
|
||||
// 14.27 If-Range
|
||||
// The If-Range header SHOULD only be used together with a Range header, and MUST be ignored if the request
|
||||
// does not include a Range header, or if the server does not support the sub-range operation.
|
||||
[Fact]
|
||||
public async Task IfRangeWithoutRangeShouldServeFullContent()
|
||||
{
|
||||
TestServer server = TestServer.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-Range", original.Headers.ETag.ToString());
|
||||
HttpResponseMessage resp = await server.CreateClient().SendAsync(req);
|
||||
Assert.Equal(HttpStatusCode.OK, resp.StatusCode);
|
||||
Assert.Null(resp.Content.Headers.ContentRange);
|
||||
Assert.Equal(62, resp.Content.Headers.ContentLength);
|
||||
Assert.Equal("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", await resp.Content.ReadAsStringAsync());
|
||||
|
||||
req = new HttpRequestMessage(HttpMethod.Get, "http://localhost/SubFolder/Ranges.txt");
|
||||
req.Headers.Add("If-Range", original.Content.Headers.LastModified.Value.ToString("r"));
|
||||
resp = await server.CreateClient().SendAsync(req);
|
||||
Assert.Equal(HttpStatusCode.OK, resp.StatusCode);
|
||||
Assert.Null(resp.Content.Headers.ContentRange);
|
||||
Assert.Equal(62, resp.Content.Headers.ContentLength);
|
||||
Assert.Equal("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", await resp.Content.ReadAsStringAsync());
|
||||
}
|
||||
|
||||
// 14.27 If-Range
|
||||
// The If-Range header SHOULD only be used together with a Range header, and MUST be ignored if the request
|
||||
// does not include a Range header, or if the server does not support the sub-range operation.
|
||||
[Fact]
|
||||
public async Task HEADIfRangeWithoutRangeShouldServeFullContent()
|
||||
{
|
||||
TestServer server = TestServer.Create(app => app.UseFileServer());
|
||||
HttpResponseMessage original = await server.CreateClient().GetAsync("http://localhost/SubFolder/Ranges.txt");
|
||||
|
||||
var req = new HttpRequestMessage(HttpMethod.Head, "http://localhost/SubFolder/Ranges.txt");
|
||||
req.Headers.Add("If-Range", original.Headers.ETag.ToString());
|
||||
HttpResponseMessage resp = await server.CreateClient().SendAsync(req);
|
||||
Assert.Equal(HttpStatusCode.OK, resp.StatusCode);
|
||||
Assert.Null(resp.Content.Headers.ContentRange);
|
||||
Assert.Equal(62, resp.Content.Headers.ContentLength);
|
||||
Assert.Equal(string.Empty, await resp.Content.ReadAsStringAsync());
|
||||
|
||||
req = new HttpRequestMessage(HttpMethod.Head, "http://localhost/SubFolder/Ranges.txt");
|
||||
req.Headers.Add("If-Range", original.Content.Headers.LastModified.Value.ToString("r"));
|
||||
resp = await server.CreateClient().SendAsync(req);
|
||||
Assert.Equal(HttpStatusCode.OK, resp.StatusCode);
|
||||
Assert.Null(resp.Content.Headers.ContentRange);
|
||||
Assert.Equal(62, resp.Content.Headers.ContentLength);
|
||||
Assert.Equal(string.Empty, await resp.Content.ReadAsStringAsync());
|
||||
}
|
||||
|
||||
// 14.35 Range
|
||||
[Theory]
|
||||
[InlineData("0-0", "0-0", 1, "0")]
|
||||
[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
|
||||
[InlineData("-26", "36-61", 26, "ABCDEFGHIJKLMNOPQRSTUVWXYZ")] // Last 26
|
||||
[InlineData("0-", "0-61", 62, "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")]
|
||||
[InlineData("-1001", "0-61", 62, "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")]
|
||||
public async Task SingleValidRangeShouldServePartialContent(string range, string expectedRange, int length, string expectedData)
|
||||
{
|
||||
TestServer server = TestServer.Create(app => app.UseFileServer());
|
||||
var req = new HttpRequestMessage(HttpMethod.Get, "http://localhost/SubFolder/Ranges.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 + "/62", resp.Content.Headers.ContentRange.ToString());
|
||||
Assert.Equal(length, resp.Content.Headers.ContentLength);
|
||||
Assert.Equal(expectedData, await resp.Content.ReadAsStringAsync());
|
||||
}
|
||||
|
||||
// 14.35 Range
|
||||
// HEAD ignores range headers
|
||||
[Theory]
|
||||
[InlineData("10-35")]
|
||||
public async Task HEADSingleValidRangeShouldReturnOk(string range)
|
||||
{
|
||||
TestServer server = TestServer.Create(app => app.UseFileServer());
|
||||
var req = new HttpRequestMessage(HttpMethod.Head, "http://localhost/SubFolder/Ranges.txt");
|
||||
req.Headers.Add("Range", "bytes=" + range);
|
||||
HttpResponseMessage resp = await server.CreateClient().SendAsync(req);
|
||||
Assert.Equal(HttpStatusCode.OK, resp.StatusCode);
|
||||
Assert.Null(resp.Content.Headers.ContentRange);
|
||||
Assert.Equal(62, resp.Content.Headers.ContentLength);
|
||||
Assert.Equal(string.Empty, await resp.Content.ReadAsStringAsync());
|
||||
}
|
||||
|
||||
// 14.35 Range
|
||||
[Theory]
|
||||
[InlineData("100-")] // Out of range
|
||||
[InlineData("1000-1001")] // Out of range
|
||||
[InlineData("-0")] // Suffix range must be non-zero
|
||||
public async Task SingleNotSatisfiableRange(string range)
|
||||
{
|
||||
TestServer server = TestServer.Create(app => app.UseFileServer());
|
||||
var req = new HttpRequestMessage(HttpMethod.Get, "http://localhost/SubFolder/Ranges.txt");
|
||||
req.Headers.TryAddWithoutValidation("Range", "bytes=" + range);
|
||||
HttpResponseMessage resp = await server.CreateClient().SendAsync(req);
|
||||
Assert.Equal(HttpStatusCode.RequestedRangeNotSatisfiable, resp.StatusCode);
|
||||
Assert.Equal("bytes */62", resp.Content.Headers.ContentRange.ToString());
|
||||
}
|
||||
|
||||
// 14.35 Range
|
||||
// HEAD ignores range headers
|
||||
[Theory]
|
||||
[InlineData("1000-1001")] // Out of range
|
||||
public async Task HEADSingleNotSatisfiableRangeReturnsOk(string range)
|
||||
{
|
||||
TestServer server = TestServer.Create(app => app.UseFileServer());
|
||||
var req = new HttpRequestMessage(HttpMethod.Head, "http://localhost/SubFolder/Ranges.txt");
|
||||
req.Headers.TryAddWithoutValidation("Range", "bytes=" + range);
|
||||
HttpResponseMessage resp = await server.CreateClient().SendAsync(req);
|
||||
Assert.Equal(HttpStatusCode.OK, resp.StatusCode);
|
||||
Assert.Null(resp.Content.Headers.ContentRange);
|
||||
}
|
||||
|
||||
// 14.35 Range
|
||||
[Theory]
|
||||
[InlineData("")]
|
||||
[InlineData("0")]
|
||||
[InlineData("1-0")]
|
||||
[InlineData("-")]
|
||||
public async Task SingleInvalidRangeIgnored(string range)
|
||||
{
|
||||
TestServer server = TestServer.Create(app => app.UseFileServer());
|
||||
var req = new HttpRequestMessage(HttpMethod.Get, "http://localhost/SubFolder/Ranges.txt");
|
||||
req.Headers.TryAddWithoutValidation("Range", "bytes=" + range);
|
||||
HttpResponseMessage resp = await server.CreateClient().SendAsync(req);
|
||||
Assert.Equal(HttpStatusCode.OK, resp.StatusCode);
|
||||
Assert.Null(resp.Content.Headers.ContentRange);
|
||||
Assert.Equal(62, resp.Content.Headers.ContentLength);
|
||||
Assert.Equal("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", await resp.Content.ReadAsStringAsync());
|
||||
}
|
||||
|
||||
// 14.35 Range
|
||||
[Theory]
|
||||
[InlineData("")]
|
||||
[InlineData("0")]
|
||||
[InlineData("1-0")]
|
||||
[InlineData("-")]
|
||||
public async Task HEADSingleInvalidRangeIgnored(string range)
|
||||
{
|
||||
TestServer server = TestServer.Create(app => app.UseFileServer());
|
||||
var req = new HttpRequestMessage(HttpMethod.Head, "http://localhost/SubFolder/Ranges.txt");
|
||||
req.Headers.TryAddWithoutValidation("Range", "bytes=" + range);
|
||||
HttpResponseMessage resp = await server.CreateClient().SendAsync(req);
|
||||
Assert.Equal(HttpStatusCode.OK, resp.StatusCode);
|
||||
Assert.Null(resp.Content.Headers.ContentRange);
|
||||
Assert.Equal(62, resp.Content.Headers.ContentLength);
|
||||
Assert.Equal(string.Empty, await resp.Content.ReadAsStringAsync());
|
||||
}
|
||||
|
||||
// 14.35 Range
|
||||
[Theory]
|
||||
[InlineData("0-0,2-2")]
|
||||
[InlineData("0-0,60-")]
|
||||
[InlineData("0-0,-2")]
|
||||
[InlineData("2-2,0-0")]
|
||||
[InlineData("0-0,2-2,4-4,6-6,8-8")]
|
||||
[InlineData("0-0,6-6,8-8,2-2,4-4")]
|
||||
public async Task MultipleValidRangesShouldServeFullContent(string ranges)
|
||||
{
|
||||
TestServer server = TestServer.Create(app => app.UseFileServer());
|
||||
var req = new HttpRequestMessage(HttpMethod.Get, "http://localhost/SubFolder/Ranges.txt");
|
||||
req.Headers.Add("Range", "bytes=" + ranges);
|
||||
HttpResponseMessage resp = await server.CreateClient().SendAsync(req);
|
||||
Assert.Equal(HttpStatusCode.OK, resp.StatusCode);
|
||||
Assert.Equal("text/plain", resp.Content.Headers.ContentType.ToString());
|
||||
Assert.Null(resp.Content.Headers.ContentRange);
|
||||
Assert.Equal(62, resp.Content.Headers.ContentLength);
|
||||
Assert.Equal("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", await resp.Content.ReadAsStringAsync());
|
||||
}
|
||||
|
||||
// 14.35 Range
|
||||
[Theory]
|
||||
[InlineData("0-0,2-2")]
|
||||
[InlineData("0-0,60-")]
|
||||
[InlineData("0-0,-2")]
|
||||
[InlineData("2-2,0-0")] // SHOULD send in the requested order.
|
||||
public async Task HEADMultipleValidRangesShouldServeFullContent(string range)
|
||||
{
|
||||
TestServer server = TestServer.Create(app => app.UseFileServer());
|
||||
var req = new HttpRequestMessage(HttpMethod.Head, "http://localhost/SubFolder/Ranges.txt");
|
||||
req.Headers.Add("Range", "bytes=" + range);
|
||||
HttpResponseMessage resp = await server.CreateClient().SendAsync(req);
|
||||
Assert.Equal(HttpStatusCode.OK, resp.StatusCode);
|
||||
Assert.Equal("text/plain", resp.Content.Headers.ContentType.ToString());
|
||||
Assert.Equal(string.Empty, await resp.Content.ReadAsStringAsync());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
// 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.HttpFeature;
|
||||
using Microsoft.AspNet.PipelineCore;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.StaticFiles
|
||||
{
|
||||
public class SendFileResponseExtensionsTests
|
||||
{
|
||||
[Fact]
|
||||
public void SendFileSupport()
|
||||
{
|
||||
var context = new DefaultHttpContext();
|
||||
var response = context.Response;
|
||||
Assert.False(response.SupportsSendFile());
|
||||
context.SetFeature<IHttpSendFileFeature>(new FakeSendFileFeature());
|
||||
Assert.True(response.SupportsSendFile());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public Task SendFileWhenNotSupported()
|
||||
{
|
||||
var response = new DefaultHttpContext().Response;
|
||||
return Assert.ThrowsAsync<NotSupportedException>(() => response.SendFileAsync("foo"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SendFileWorks()
|
||||
{
|
||||
var context = new DefaultHttpContext();
|
||||
var response = context.Response;
|
||||
var fakeFeature = new FakeSendFileFeature();
|
||||
context.SetFeature<IHttpSendFileFeature>(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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,117 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Builder;
|
||||
using Microsoft.AspNet.FileSystems;
|
||||
using Microsoft.AspNet.Http;
|
||||
using Microsoft.AspNet.TestHost;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.StaticFiles
|
||||
{
|
||||
public class StaticFileMiddlewareTests
|
||||
{
|
||||
[Fact]
|
||||
public async Task NullArguments()
|
||||
{
|
||||
Assert.Throws<ArgumentNullException>(() => TestServer.Create(app => app.UseStaticFiles((StaticFileOptions)null)));
|
||||
Assert.Throws<ArgumentException>(() => TestServer.Create(app => app.UseStaticFiles(new StaticFileOptions() { ContentTypeProvider = null })));
|
||||
|
||||
// No exception, default provided
|
||||
TestServer.Create(app => app.UseStaticFiles(new StaticFileOptions() { FileSystem = null }));
|
||||
|
||||
// PathString(null) is OK.
|
||||
TestServer server = TestServer.Create(app => app.UseStaticFiles((string)null));
|
||||
var response = await server.CreateClient().GetAsync("/");
|
||||
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GivenDirDoesntExist_Throw()
|
||||
{
|
||||
Assert.Throws<DirectoryNotFoundException>(() => TestServer.Create(app => app.UseStaticFiles("/ThisDirDoesntExist")));
|
||||
}
|
||||
|
||||
[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)
|
||||
{
|
||||
TestServer server = TestServer.Create(app => app.UseStaticFiles(new StaticFileOptions()
|
||||
{
|
||||
RequestPath = new PathString(baseUrl),
|
||||
FileSystem = new PhysicalFileSystem(baseDir)
|
||||
}));
|
||||
HttpResponseMessage response = await server.CreateRequest(requestUrl).GetAsync();
|
||||
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("", @".", "/TestDocument.txt")]
|
||||
[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 FoundFile_Served(string baseUrl, string baseDir, string requestUrl)
|
||||
{
|
||||
TestServer server = TestServer.Create(app => app.UseStaticFiles(new StaticFileOptions()
|
||||
{
|
||||
RequestPath = new PathString(baseUrl),
|
||||
FileSystem = new PhysicalFileSystem(baseDir)
|
||||
}));
|
||||
HttpResponseMessage response = await server.CreateRequest(requestUrl).GetAsync();
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("", @".", "/TestDocument.txt")]
|
||||
[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)
|
||||
{
|
||||
TestServer server = TestServer.Create(app => app.UseStaticFiles(new StaticFileOptions()
|
||||
{
|
||||
RequestPath = new PathString(baseUrl),
|
||||
FileSystem = new PhysicalFileSystem(baseDir)
|
||||
}));
|
||||
HttpResponseMessage response = await server.CreateRequest(requestUrl).PostAsync();
|
||||
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("", @".", "/TestDocument.txt")]
|
||||
[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 HeadFile_HeadersButNotBodyServed(string baseUrl, string baseDir, string requestUrl)
|
||||
{
|
||||
TestServer server = TestServer.Create(app => app.UseStaticFiles(new StaticFileOptions()
|
||||
{
|
||||
RequestPath = new PathString(baseUrl),
|
||||
FileSystem = new PhysicalFileSystem(baseDir)
|
||||
}));
|
||||
HttpResponseMessage 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.Equal(0, (await response.Content.ReadAsByteArrayAsync()).Length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
<!DOCTYPE html>
|
||||
|
||||
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title></title>
|
||||
</head>
|
||||
<body>
|
||||
Hello World
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1 @@
|
|||
<xml/>
|
||||
|
|
@ -0,0 +1 @@
|
|||
0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
|
||||
|
|
@ -0,0 +1 @@
|
|||
0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
|
||||
Loading…
Reference in New Issue