From 94c895a1bd1b9bba48ce496200fd386322fb6a74 Mon Sep 17 00:00:00 2001 From: Justin Kotalik Date: Wed, 25 Oct 2017 12:35:13 -0700 Subject: [PATCH] Parse Path and PathBase from Virtual Directory. (#457) --- .../NativeMethods.cs | 3 +- .../Server/IISHttpContext.cs | 20 ++++--------- .../Server/IISHttpServer.cs | 2 -- .../Server/IISServerSetupFilter.cs | 28 +++++++++++++++++++ .../WebHostBuilderIISExtensions.cs | 12 ++++++-- 5 files changed, 44 insertions(+), 21 deletions(-) create mode 100644 src/Microsoft.AspNetCore.Server.IISIntegration/Server/IISServerSetupFilter.cs diff --git a/src/Microsoft.AspNetCore.Server.IISIntegration/NativeMethods.cs b/src/Microsoft.AspNetCore.Server.IISIntegration/NativeMethods.cs index 5f4e06cadb..169985495f 100644 --- a/src/Microsoft.AspNetCore.Server.IISIntegration/NativeMethods.cs +++ b/src/Microsoft.AspNetCore.Server.IISIntegration/NativeMethods.cs @@ -75,8 +75,7 @@ namespace Microsoft.AspNetCore.Server.IISIntegration public unsafe static extern bool http_set_managed_context(IntPtr pHttpContext, IntPtr pvManagedContext); [DllImport(AspNetCoreModuleDll)] - [return: MarshalAs(UnmanagedType.BStr)] - public unsafe static extern string http_get_application_full_path(); + public unsafe static extern int http_get_application_paths([MarshalAs(UnmanagedType.BStr)] out string fullPath, [MarshalAs(UnmanagedType.BStr)] out string virtualPath); [DllImport(AspNetCoreModuleDll)] public unsafe static extern bool http_shutdown(); diff --git a/src/Microsoft.AspNetCore.Server.IISIntegration/Server/IISHttpContext.cs b/src/Microsoft.AspNetCore.Server.IISIntegration/Server/IISHttpContext.cs index e64542864b..5d3fa722d1 100644 --- a/src/Microsoft.AspNetCore.Server.IISIntegration/Server/IISHttpContext.cs +++ b/src/Microsoft.AspNetCore.Server.IISIntegration/Server/IISHttpContext.cs @@ -67,7 +67,7 @@ namespace Microsoft.AspNetCore.Server.IISIntegration _pipeFactory = pipeFactory; _pHttpContext = pHttpContext; - NativeMethods.http_set_managed_context(pHttpContext, (IntPtr)_thisHandle); + NativeMethods.http_set_managed_context(_pHttpContext, (IntPtr)_thisHandle); unsafe { Method = GetVerb(); @@ -80,27 +80,17 @@ namespace Microsoft.AspNetCore.Server.IISIntegration var originalPath = RequestUriBuilder.DecodeAndUnescapePath(GetRawUrlInBytes()); - // TODO: Read this from IIS config - // See https://github.com/aspnet/IISIntegration/issues/427 - var prefix = "/"; if (KnownMethod == HttpApiTypes.HTTP_VERB.HttpVerbOPTIONS && string.Equals(RawTarget, "*", StringComparison.Ordinal)) { PathBase = string.Empty; Path = string.Empty; } - // These paths are both unescaped already. - else if (originalPath.Length == prefix.Length - 1) - { - // They matched exactly except for the trailing slash. - PathBase = originalPath; - Path = string.Empty; - } else { - // url: /base/path, prefix: /base/, base: /base, path: /path - // url: /, prefix: /, base: , path: / - PathBase = originalPath.Substring(0, prefix.Length - 1); - Path = originalPath.Substring(prefix.Length - 1); + // Path and pathbase are unescaped by RequestUriBuilder + // The UsePathBase middleware will modify the pathbase and path correctly + PathBase = string.Empty; + Path = originalPath; } var cookedUrl = GetCookedUrl(); diff --git a/src/Microsoft.AspNetCore.Server.IISIntegration/Server/IISHttpServer.cs b/src/Microsoft.AspNetCore.Server.IISIntegration/Server/IISHttpServer.cs index 714c91dda6..e65afdfb0a 100644 --- a/src/Microsoft.AspNetCore.Server.IISIntegration/Server/IISHttpServer.cs +++ b/src/Microsoft.AspNetCore.Server.IISIntegration/Server/IISHttpServer.cs @@ -9,7 +9,6 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting.Server; using Microsoft.AspNetCore.Http.Features; -using Microsoft.Extensions.DependencyInjection; namespace Microsoft.AspNetCore.Server.IISIntegration { @@ -38,7 +37,6 @@ namespace Microsoft.AspNetCore.Server.IISIntegration _iisContextFactory = new IISContextFactory(_pipeFactory, application); // Start the server by registering the callback - // TODO the context may change here for shutdown. NativeMethods.register_callbacks(_requestHandler, _shutdownHandler, _onAsyncCompletion, (IntPtr)_httpServerHandle, (IntPtr)_httpServerHandle); return Task.CompletedTask; diff --git a/src/Microsoft.AspNetCore.Server.IISIntegration/Server/IISServerSetupFilter.cs b/src/Microsoft.AspNetCore.Server.IISIntegration/Server/IISServerSetupFilter.cs new file mode 100644 index 0000000000..94fa2ac136 --- /dev/null +++ b/src/Microsoft.AspNetCore.Server.IISIntegration/Server/IISServerSetupFilter.cs @@ -0,0 +1,28 @@ +// 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; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; + +namespace Microsoft.AspNetCore.Server.IISIntegration +{ + internal class IISServerSetupFilter : IStartupFilter + { + private string _virtualPath; + + public IISServerSetupFilter(string virtualPath) + { + _virtualPath = virtualPath; + } + + public Action Configure(Action next) + { + return app => + { + app.UsePathBase(_virtualPath); + next(app); + }; + } + } +} diff --git a/src/Microsoft.AspNetCore.Server.IISIntegration/WebHostBuilderIISExtensions.cs b/src/Microsoft.AspNetCore.Server.IISIntegration/WebHostBuilderIISExtensions.cs index 7d452f97f1..2a09eed46b 100644 --- a/src/Microsoft.AspNetCore.Server.IISIntegration/WebHostBuilderIISExtensions.cs +++ b/src/Microsoft.AspNetCore.Server.IISIntegration/WebHostBuilderIISExtensions.cs @@ -45,11 +45,19 @@ namespace Microsoft.AspNetCore.Hosting hostBuilder.UseSetting(nameof(UseIISIntegration), "true"); hostBuilder.CaptureStartupErrors(true); - var applicationPath = NativeMethods.http_get_application_full_path(); - hostBuilder.UseContentRoot(applicationPath); + // TODO consider adding a configuration load where all variables needed are loaded from ANCM in one call. + var hResult = NativeMethods.http_get_application_paths(out var fullPath, out var virtualPath); + var exception = Marshal.GetExceptionForHR(hResult); + if (exception != null) + { + throw exception; + } + + hostBuilder.UseContentRoot(fullPath); return hostBuilder.ConfigureServices(services => { services.AddSingleton(); + services.AddSingleton(new IISServerSetupFilter(virtualPath)); services.AddAuthenticationCore(); }); }