diff --git a/src/Middleware/StaticFiles/src/DefaultFilesMiddleware.cs b/src/Middleware/StaticFiles/src/DefaultFilesMiddleware.cs
index 1f020dbe1c..627c4b2b5f 100644
--- a/src/Middleware/StaticFiles/src/DefaultFilesMiddleware.cs
+++ b/src/Middleware/StaticFiles/src/DefaultFilesMiddleware.cs
@@ -6,6 +6,7 @@ using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Http.Endpoints;
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Options;
using Microsoft.Net.Http.Headers;
@@ -62,7 +63,8 @@ namespace Microsoft.AspNetCore.StaticFiles
///
public Task Invoke(HttpContext context)
{
- if (Helpers.IsGetOrHeadMethod(context.Request.Method)
+ if (context.GetEndpoint() == null &&
+ Helpers.IsGetOrHeadMethod(context.Request.Method)
&& Helpers.TryMatchPath(context, _matchUrl, forDirectory: true, subpath: out var subpath))
{
var dirContents = _fileProvider.GetDirectoryContents(subpath.Value);
diff --git a/src/Middleware/StaticFiles/src/DirectoryBrowserMiddleware.cs b/src/Middleware/StaticFiles/src/DirectoryBrowserMiddleware.cs
index 1ac950ebe9..cc9c9118a6 100644
--- a/src/Middleware/StaticFiles/src/DirectoryBrowserMiddleware.cs
+++ b/src/Middleware/StaticFiles/src/DirectoryBrowserMiddleware.cs
@@ -7,6 +7,7 @@ using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Http.Endpoints;
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Options;
using Microsoft.Net.Http.Headers;
@@ -78,8 +79,9 @@ namespace Microsoft.AspNetCore.StaticFiles
///
public Task Invoke(HttpContext context)
{
- // Check if the URL matches any expected paths
- if (Helpers.IsGetOrHeadMethod(context.Request.Method)
+ // Check if the URL matches any expected paths, skip if an endpoint was selected
+ if (context.GetEndpoint() == null &&
+ Helpers.IsGetOrHeadMethod(context.Request.Method)
&& Helpers.TryMatchPath(context, _matchUrl, forDirectory: true, subpath: out var subpath)
&& TryGetDirectoryInfo(subpath, out var contents))
{
diff --git a/src/Middleware/StaticFiles/src/LoggerExtensions.cs b/src/Middleware/StaticFiles/src/LoggerExtensions.cs
index 56afbeb5eb..8630cf8fa0 100644
--- a/src/Middleware/StaticFiles/src/LoggerExtensions.cs
+++ b/src/Middleware/StaticFiles/src/LoggerExtensions.cs
@@ -24,6 +24,7 @@ namespace Microsoft.AspNetCore.StaticFiles
private static Action _sendingFileRange;
private static Action _copyingFileRange;
private static Action _writeCancelled;
+ private static Action _endpointMatched;
static LoggerExtensions()
{
@@ -75,6 +76,10 @@ namespace Microsoft.AspNetCore.StaticFiles
logLevel: LogLevel.Debug,
eventId: new EventId(14, "WriteCancelled"),
formatString: "The file transmission was cancelled");
+ _endpointMatched = LoggerMessage.Define(
+ logLevel: LogLevel.Debug,
+ eventId: new EventId(15, "EndpointMatched"),
+ formatString: "Static files was skipped as the request already matched an endpoint.");
}
public static void RequestMethodNotSupported(this ILogger logger, string method)
@@ -91,6 +96,11 @@ namespace Microsoft.AspNetCore.StaticFiles
_fileServed(logger, virtualPath, physicalPath, null);
}
+ public static void EndpointMatched(this ILogger logger)
+ {
+ _endpointMatched(logger, null);
+ }
+
public static void PathMismatch(this ILogger logger, string path)
{
_pathMismatch(logger, path, null);
diff --git a/src/Middleware/StaticFiles/src/StaticFileContext.cs b/src/Middleware/StaticFiles/src/StaticFileContext.cs
index 7473db4f36..e38b600f7b 100644
--- a/src/Middleware/StaticFiles/src/StaticFileContext.cs
+++ b/src/Middleware/StaticFiles/src/StaticFileContext.cs
@@ -8,6 +8,7 @@ using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Http.Endpoints;
using Microsoft.AspNetCore.Http.Extensions;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Http.Headers;
@@ -108,6 +109,12 @@ namespace Microsoft.AspNetCore.StaticFiles
get { return _fileInfo?.PhysicalPath; }
}
+ public bool ValidateNoEndpoint()
+ {
+ // Return true because we only want to run if there is no endpoint.
+ return _context.GetEndpoint() == null;
+ }
+
public bool ValidateMethod()
{
_method = _request.Method;
diff --git a/src/Middleware/StaticFiles/src/StaticFileMiddleware.cs b/src/Middleware/StaticFiles/src/StaticFileMiddleware.cs
index 1a97a5e90a..fe9dcd0119 100644
--- a/src/Middleware/StaticFiles/src/StaticFileMiddleware.cs
+++ b/src/Middleware/StaticFiles/src/StaticFileMiddleware.cs
@@ -72,7 +72,11 @@ namespace Microsoft.AspNetCore.StaticFiles
{
var fileContext = new StaticFileContext(context, _options, _matchUrl, _logger, _fileProvider, _contentTypeProvider);
- if (!fileContext.ValidateMethod())
+ if (!fileContext.ValidateNoEndpoint())
+ {
+ _logger.EndpointMatched();
+ }
+ else if (!fileContext.ValidateMethod())
{
_logger.RequestMethodNotSupported(context.Request.Method);
}
diff --git a/src/Middleware/StaticFiles/test/FunctionalTests/StaticFileMiddlewareTests.cs b/src/Middleware/StaticFiles/test/FunctionalTests/StaticFileMiddlewareTests.cs
index 7e55b79b78..7413eaf89d 100644
--- a/src/Middleware/StaticFiles/test/FunctionalTests/StaticFileMiddlewareTests.cs
+++ b/src/Middleware/StaticFiles/test/FunctionalTests/StaticFileMiddlewareTests.cs
@@ -14,6 +14,7 @@ using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Http.Endpoints;
using Microsoft.AspNetCore.Server.IntegrationTesting;
using Microsoft.AspNetCore.Server.IntegrationTesting.Common;
using Microsoft.AspNetCore.Testing;
@@ -45,6 +46,44 @@ namespace Microsoft.AspNetCore.StaticFiles
}
}
+ [Fact]
+ public async Task Endpoint_PassesThrough()
+ {
+ var builder = new WebHostBuilder()
+ .ConfigureServices(services => services.AddSingleton(LoggerFactory))
+ .UseKestrel()
+ .UseWebRoot(AppContext.BaseDirectory)
+ .Configure(app =>
+ {
+ // Routing first => static files noops
+ app.Use(next => context =>
+ {
+ // Assign an endpoint, this will make the default files noop.
+ context.SetEndpoint(new Endpoint((c) =>
+ {
+ return context.Response.WriteAsync("Hi from endpoint.");
+ },
+ new EndpointMetadataCollection(),
+ "test"));
+
+ return next(context);
+ });
+
+ app.UseStaticFiles();
+ });
+
+ using (var server = builder.Start(TestUrlHelper.GetTestUrl(ServerType.Kestrel)))
+ {
+ using (var client = new HttpClient { BaseAddress = new Uri(server.GetAddress()) })
+ {
+ var response = await client.GetAsync("TestDocument.txt");
+
+ Assert.Equal(HttpStatusCode.OK, response.StatusCode);
+ Assert.Equal("Hi from endpoint.", await response.Content.ReadAsStringAsync());
+ }
+ }
+ }
+
[Fact]
public async Task FoundFile_LastModifiedTrimsSeconds()
{
diff --git a/src/Middleware/StaticFiles/test/UnitTests/DefaultFilesMiddlewareTests.cs b/src/Middleware/StaticFiles/test/UnitTests/DefaultFilesMiddlewareTests.cs
index 7df375d2d4..aff8e01a9c 100644
--- a/src/Middleware/StaticFiles/test/UnitTests/DefaultFilesMiddlewareTests.cs
+++ b/src/Middleware/StaticFiles/test/UnitTests/DefaultFilesMiddlewareTests.cs
@@ -1,4 +1,4 @@
-// Copyright (c) .NET Foundation. All rights reserved.
+// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
@@ -9,9 +9,11 @@ using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Http.Endpoints;
using Microsoft.AspNetCore.Http.Extensions;
using Microsoft.AspNetCore.TestHost;
using Microsoft.AspNetCore.Testing.xunit;
+using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.FileProviders;
using Xunit;
@@ -72,6 +74,41 @@ namespace Microsoft.AspNetCore.StaticFiles
}
}
+ [Fact]
+ public async Task Endpoint_PassesThrough()
+ {
+ using (var fileProvider = new PhysicalFileProvider(Path.Combine(AppContext.BaseDirectory, ".")))
+ {
+ var server = StaticFilesTestServer.Create(
+ app =>
+ {
+ app.Use(next => context =>
+ {
+ // Assign an endpoint, this will make the default files noop.
+ context.SetEndpoint(new Endpoint((c) =>
+ {
+ return context.Response.WriteAsync(context.Request.Path.Value);
+ },
+ new EndpointMetadataCollection(),
+ "test"));
+
+ return next(context);
+ });
+
+ app.UseDefaultFiles(new DefaultFilesOptions
+ {
+ RequestPath = new PathString(""),
+ FileProvider = fileProvider
+ });
+ },
+ services => services.AddDirectoryBrowser());
+
+ var response = await server.CreateRequest("/SubFolder/").GetAsync();
+ Assert.Equal(HttpStatusCode.OK, response.StatusCode);
+ Assert.Equal("/SubFolder/", await response.Content.ReadAsStringAsync()); // Should not be modified
+ }
+ }
+
[Theory]
[InlineData("", @".", "/SubFolder/")]
[InlineData("", @"./", "/SubFolder/")]
diff --git a/src/Middleware/StaticFiles/test/UnitTests/DirectoryBrowserMiddlewareTests.cs b/src/Middleware/StaticFiles/test/UnitTests/DirectoryBrowserMiddlewareTests.cs
index 2a12c85486..8710f46c28 100644
--- a/src/Middleware/StaticFiles/test/UnitTests/DirectoryBrowserMiddlewareTests.cs
+++ b/src/Middleware/StaticFiles/test/UnitTests/DirectoryBrowserMiddlewareTests.cs
@@ -9,6 +9,8 @@ using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Http.Endpoints;
+using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.TestHost;
using Microsoft.AspNetCore.Testing.xunit;
using Microsoft.Extensions.DependencyInjection;
@@ -86,6 +88,42 @@ namespace Microsoft.AspNetCore.StaticFiles
}
}
+ [Fact]
+ public async Task Endpoint_PassesThrough()
+ {
+ using (var fileProvider = new PhysicalFileProvider(Path.Combine(AppContext.BaseDirectory, ".")))
+ {
+ var server = StaticFilesTestServer.Create(
+ app =>
+ {
+ app.Use(next => context =>
+ {
+ // Assign an endpoint, this will make the directory browser noop
+ context.SetEndpoint(new Endpoint((c) =>
+ {
+ c.Response.StatusCode = (int)HttpStatusCode.NotAcceptable;
+ return c.Response.WriteAsync("Hi from endpoint.");
+ },
+ new EndpointMetadataCollection(),
+ "test"));
+
+ return next(context);
+ });
+
+ app.UseDirectoryBrowser(new DirectoryBrowserOptions
+ {
+ RequestPath = new PathString(""),
+ FileProvider = fileProvider
+ });
+ },
+ services => services.AddDirectoryBrowser());
+
+ var response = await server.CreateRequest("/").GetAsync();
+ Assert.Equal(HttpStatusCode.NotAcceptable, response.StatusCode);
+ Assert.Equal("Hi from endpoint.", await response.Content.ReadAsStringAsync());
+ }
+ }
+
[Theory]
[InlineData("", @".", "/")]
[InlineData("", @".", "/SubFolder/")]