From 167529cdf6addc3e10a6f8cc457040a1d0a89d74 Mon Sep 17 00:00:00 2001 From: Taylor Southwick Date: Mon, 17 Apr 2023 13:49:40 -0700 Subject: [PATCH] Add overloads of HttpContext.RewritePath We added HttpContext.RewritePath with a single path parameter. This adds the rest of the overloads to support optionally setting the FilePath/PathInfo, support for which was added a while back. Fixes #315 --- .../HttpRequestInputStreamFeature.cs | 44 +++++- .../RegisterAdapterFeaturesMiddleware.cs | 2 + .../Adapters/IHttpRequestPathFeature.cs | 19 +++ .../Adapters/IPathInfoFeature.cs | 13 -- .../Generated/Ref.Standard.cs | 3 + .../HttpContext.cs | 13 +- .../HttpRequest.cs | 12 +- .../HttpRequestBase.cs | 4 +- .../HttpRequestWrapper.cs | 4 +- .../HttpContextIntegrationTests.cs | 133 ++++++++++++++++++ .../HttpContextTests.cs | 83 ++++++++--- .../HttpRequestTests.cs | 68 +++------ 12 files changed, 301 insertions(+), 97 deletions(-) create mode 100644 src/Microsoft.AspNetCore.SystemWebAdapters/Adapters/IHttpRequestPathFeature.cs delete mode 100644 src/Microsoft.AspNetCore.SystemWebAdapters/Adapters/IPathInfoFeature.cs create mode 100644 test/Microsoft.AspNetCore.SystemWebAdapters.CoreServices.Tests/HttpContextIntegrationTests.cs diff --git a/src/Microsoft.AspNetCore.SystemWebAdapters.CoreServices/HttpRequestInputStreamFeature.cs b/src/Microsoft.AspNetCore.SystemWebAdapters.CoreServices/HttpRequestInputStreamFeature.cs index 6bd05f70a4..c343be74ea 100644 --- a/src/Microsoft.AspNetCore.SystemWebAdapters.CoreServices/HttpRequestInputStreamFeature.cs +++ b/src/Microsoft.AspNetCore.SystemWebAdapters.CoreServices/HttpRequestInputStreamFeature.cs @@ -14,13 +14,16 @@ namespace Microsoft.AspNetCore.SystemWebAdapters; -internal class HttpRequestInputStreamFeature : IHttpRequestInputStreamFeature, IHttpRequestFeature, IRequestBodyPipeFeature, IDisposable +internal class HttpRequestInputStreamFeature : IHttpRequestInputStreamFeature, IHttpRequestPathFeature, IHttpRequestFeature, IRequestBodyPipeFeature, IDisposable { private readonly IHttpRequestFeature _other; private PipeReader? _pipeReader; private Stream? _bufferedStream; + private string? _pathInfo; + private string? _filePath; + public HttpRequestInputStreamFeature(IHttpRequestFeature other) { BufferThreshold = PreBufferRequestStreamAttribute.DefaultBufferThreshold; @@ -120,10 +123,15 @@ string IHttpRequestFeature.PathBase set => _other.PathBase = value; } - string IHttpRequestFeature.Path + public string Path { get => _other.Path; - set => _other.Path = value; + set + { + _filePath = null; + _pathInfo = null; + _other.Path = value; + } } string IHttpRequestFeature.QueryString @@ -179,6 +187,34 @@ private void Reset() private Stream GetBody() => _bufferedStream ?? _other.Body; + void IHttpRequestPathFeature.Rewrite(string filePath, string pathInfo, string? queryString, bool setClientFilePath) + { + _other.QueryString = queryString ?? string.Empty; + + if (string.IsNullOrEmpty(pathInfo)) + { + Path = filePath; + } + else if (pathInfo.StartsWith('/')) + { + Path = $"{filePath}{pathInfo}"; + } + else + { + Path = $"{filePath}/{pathInfo}"; + } + + // This must be set after setting Path as it will reset the PathInfo and FilePath instances + _pathInfo = pathInfo; + _filePath = filePath; + } + + string IHttpRequestPathFeature.PathInfo => _pathInfo ?? string.Empty; + + string IHttpRequestPathFeature.FilePath => _filePath ?? Path; + + string IHttpRequestPathFeature.RawUrl => _other.RawTarget; + internal static class AspNetCoreTempDirectory { private static string? _tempDirectory; @@ -191,7 +227,7 @@ public static string TempDirectory { // Look for folders in the following order. var temp = Environment.GetEnvironmentVariable("ASPNETCORE_TEMP") ?? // ASPNETCORE_TEMP - User set temporary location. - Path.GetTempPath(); // Fall back. + System.IO.Path.GetTempPath(); // Fall back. if (!Directory.Exists(temp)) { diff --git a/src/Microsoft.AspNetCore.SystemWebAdapters.CoreServices/RegisterAdapterFeaturesMiddleware.cs b/src/Microsoft.AspNetCore.SystemWebAdapters.CoreServices/RegisterAdapterFeaturesMiddleware.cs index c9d567f2ed..112b24ae1e 100644 --- a/src/Microsoft.AspNetCore.SystemWebAdapters.CoreServices/RegisterAdapterFeaturesMiddleware.cs +++ b/src/Microsoft.AspNetCore.SystemWebAdapters.CoreServices/RegisterAdapterFeaturesMiddleware.cs @@ -45,12 +45,14 @@ private static DelegateDisposable RegisterRequestFeatures(HttpContextCore contex context.Features.Set(inputStreamFeature); context.Features.Set(inputStreamFeature); context.Features.Set(inputStreamFeature); + context.Features.Set(inputStreamFeature); return new DelegateDisposable(() => { context.Features.Set(existing); context.Features.Set(existingPipe); context.Features.Set(null); + context.Features.Set(null); }); } diff --git a/src/Microsoft.AspNetCore.SystemWebAdapters/Adapters/IHttpRequestPathFeature.cs b/src/Microsoft.AspNetCore.SystemWebAdapters/Adapters/IHttpRequestPathFeature.cs new file mode 100644 index 0000000000..ec66030b33 --- /dev/null +++ b/src/Microsoft.AspNetCore.SystemWebAdapters/Adapters/IHttpRequestPathFeature.cs @@ -0,0 +1,19 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#if NETCOREAPP + +internal interface IHttpRequestPathFeature +{ + string Path { get; } + + string PathInfo { get; } + + string FilePath { get; } + + string RawUrl { get; } + + void Rewrite(string filePath, string pathInfo, string? queryString, bool setClientFilePath); +} + +#endif diff --git a/src/Microsoft.AspNetCore.SystemWebAdapters/Adapters/IPathInfoFeature.cs b/src/Microsoft.AspNetCore.SystemWebAdapters/Adapters/IPathInfoFeature.cs deleted file mode 100644 index 5fa7e4619a..0000000000 --- a/src/Microsoft.AspNetCore.SystemWebAdapters/Adapters/IPathInfoFeature.cs +++ /dev/null @@ -1,13 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -#if NET6_0_OR_GREATER -namespace Microsoft.AspNetCore.SystemWebAdapters; - -internal interface IPathInfoFeature -{ - string PathInfo { get; } - - string FileInfo { get; } -} -#endif diff --git a/src/Microsoft.AspNetCore.SystemWebAdapters/Generated/Ref.Standard.cs b/src/Microsoft.AspNetCore.SystemWebAdapters/Generated/Ref.Standard.cs index dc7e28ff81..424975e48a 100644 --- a/src/Microsoft.AspNetCore.SystemWebAdapters/Generated/Ref.Standard.cs +++ b/src/Microsoft.AspNetCore.SystemWebAdapters/Generated/Ref.Standard.cs @@ -125,6 +125,9 @@ internal HttpContext() { } public void ClearError() { throw new System.PlatformNotSupportedException("Only supported when running on ASP.NET Core or System.Web");} public System.Web.ISubscriptionToken DisposeOnPipelineCompleted(System.IDisposable target) { throw new System.PlatformNotSupportedException("Only supported when running on ASP.NET Core or System.Web");} public void RewritePath(string path) { throw new System.PlatformNotSupportedException("Only supported when running on ASP.NET Core or System.Web");} + public void RewritePath(string path, bool rebaseClientPath) { throw new System.PlatformNotSupportedException("Only supported when running on ASP.NET Core or System.Web");} + public void RewritePath(string filePath, string pathInfo, string queryString) { throw new System.PlatformNotSupportedException("Only supported when running on ASP.NET Core or System.Web");} + public void RewritePath(string filePath, string pathInfo, string queryString, bool setClientFilePath) { throw new System.PlatformNotSupportedException("Only supported when running on ASP.NET Core or System.Web");} object System.IServiceProvider.GetService(System.Type service) { throw new System.PlatformNotSupportedException("Only supported when running on ASP.NET Core or System.Web");} } public partial class HttpContextBase : System.IServiceProvider diff --git a/src/Microsoft.AspNetCore.SystemWebAdapters/HttpContext.cs b/src/Microsoft.AspNetCore.SystemWebAdapters/HttpContext.cs index 9441d25d93..fac7b49b95 100644 --- a/src/Microsoft.AspNetCore.SystemWebAdapters/HttpContext.cs +++ b/src/Microsoft.AspNetCore.SystemWebAdapters/HttpContext.cs @@ -76,7 +76,9 @@ public IPrincipal User public DateTime Timestamp { get; } = DateTime.UtcNow.ToLocalTime(); - public void RewritePath(string path) + public void RewritePath(string path) => RewritePath(path, true); + + public void RewritePath(string path, bool rebaseClientPath) { ArgumentNullException.ThrowIfNull(path); @@ -95,10 +97,15 @@ public void RewritePath(string path) path = "/" + path; } - _context.Request.QueryString = new QueryString(qs); - _context.Request.Path = new PathString(path.Trim()); + RewritePath(path.Trim(), string.Empty, qs, rebaseClientPath); } + public void RewritePath(string filePath, string pathInfo, string? queryString) + => RewritePath(filePath, pathInfo, queryString, false); + + public void RewritePath(string filePath, string pathInfo, string? queryString, bool setClientFilePath) + => _context.Features.GetRequired().Rewrite(filePath, pathInfo, queryString, setClientFilePath); + [SuppressMessage("Design", "CA1033:Interface methods should be callable by child types", Justification = Constants.ApiFromAspNet)] object? IServiceProvider.GetService(Type service) { diff --git a/src/Microsoft.AspNetCore.SystemWebAdapters/HttpRequest.cs b/src/Microsoft.AspNetCore.SystemWebAdapters/HttpRequest.cs index 0b742d124a..31f74756cb 100644 --- a/src/Microsoft.AspNetCore.SystemWebAdapters/HttpRequest.cs +++ b/src/Microsoft.AspNetCore.SystemWebAdapters/HttpRequest.cs @@ -42,11 +42,14 @@ internal HttpRequest(HttpRequestCore request) internal RequestHeaders TypedHeaders => _typedHeaders ??= new(_request.Headers); - public string? Path => _request.Path.Value; + public string Path => _request.HttpContext.Features.GetRequired().Path; - public string? PathInfo => _request.HttpContext.Features.Get()?.PathInfo ?? string.Empty; + public string PathInfo => _request.HttpContext.Features.GetRequired().PathInfo; - public string? FilePath => _request.HttpContext.Features.Get()?.FileInfo ?? Path; + public string FilePath => _request.HttpContext.Features.GetRequired().FilePath; + + [SuppressMessage("Design", "CA1056:URI-like properties should not be strings", Justification = Constants.ApiFromAspNet)] + public string RawUrl => _request.HttpContext.Features.GetRequired().RawUrl; public NameValueCollection Headers => _headers ??= _request.Headers.ToNameValueCollection(); @@ -58,9 +61,6 @@ internal HttpRequest(HttpRequestCore request) public Stream GetBufferedInputStream() => _request.HttpContext.Features.GetRequired().GetBufferedInputStream(); - [SuppressMessage("Design", "CA1056:URI-like properties should not be strings", Justification = Constants.ApiFromAspNet)] - public string? RawUrl => _request.HttpContext.Features.Get()?.RawTarget; - public string HttpMethod => _request.Method; public string? UserHostAddress => _request.HttpContext.Connection.RemoteIpAddress?.ToString(); diff --git a/src/Microsoft.AspNetCore.SystemWebAdapters/HttpRequestBase.cs b/src/Microsoft.AspNetCore.SystemWebAdapters/HttpRequestBase.cs index 81a730a555..e8f031fe07 100644 --- a/src/Microsoft.AspNetCore.SystemWebAdapters/HttpRequestBase.cs +++ b/src/Microsoft.AspNetCore.SystemWebAdapters/HttpRequestBase.cs @@ -16,14 +16,14 @@ public abstract class HttpRequestBase [Diagnostics.CodeAnalysis.SuppressMessage("Performance", "CA1819:Properties should not return arrays", Justification = Constants.ApiFromAspNet)] public virtual string[] AcceptTypes => throw new NotImplementedException(); - public virtual string? Path => throw new NotImplementedException(); + public virtual string Path => throw new NotImplementedException(); public virtual NameValueCollection Headers => throw new NotImplementedException(); public virtual Uri Url => throw new NotImplementedException(); [Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1056:URI-like properties should not be strings", Justification = Constants.ApiFromAspNet)] - public virtual string? RawUrl => throw new NotImplementedException(); + public virtual string RawUrl => throw new NotImplementedException(); public virtual string HttpMethod => throw new NotImplementedException(); diff --git a/src/Microsoft.AspNetCore.SystemWebAdapters/HttpRequestWrapper.cs b/src/Microsoft.AspNetCore.SystemWebAdapters/HttpRequestWrapper.cs index 7c1d71f7d7..d0c1b99933 100644 --- a/src/Microsoft.AspNetCore.SystemWebAdapters/HttpRequestWrapper.cs +++ b/src/Microsoft.AspNetCore.SystemWebAdapters/HttpRequestWrapper.cs @@ -57,13 +57,13 @@ public override string? ContentType public override IIdentity? LogonUserIdentity => _request.LogonUserIdentity; - public override string? Path => _request.Path; + public override string Path => _request.Path; public override NameValueCollection QueryString => _request.QueryString; public override HttpBrowserCapabilitiesBase Browser => new HttpBrowserCapabilitiesWrapper(_request.Browser); - public override string? RawUrl => _request.RawUrl; + public override string RawUrl => _request.RawUrl; public override string RequestType => _request.RequestType; diff --git a/test/Microsoft.AspNetCore.SystemWebAdapters.CoreServices.Tests/HttpContextIntegrationTests.cs b/test/Microsoft.AspNetCore.SystemWebAdapters.CoreServices.Tests/HttpContextIntegrationTests.cs new file mode 100644 index 0000000000..f9659264dc --- /dev/null +++ b/test/Microsoft.AspNetCore.SystemWebAdapters.CoreServices.Tests/HttpContextIntegrationTests.cs @@ -0,0 +1,133 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.TestHost; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Xunit; + +namespace Microsoft.AspNetCore.SystemWebAdapters; + +public class HttpContextIntegrationTests +{ + [Fact] + public Task RequestInfo() + => RunTest("/", context => + { + Assert.Equal("/", context.Request.Path); + Assert.Empty(context.Request.Query); + + var adapter = (System.Web.HttpRequest)context.Request; + + Assert.Equal("", adapter.PathInfo); + Assert.Equal("/", adapter.FilePath); + Assert.Equal("/", adapter.Path); + Assert.Empty(adapter.QueryString); + }); + + [Fact] + public Task RewriteRequestPath() + => RunTest("/", context => + { + var adapter = (System.Web.HttpContext)context; + + adapter.RewritePath("/some/path?q=1"); + + Assert.Equal("/some/path", context.Request.Path); + Assert.Collection(context.Request.Query, + q => + { + Assert.Equal("q", q.Key); + Assert.Equal("1", q.Value); + }); + + Assert.Equal("", adapter.Request.PathInfo); + Assert.Equal("/some/path", adapter.Request.FilePath); + Assert.Equal("/some/path", adapter.Request.Path); + Assert.Single(adapter.Request.QueryString); + Assert.Equal("1", adapter.Request.QueryString["q"]); + }); + + [Fact] + public Task RewriteRequestPathInfo() + => RunTest("/", context => + { + var adapter = (System.Web.HttpContext)context; + + adapter.RewritePath("/some/path", "/pathInfo", "q=1"); + + Assert.Equal("/some/path/pathInfo", context.Request.Path); + Assert.Collection(context.Request.Query, + q => + { + Assert.Equal("q", q.Key); + Assert.Equal("1", q.Value); + }); + + Assert.Equal("/pathInfo", adapter.Request.PathInfo); + Assert.Equal("/some/path", adapter.Request.FilePath); + Assert.Equal("/some/path/pathInfo", adapter.Request.Path); + Assert.Single(adapter.Request.QueryString); + Assert.Equal("1", adapter.Request.QueryString["q"]); + }); + + [Fact] + public Task RewritePathViaCoreApis() + => RunTest("/", context => + { + var adapter = (System.Web.HttpContext)context; + + // This is the same as RewriteRequestPathInfo as above to get a custom PathInfo + adapter.RewritePath("/some/path", "/pathInfo", "q=1"); + context.Request.Path = "/other"; + + Assert.Equal("/other", context.Request.Path); + Assert.Collection(context.Request.Query, + q => + { + Assert.Equal("q", q.Key); + Assert.Equal("1", q.Value); + }); + + Assert.Equal(string.Empty, adapter.Request.PathInfo); + Assert.Equal("/other", adapter.Request.FilePath); + Assert.Equal("/other", adapter.Request.Path); + Assert.Single(adapter.Request.QueryString); + Assert.Equal("1", adapter.Request.QueryString["q"]); + }); + + private static async Task RunTest(string path, Action run) + { + // Arrange + using var host = await new HostBuilder() + .ConfigureWebHost(webBuilder => + { + webBuilder + .UseTestServer() + .ConfigureServices(services => + { + services.AddRouting(); + services.AddSystemWebAdapters(); + }) + .Configure(app => + { + app.UseRouting(); + app.UseSystemWebAdapters(); + + app.Run(ctx => + { + run(ctx); + return Task.CompletedTask; + }); + + }); + }) + .StartAsync(); + + _ = await host.GetTestClient().GetAsync(new Uri(path, UriKind.Relative)); + } +} diff --git a/test/Microsoft.AspNetCore.SystemWebAdapters.Tests/HttpContextTests.cs b/test/Microsoft.AspNetCore.SystemWebAdapters.Tests/HttpContextTests.cs index 68c17e6d73..c346d712fb 100644 --- a/test/Microsoft.AspNetCore.SystemWebAdapters.Tests/HttpContextTests.cs +++ b/test/Microsoft.AspNetCore.SystemWebAdapters.Tests/HttpContextTests.cs @@ -8,6 +8,7 @@ using System.Web; using System.Web.Caching; using System.Web.SessionState; +using AutoFixture; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.SystemWebAdapters.SessionState; using Moq; @@ -17,6 +18,13 @@ namespace Microsoft.AspNetCore.SystemWebAdapters { public class HttpContextTests { + private readonly Fixture _fixture; + + public HttpContextTests() + { + _fixture = new Fixture(); + } + [Fact] public void ConstructorChecksNull() { @@ -336,48 +344,79 @@ public void ErrorWithFeatureAdd() exceptionFeature.Verify(f => f.Add(error), Times.Once); } - [InlineData("path1", "/path1", "", 0)] - [InlineData("/path1", "/path1", "", 0)] - [InlineData("path1?", "/path1", "", 0)] - [InlineData("/path1?", "/path1", "", 0)] - [InlineData("path1?q=1", "/path1", "?q=1", 1)] - [InlineData("/path1?q=1", "/path1", "?q=1", 1)] - [InlineData("/path1 ?q=1", "/path1", "?q=1", 1)] + [InlineData("path1", "/path1", null)] + [InlineData("/path1", "/path1", null)] + [InlineData("path1?", "/path1", "")] + [InlineData("/path1?", "/path1", "")] + [InlineData("path1?q=1", "/path1", "?q=1")] + [InlineData("/path1?q=1", "/path1", "?q=1")] + [InlineData("/path1 ?q=1", "/path1", "?q=1")] [Theory] - public void RewritePath(string rewritePath, string finalPath, string finalQuery, int queryCount) + public void RewritePath(string rewritePath, string finalPath, string finalQuery) { // Arrange var coreContext = new DefaultHttpContext(); + var feature = new Mock(); + coreContext.Features.Set(feature.Object); var context = new HttpContext(coreContext); // Act context.RewritePath(rewritePath); // Assert - Assert.Equal(finalPath, coreContext.Request.Path); - Assert.Equal(new(finalQuery), coreContext.Request.QueryString); - Assert.Equal(queryCount, coreContext.Request.Query.Count); + feature.Verify(f => f.Rewrite(finalPath, string.Empty, finalQuery, true), Times.Once); } - [Fact] - public void RewritePathWithSpace() + [InlineData("path1", "/path1", null, true)] + [InlineData("path1", "/path1", null, false)] + [InlineData("/path1", "/path1", null, true)] + [InlineData("/path1", "/path1", null, false)] + [InlineData("path1?", "/path1", "", true)] + [InlineData("path1?", "/path1", "", false)] + [InlineData("/path1?", "/path1", "", true)] + [InlineData("/path1?", "/path1", "", false)] + [InlineData("path1?q=1", "/path1", "?q=1", true)] + [InlineData("path1?q=1", "/path1", "?q=1", false)] + [InlineData("/path1?q=1", "/path1", "?q=1", true)] + [InlineData("/path1?q=1", "/path1", "?q=1", false)] + [InlineData("/path1 ?q=1", "/path1", "?q=1", true)] + [InlineData("/path1 ?q=1", "/path1", "?q=1", false)] + [Theory] + public void RewritePathWithRebaseValue(string rewritePath, string finalPath, string finalQuery, bool rebase) { // Arrange var coreContext = new DefaultHttpContext(); + var feature = new Mock(); + coreContext.Features.Set(feature.Object); var context = new HttpContext(coreContext); - var rewritePath = "/path1 withspace?q=1"; // Act - context.RewritePath(rewritePath); + context.RewritePath(rewritePath, rebase); // Assert - Assert.Equal("/path1%20withspace", coreContext.Request.Path); - Assert.Equal("/path1 withspace", context.Request.Path); - Assert.Collection(coreContext.Request.Query, q => - { - Assert.Equal("q", q.Key); - Assert.Equal("1", q.Value); - }); + feature.Verify(f => f.Rewrite(finalPath, string.Empty, finalQuery, rebase), Times.Once); + } + + [InlineData(true)] + [InlineData(false)] + [Theory] + public void RewritePathWithPathInfo(bool rebase) + { + // Arrange + var coreContext = new DefaultHttpContext(); + var feature = new Mock(); + coreContext.Features.Set(feature.Object); + var context = new HttpContext(coreContext); + + var filePath = _fixture.Create(); + var pathInfo = _fixture.Create(); + var query = _fixture.Create(); + + // Act + context.RewritePath(filePath, pathInfo, query, rebase); + + // Assert + feature.Verify(f => f.Rewrite(filePath, pathInfo, query, rebase), Times.Once); } } } diff --git a/test/Microsoft.AspNetCore.SystemWebAdapters.Tests/HttpRequestTests.cs b/test/Microsoft.AspNetCore.SystemWebAdapters.Tests/HttpRequestTests.cs index f1e39e97ab..17ac774e9b 100644 --- a/test/Microsoft.AspNetCore.SystemWebAdapters.Tests/HttpRequestTests.cs +++ b/test/Microsoft.AspNetCore.SystemWebAdapters.Tests/HttpRequestTests.cs @@ -45,32 +45,34 @@ public HttpRequestTests() public void Path() { // Arrange - var path = new PathString(CreateRandomPath()); - var coreRequest = new Mock(); - coreRequest.Setup(c => c.Path).Returns(path); + var context = new DefaultHttpContext(); + var path = CreateRandomPath(); - var request = new HttpRequest(coreRequest.Object); + var pathFeature = new Mock(); + pathFeature.Setup(p => p.Path).Returns(path); + context.Features.Set(pathFeature.Object); + + var request = new HttpRequest(context.Request); // Act var result = request.Path; // Assert - Assert.Equal(path.Value, result); + Assert.Equal(path, result); } [Fact] public void FilePathNoFeature() { // Arrange - var context = new Mock(); - context.Setup(c => c.Features).Returns(new FeatureCollection()); + var context = new DefaultHttpContext(); - var coreRequest = new Mock(); - var path = new PathString(CreateRandomPath()); - coreRequest.Setup(c => c.Path).Returns(path); - coreRequest.Setup(c => c.HttpContext).Returns(context.Object); + var pathFeature = new Mock(); + var path = CreateRandomPath(); + pathFeature.Setup(c => c.FilePath).Returns(path); + context.Features.Set(pathFeature.Object); - var request = new HttpRequest(coreRequest.Object); + var request = new HttpRequest(context.Request); // Act var result = request.FilePath; @@ -83,9 +85,9 @@ public void FilePathNoFeature() public void FilePathFeature() { // Arrange - var feature = new Mock(); + var feature = new Mock(); var path = CreateRandomPath(); - feature.Setup(f => f.FileInfo).Returns(path); + feature.Setup(f => f.FilePath).Returns(path); var features = new FeatureCollection(); features.Set(feature.Object); @@ -106,31 +108,11 @@ public void FilePathFeature() Assert.Equal(path, result); } - [Fact] - public void PathInfoNoFeature() - { - // Arrange - var context = new Mock(); - context.Setup(c => c.Features).Returns(new FeatureCollection()); - - var coreRequest = new Mock(); - coreRequest.Setup(c => c.Path).Returns(CreateRandomPath()); - coreRequest.Setup(c => c.HttpContext).Returns(context.Object); - - var request = new HttpRequest(coreRequest.Object); - - // Act - var result = request.PathInfo; - - // Assert - Assert.Same(string.Empty, result); - } - [Fact] public void PathInfoFeature() { // Arrange - var feature = new Mock(); + var feature = new Mock(); var path = CreateRandomPath(); feature.Setup(f => f.PathInfo).Returns(path); @@ -490,18 +472,14 @@ public void IsLocalNullLocal(bool isLoopback) public void AppRelativeCurrentExecutionFilePath() { // Arrange - var context = new Mock(); - context.Setup(c => c.Features).Returns(new FeatureCollection()); + var features = new FeatureCollection(); + var context = new DefaultHttpContext(); - var coreRequest = new Mock(); - coreRequest.Setup(c => c.Scheme).Returns("http"); - coreRequest.Setup(c => c.Host).Returns(new HostString("www.A.com")); - coreRequest.Setup(c => c.Path).Returns("/B/ C"); - coreRequest.Setup(c => c.QueryString).Returns(new QueryString("?D=E")); - coreRequest.Setup(c => c.PathBase).Returns("/F"); - coreRequest.Setup(c => c.HttpContext).Returns(context.Object); + var pathFeature = new Mock(); + pathFeature.Setup(p => p.FilePath).Returns("/B/ C"); + context.Features.Set(pathFeature.Object); - var request = new HttpRequest(coreRequest.Object); + var request = new HttpRequest(context.Request); // Act var result = request.AppRelativeCurrentExecutionFilePath;