From ac30a4adeb75e2d8f9188595eb02ba9e3d153bc3 Mon Sep 17 00:00:00 2001 From: Taylor Southwick Date: Wed, 16 Aug 2023 14:39:28 -0700 Subject: [PATCH 01/15] Add IIISEnvironmentFeature --- .../AspNetCoreModuleV2/AspNetCore/Source.def | 1 + .../AspNetCoreModuleV2/AspNetCore/dllmain.cpp | 8 ++- .../InProcessOptions.cpp | 10 ++- .../InProcessOptions.h | 30 ++++++++- .../managedexports.cpp | 30 +++++++++ .../IIS/samples/NativeIISSample/Startup.cs | 16 ++++- .../IIS/IIS/src/Core/IISConfigurationData.cs | 65 ++++++++++++++++++- src/Servers/IIS/IIS/src/Core/IISHttpServer.cs | 1 + .../IIS/IIS/src/IIISEnvironmentFeature.cs | 50 ++++++++++++++ src/Servers/IIS/IIS/src/IISUtility.cs | 26 ++++++++ .../IIS/IIS/src/PublicAPI.Unshipped.txt | 13 +++- 11 files changed, 242 insertions(+), 8 deletions(-) create mode 100644 src/Servers/IIS/IIS/src/IIISEnvironmentFeature.cs create mode 100644 src/Servers/IIS/IIS/src/IISUtility.cs diff --git a/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/Source.def b/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/Source.def index 74135f48355d..563a58605cab 100644 --- a/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/Source.def +++ b/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/Source.def @@ -2,3 +2,4 @@ LIBRARY aspnetcorev2 EXPORTS RegisterModule + GetIISVersion diff --git a/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/dllmain.cpp b/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/dllmain.cpp index acf90e07c622..90ae1bcc932b 100644 --- a/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/dllmain.cpp +++ b/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/dllmain.cpp @@ -63,6 +63,12 @@ BOOL WINAPI DllMain(HMODULE hModule, return TRUE; } +DWORD dwIISServerVersion; + +DWORD __stdcall GetIISVersion() { + return dwIISServerVersion; +} + HRESULT __stdcall RegisterModule( @@ -90,7 +96,7 @@ HRESULT --*/ { - UNREFERENCED_PARAMETER(dwServerVersion); + dwIISServerVersion = dwServerVersion; if (pHttpServer->IsCommandLineLaunch()) { diff --git a/src/Servers/IIS/AspNetCoreModuleV2/InProcessRequestHandler/InProcessOptions.cpp b/src/Servers/IIS/AspNetCoreModuleV2/InProcessRequestHandler/InProcessOptions.cpp index 157f0dda2265..a21594468605 100644 --- a/src/Servers/IIS/AspNetCoreModuleV2/InProcessRequestHandler/InProcessOptions.cpp +++ b/src/Servers/IIS/AspNetCoreModuleV2/InProcessRequestHandler/InProcessOptions.cpp @@ -15,7 +15,7 @@ HRESULT InProcessOptions::Create( try { const WebConfigConfigurationSource configurationSource(pServer.GetAdminManager(), pHttpApplication); - options = std::make_unique(configurationSource, site); + options = std::make_unique(configurationSource, &pServer, site); } catch (InvalidOperationException& ex) { @@ -40,7 +40,7 @@ HRESULT InProcessOptions::Create( return S_OK; } -InProcessOptions::InProcessOptions(const ConfigurationSource &configurationSource, IHttpSite* pSite) : +InProcessOptions::InProcessOptions(const ConfigurationSource &configurationSource, IHttpServer* server, IHttpSite* pSite) : m_fStdoutLogEnabled(false), m_fWindowsAuthEnabled(false), m_fBasicAuthEnabled(false), @@ -49,6 +49,12 @@ InProcessOptions::InProcessOptions(const ConfigurationSource &configurationSourc m_dwStartupTimeLimitInMS(INFINITE), m_dwShutdownTimeLimitInMS(INFINITE) { + m_dwSiteId = pSite->GetSiteId(); + m_strSiteName = std::wstring(pSite->GetSiteName()); + + m_appPoolId = std::wstring(server->GetAppPoolName()); + m_appPoolConfig = ((IHttpServer2*)server)->GetAppPoolConfigFile(); + auto const aspNetCoreSection = configurationSource.GetRequiredSection(CS_ASPNETCORE_SECTION); m_strArguments = aspNetCoreSection->GetString(CS_ASPNETCORE_PROCESS_ARGUMENTS).value_or(CS_ASPNETCORE_PROCESS_ARGUMENTS_DEFAULT); m_strProcessPath = aspNetCoreSection->GetRequiredString(CS_ASPNETCORE_PROCESS_EXE_PATH); diff --git a/src/Servers/IIS/AspNetCoreModuleV2/InProcessRequestHandler/InProcessOptions.h b/src/Servers/IIS/AspNetCoreModuleV2/InProcessRequestHandler/InProcessOptions.h index fa0e19e84952..dcb7a56a0e1e 100644 --- a/src/Servers/IIS/AspNetCoreModuleV2/InProcessRequestHandler/InProcessOptions.h +++ b/src/Servers/IIS/AspNetCoreModuleV2/InProcessRequestHandler/InProcessOptions.h @@ -12,6 +12,30 @@ class InProcessOptions: NonCopyable { public: + const std::wstring& + QueryAppPoolConfig() const + { + return m_appPoolConfig; + } + + const std::wstring& + QueryAppPoolId() const + { + return m_appPoolId; + } + + const std::wstring& + QuerySiteName() const + { + return m_strSiteName; + } + + const DWORD + QuerySiteId() const + { + return m_dwSiteId; + } + const std::wstring& QueryProcessPath() const { @@ -124,7 +148,7 @@ class InProcessOptions: NonCopyable return m_fSuppressRecycleOnStartupTimeout; } - InProcessOptions(const ConfigurationSource &configurationSource, IHttpSite* pSite); + InProcessOptions(const ConfigurationSource &configurationSource, IHttpServer* server, IHttpSite* pSite); static HRESULT InProcessOptions::Create( @@ -136,8 +160,11 @@ class InProcessOptions: NonCopyable private: std::wstring m_strArguments; std::wstring m_strProcessPath; + std::wstring m_strSiteName; std::wstring m_struStdoutLogFile; std::wstring m_strStackSize; + std::wstring m_appPoolId; + std::wstring m_appPoolConfig; bool m_fStdoutLogEnabled; bool m_fDisableStartUpErrorPage; bool m_fSetCurrentDirectory; @@ -146,6 +173,7 @@ class InProcessOptions: NonCopyable bool m_fBasicAuthEnabled; bool m_fAnonymousAuthEnabled; bool m_fSuppressRecycleOnStartupTimeout; + DWORD m_dwSiteId; DWORD m_dwStartupTimeLimitInMS; DWORD m_dwShutdownTimeLimitInMS; DWORD m_dwMaxRequestBodySize; diff --git a/src/Servers/IIS/AspNetCoreModuleV2/InProcessRequestHandler/managedexports.cpp b/src/Servers/IIS/AspNetCoreModuleV2/InProcessRequestHandler/managedexports.cpp index 23639860527a..974ad494aea9 100644 --- a/src/Servers/IIS/AspNetCoreModuleV2/InProcessRequestHandler/managedexports.cpp +++ b/src/Servers/IIS/AspNetCoreModuleV2/InProcessRequestHandler/managedexports.cpp @@ -222,6 +222,24 @@ http_get_completion_info( *hr = info->GetCompletionStatus(); } +// Attempts to load the IIS version if it is exported from the module. This was added in .NET 8, +// and if it is unavailable to defaults to 0 +DWORD GetIISVersion() { + auto module = GetModuleHandle(L"aspnetcorev2.dll"); + + if (module != nullptr) + { + auto func = (DWORD(_stdcall*)()) GetProcAddress(module, "GetIISVersion"); + + if (func != NULL) + { + return func(); + } + } + + return 0; +} + // // the signature should be changed. application's based address should be passed in // @@ -236,6 +254,12 @@ struct IISConfigurationData BOOL fAnonymousAuthEnable; BSTR pwzBindings; DWORD maxRequestBodySize; + BSTR pwzApplicationId; + BSTR pwzSiteName; + DWORD siteId; + BSTR pwzAppPoolId; + BSTR pwzAppPoolConfig; + DWORD iisVersion; }; EXTERN_C __declspec(dllexport) @@ -258,6 +282,12 @@ http_get_application_properties( pIISConfigurationData->fWindowsAuthEnabled = pConfiguration.QueryWindowsAuthEnabled(); pIISConfigurationData->fBasicAuthEnabled = pConfiguration.QueryBasicAuthEnabled(); pIISConfigurationData->fAnonymousAuthEnable = pConfiguration.QueryAnonymousAuthEnabled(); + pIISConfigurationData->pwzApplicationId = SysAllocString(pInProcessApplication->QueryApplicationId().c_str()); + pIISConfigurationData->siteId = pInProcessApplication->QueryConfig().QuerySiteId(); + pIISConfigurationData->pwzSiteName = SysAllocString(pInProcessApplication->QueryConfig().QuerySiteName().c_str()); + pIISConfigurationData->pwzAppPoolId = SysAllocString(pInProcessApplication->QueryConfig().QueryAppPoolId().c_str()); + pIISConfigurationData->pwzAppPoolConfig = SysAllocString(pInProcessApplication->QueryConfig().QueryAppPoolConfig().c_str()); + pIISConfigurationData->iisVersion = GetIISVersion(); auto const serverAddresses = BindingInformation::Format(pConfiguration.QueryBindings(), pInProcessApplication->QueryApplicationVirtualPath()); pIISConfigurationData->pwzBindings = SysAllocString(serverAddresses.c_str()); diff --git a/src/Servers/IIS/IIS/samples/NativeIISSample/Startup.cs b/src/Servers/IIS/IIS/samples/NativeIISSample/Startup.cs index cf3267fff681..55cad0253118 100644 --- a/src/Servers/IIS/IIS/samples/NativeIISSample/Startup.cs +++ b/src/Servers/IIS/IIS/samples/NativeIISSample/Startup.cs @@ -96,11 +96,25 @@ public void Configure(IApplicationBuilder app) } await context.Response.WriteAsync(Environment.NewLine); - var addresses = context.RequestServices.GetService().Features.Get(); + var server = context.RequestServices.GetService(); + + var addresses = server.Features.Get(); foreach (var key in addresses.Addresses) { await context.Response.WriteAsync(key + Environment.NewLine); } + + var envFeature = server.Features.Get(); + await context.Response.WriteAsync(Environment.NewLine); + await context.Response.WriteAsync("IIS Environment Information:" + Environment.NewLine); + await context.Response.WriteAsync("IIS Version: " + envFeature.IISVersion + Environment.NewLine); + await context.Response.WriteAsync("ApplicationId: " + envFeature.ApplicationId + Environment.NewLine); + await context.Response.WriteAsync("Application Path: " + envFeature.ApplicationPath + Environment.NewLine); + await context.Response.WriteAsync("Application Virtual Path: " + envFeature.ApplicationVirtualPath + Environment.NewLine); + await context.Response.WriteAsync("AppPool Config: " + envFeature.AppPoolConfig + Environment.NewLine); + await context.Response.WriteAsync("AppPool ID: " + envFeature.AppPoolId + Environment.NewLine); + await context.Response.WriteAsync("Site ID: " + envFeature.SiteId + Environment.NewLine); + await context.Response.WriteAsync("Site Name: " + envFeature.SiteName + Environment.NewLine); }); } diff --git a/src/Servers/IIS/IIS/src/Core/IISConfigurationData.cs b/src/Servers/IIS/IIS/src/Core/IISConfigurationData.cs index 41f3aba13f46..f58bdbc66d39 100644 --- a/src/Servers/IIS/IIS/src/Core/IISConfigurationData.cs +++ b/src/Servers/IIS/IIS/src/Core/IISConfigurationData.cs @@ -8,7 +8,7 @@ namespace Microsoft.AspNetCore.Server.IIS.Core; [NativeMarshalling(typeof(Marshaller))] [StructLayout(LayoutKind.Sequential)] -internal struct IISConfigurationData +internal struct IISConfigurationData : IIISEnvironmentFeature { public IntPtr pNativeApplication; public string pwzFullApplicationPath; @@ -18,6 +18,28 @@ internal struct IISConfigurationData public bool fAnonymousAuthEnable; public string pwzBindings; public uint maxRequestBodySize; + public string pwzApplicationId; + public string pwzSiteName; + public uint siteId; + public string pwzAppPoolId; + public string pwzAppPoolConfig; + public Version version; + + Version IIISEnvironmentFeature.IISVersion => version; + + string IIISEnvironmentFeature.AppPoolId => pwzAppPoolId; + + string IIISEnvironmentFeature.AppPoolConfig => pwzAppPoolConfig; + + string IIISEnvironmentFeature.ApplicationId => pwzApplicationId; + + string IIISEnvironmentFeature.SiteName => pwzSiteName; + + uint IIISEnvironmentFeature.SiteId => siteId; + + string IIISEnvironmentFeature.ApplicationPath => pwzFullApplicationPath; + + string IIISEnvironmentFeature.ApplicationVirtualPath => pwzVirtualApplicationPath; [CustomMarshaller(typeof(IISConfigurationData), MarshalMode.Default, typeof(Marshaller))] public static class Marshaller @@ -32,6 +54,12 @@ public struct Native public int fAnonymousAuthEnable; public IntPtr pwzBindings; public uint maxRequestBodySize; + public IntPtr pwzApplicationId; + public IntPtr pwzSiteName; + public uint siteId; + public IntPtr pwzAppPoolId; + public IntPtr pwzAppPoolConfig; + public uint version; } public static Native ConvertToUnmanaged(IISConfigurationData managed) @@ -45,9 +73,20 @@ public static Native ConvertToUnmanaged(IISConfigurationData managed) native.fAnonymousAuthEnable = managed.fAnonymousAuthEnable ? 1 : 0; native.pwzBindings = managed.pwzBindings is null ? IntPtr.Zero : Marshal.StringToBSTR(managed.pwzBindings); native.maxRequestBodySize = managed.maxRequestBodySize; + native.pwzApplicationId = managed.pwzApplicationId is null ? IntPtr.Zero : Marshal.StringToBSTR(managed.pwzApplicationId); + native.pwzSiteName = managed.pwzSiteName is null ? IntPtr.Zero : Marshal.StringToBSTR(managed.pwzApplicationId); + native.siteId = managed.siteId; + native.pwzAppPoolId = managed.pwzAppPoolId is null ? IntPtr.Zero : Marshal.StringToBSTR(managed.pwzAppPoolId); + native.pwzAppPoolConfig = managed.pwzAppPoolConfig is null ? IntPtr.Zero : Marshal.StringToBSTR(managed.pwzAppPoolConfig); + native.version = ConvertFromVersion(managed.version); + return native; } + private static Version ConvertToVersion(uint dwVersion) => new((int)(dwVersion >> 16), (int)(dwVersion & 0xffff)); + + private static uint ConvertFromVersion(Version version) => ((uint)version.Major << 16) | ((uint)version.Minor); + public static void Free(Native native) { if (native.pwzFullApplicationPath != IntPtr.Zero) @@ -62,6 +101,22 @@ public static void Free(Native native) { Marshal.FreeBSTR(native.pwzBindings); } + if (native.pwzApplicationId != IntPtr.Zero) + { + Marshal.FreeBSTR(native.pwzApplicationId); + } + if (native.pwzSiteName != IntPtr.Zero) + { + Marshal.FreeBSTR(native.pwzSiteName); + } + if (native.pwzAppPoolId != IntPtr.Zero) + { + Marshal.FreeBSTR(native.pwzAppPoolId); + } + if (native.pwzAppPoolConfig != IntPtr.Zero) + { + Marshal.FreeBSTR(native.pwzAppPoolConfig); + } } public static IISConfigurationData ConvertToManaged(Native native) @@ -75,7 +130,13 @@ public static IISConfigurationData ConvertToManaged(Native native) fBasicAuthEnabled = native.fBasicAuthEnabled != 0, fAnonymousAuthEnable = native.fAnonymousAuthEnable != 0, pwzBindings = native.pwzBindings == IntPtr.Zero ? string.Empty : Marshal.PtrToStringBSTR(native.pwzBindings), - maxRequestBodySize = native.maxRequestBodySize + maxRequestBodySize = native.maxRequestBodySize, + pwzApplicationId = native.pwzApplicationId == IntPtr.Zero ? string.Empty : Marshal.PtrToStringBSTR(native.pwzApplicationId), + pwzSiteName = native.pwzSiteName == IntPtr.Zero ? string.Empty : Marshal.PtrToStringBSTR(native.pwzSiteName), + siteId = native.siteId, + pwzAppPoolConfig = native.pwzAppPoolConfig == IntPtr.Zero ? string.Empty : Marshal.PtrToStringBSTR(native.pwzAppPoolConfig), + pwzAppPoolId = native.pwzAppPoolId == IntPtr.Zero ? string.Empty : Marshal.PtrToStringBSTR(native.pwzAppPoolId), + version = ConvertToVersion(native.version), }; } } diff --git a/src/Servers/IIS/IIS/src/Core/IISHttpServer.cs b/src/Servers/IIS/IIS/src/Core/IISHttpServer.cs index 44fff105615d..ce99b8bdc86d 100644 --- a/src/Servers/IIS/IIS/src/Core/IISHttpServer.cs +++ b/src/Servers/IIS/IIS/src/Core/IISHttpServer.cs @@ -76,6 +76,7 @@ ILogger logger } Features.Set(_serverAddressesFeature); + Features.Set(iisConfigData); if (_options.MaxRequestBodySize > _options.IisMaxRequestSizeLimit) { diff --git a/src/Servers/IIS/IIS/src/IIISEnvironmentFeature.cs b/src/Servers/IIS/IIS/src/IIISEnvironmentFeature.cs new file mode 100644 index 000000000000..c807dca6adc7 --- /dev/null +++ b/src/Servers/IIS/IIS/src/IIISEnvironmentFeature.cs @@ -0,0 +1,50 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Microsoft.AspNetCore.Server.IIS; + +/// +/// This feature provides access to IIS application information +/// +public interface IIISEnvironmentFeature +{ + /// + /// Gets the version of IIS that is being used. + /// + Version IISVersion { get; } + + /// + /// Gets the AppPool Id that is currently running + /// + string AppPoolId { get; } + + /// + /// Gets path to the AppPool configuration that is currently running + /// + string AppPoolConfig { get; } + + /// + /// Gets the path of the application. + /// + string ApplicationPath { get; } + + /// + /// Gets the virtual path of the application. + /// + string ApplicationVirtualPath { get; } + + /// + /// Gets ID of the current application. + /// + string ApplicationId { get; } + + /// + /// Gets the name of the current site. + /// + string SiteName { get; } + + /// + /// Gets the id of the current site. + /// + uint SiteId { get; } +} diff --git a/src/Servers/IIS/IIS/src/IISUtility.cs b/src/Servers/IIS/IIS/src/IISUtility.cs new file mode 100644 index 000000000000..b1afc373bab2 --- /dev/null +++ b/src/Servers/IIS/IIS/src/IISUtility.cs @@ -0,0 +1,26 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Microsoft.AspNetCore.Hosting.Server; + +namespace Microsoft.AspNetCore.Server.IIS; + +/// +/// Utility to access IIS details. +/// +public static class IISUtility +{ + /// + /// Gets the for the current application if available. + /// If possible, prefer to access this value. + /// + public static IIISEnvironmentFeature? GetEnvironmentFeature() + { + if (NativeMethods.IsAspNetCoreModuleLoaded()) + { + return NativeMethods.HttpGetApplicationProperties(); + } + + return null; + } +} diff --git a/src/Servers/IIS/IIS/src/PublicAPI.Unshipped.txt b/src/Servers/IIS/IIS/src/PublicAPI.Unshipped.txt index bdbf94be0126..123f40bd7e8b 100644 --- a/src/Servers/IIS/IIS/src/PublicAPI.Unshipped.txt +++ b/src/Servers/IIS/IIS/src/PublicAPI.Unshipped.txt @@ -26,4 +26,15 @@ *REMOVED*override Microsoft.AspNetCore.Server.IIS.Core.WriteOnlyStream.ReadTimeout.get -> int *REMOVED*override Microsoft.AspNetCore.Server.IIS.Core.WriteOnlyStream.ReadTimeout.set -> void *REMOVED*override Microsoft.AspNetCore.Server.IIS.Core.WriteOnlyStream.Seek(long offset, System.IO.SeekOrigin origin) -> long -*REMOVED*override Microsoft.AspNetCore.Server.IIS.Core.WriteOnlyStream.SetLength(long value) -> void \ No newline at end of file +*REMOVED*override Microsoft.AspNetCore.Server.IIS.Core.WriteOnlyStream.SetLength(long value) -> void +Microsoft.AspNetCore.Server.IIS.IIISEnvironmentFeature +Microsoft.AspNetCore.Server.IIS.IIISEnvironmentFeature.ApplicationId.get -> string! +Microsoft.AspNetCore.Server.IIS.IIISEnvironmentFeature.ApplicationPath.get -> string! +Microsoft.AspNetCore.Server.IIS.IIISEnvironmentFeature.ApplicationVirtualPath.get -> string! +Microsoft.AspNetCore.Server.IIS.IIISEnvironmentFeature.AppPoolConfig.get -> string! +Microsoft.AspNetCore.Server.IIS.IIISEnvironmentFeature.AppPoolId.get -> string! +Microsoft.AspNetCore.Server.IIS.IIISEnvironmentFeature.IISVersion.get -> System.Version! +Microsoft.AspNetCore.Server.IIS.IIISEnvironmentFeature.SiteId.get -> uint +Microsoft.AspNetCore.Server.IIS.IIISEnvironmentFeature.SiteName.get -> string! +Microsoft.AspNetCore.Server.IIS.IISUtility +static Microsoft.AspNetCore.Server.IIS.IISUtility.GetEnvironmentFeature() -> Microsoft.AspNetCore.Server.IIS.IIISEnvironmentFeature? From 53ecd81403d957d9b0c427f32f09f09a85c32cb1 Mon Sep 17 00:00:00 2001 From: Taylor Southwick Date: Thu, 17 Aug 2023 10:57:47 -0700 Subject: [PATCH 02/15] Use environment variables --- .../AspNetCore/ApplicationFactory.h | 3 + .../AspNetCore/AspNetCore.vcxproj | 2 + .../AspNetCore/ModuleEnvironment.cpp | 49 ++++++++++++++ .../AspNetCore/ModuleEnvironment.h | 3 + .../AspNetCoreModuleV2/AspNetCore/Source.def | 1 - .../AspNetCoreModuleV2/AspNetCore/dllmain.cpp | 4 -- .../InProcessOptions.cpp | 10 +-- .../InProcessOptions.h | 30 +-------- .../managedexports.cpp | 30 --------- .../IIS/samples/NativeIISSample/Startup.cs | 6 +- .../IIS/IIS/src/Core/EnvironmentIISDetails.cs | 53 +++++++++++++++ .../IIS/IIS/src/Core/IISConfigurationData.cs | 65 +------------------ src/Servers/IIS/IIS/src/Core/IISHttpServer.cs | 2 +- .../IIS/IIS/src/IIISEnvironmentFeature.cs | 6 +- src/Servers/IIS/IIS/src/IISUtility.cs | 10 +-- .../IIS/IIS/src/PublicAPI.Unshipped.txt | 10 ++- 16 files changed, 128 insertions(+), 156 deletions(-) create mode 100644 src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/ModuleEnvironment.cpp create mode 100644 src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/ModuleEnvironment.h create mode 100644 src/Servers/IIS/IIS/src/Core/EnvironmentIISDetails.cs diff --git a/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/ApplicationFactory.h b/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/ApplicationFactory.h index 9906251f532f..fa7231c06273 100644 --- a/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/ApplicationFactory.h +++ b/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/ApplicationFactory.h @@ -8,6 +8,7 @@ #include #include "iapplication.h" #include "HandleWrapper.h" +#include "ModuleEnvironment.h" typedef HRESULT @@ -46,6 +47,8 @@ class ApplicationFactory } }; + SetApplicationEnvironmentVariables(pServer, pHttpContext); + return m_pfnAspNetCoreCreateApplication(pServer, pHttpContext->GetApplication(), parameters.data(), static_cast(parameters.size()), pApplication); } diff --git a/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/AspNetCore.vcxproj b/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/AspNetCore.vcxproj index 85cb5b49021d..8e1eb1f7c700 100644 --- a/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/AspNetCore.vcxproj +++ b/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/AspNetCore.vcxproj @@ -35,6 +35,7 @@ + @@ -49,6 +50,7 @@ + diff --git a/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/ModuleEnvironment.cpp b/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/ModuleEnvironment.cpp new file mode 100644 index 000000000000..2b45d936233b --- /dev/null +++ b/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/ModuleEnvironment.cpp @@ -0,0 +1,49 @@ +#include "ModuleEnvironment.h" +#include +#include + +extern DWORD dwIISServerVersion; + +static std::wstring GetIISVersion() { + auto major = (int)(dwIISServerVersion >> 16); + auto minor = (int)(dwIISServerVersion & 0xffff); + + std::wstringstream version; + version << major << "." << minor; + + return version.str(); +} + +static std::wstring ToVirtualPath(const std::wstring& configurationPath) +{ + auto segments = 0; + auto position = configurationPath.find('/'); + // Skip first 4 segments of config path + while (segments != 3 && position != std::wstring::npos) + { + segments++; + position = configurationPath.find('/', position + 1); + } + + if (position != std::wstring::npos) + { + return configurationPath.substr(position); + } + + return L"/"; +} + +void SetApplicationEnvironmentVariables(_In_ IHttpServer* pServer, _In_ IHttpContext* pHttpContext) { + SetEnvironmentVariable(L"ANCM_IISVersion", GetIISVersion().c_str()); + SetEnvironmentVariable(L"ANCM_AppPoolName", pServer->GetAppPoolName()); + + auto site = pHttpContext->GetSite(); + SetEnvironmentVariable(L"ANCM_SiteName", site->GetSiteName()); + SetEnvironmentVariable(L"ANCM_SiteId", std::to_wstring(site->GetSiteId()).c_str()); + + auto app = pHttpContext->GetApplication(); + SetEnvironmentVariable(L"ANCM_AppConfigPath", app->GetAppConfigPath()); + SetEnvironmentVariable(L"ANCM_ApplicationId", app->GetApplicationId()); + SetEnvironmentVariable(L"ANCM_ApplicationPhysicalPath", app->GetApplicationPhysicalPath()); + SetEnvironmentVariable(L"ANCM_ApplicationVirtualPath", ToVirtualPath(app->GetAppConfigPath()).c_str()); +} diff --git a/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/ModuleEnvironment.h b/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/ModuleEnvironment.h new file mode 100644 index 000000000000..557ba4a76b25 --- /dev/null +++ b/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/ModuleEnvironment.h @@ -0,0 +1,3 @@ +#pragma once + +void SetApplicationEnvironmentVariables(_In_ IHttpServer* pServer, _In_ IHttpContext* pHttpContext); diff --git a/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/Source.def b/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/Source.def index 563a58605cab..74135f48355d 100644 --- a/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/Source.def +++ b/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/Source.def @@ -2,4 +2,3 @@ LIBRARY aspnetcorev2 EXPORTS RegisterModule - GetIISVersion diff --git a/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/dllmain.cpp b/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/dllmain.cpp index 90ae1bcc932b..c8026430a5d5 100644 --- a/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/dllmain.cpp +++ b/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/dllmain.cpp @@ -65,10 +65,6 @@ BOOL WINAPI DllMain(HMODULE hModule, DWORD dwIISServerVersion; -DWORD __stdcall GetIISVersion() { - return dwIISServerVersion; -} - HRESULT __stdcall RegisterModule( diff --git a/src/Servers/IIS/AspNetCoreModuleV2/InProcessRequestHandler/InProcessOptions.cpp b/src/Servers/IIS/AspNetCoreModuleV2/InProcessRequestHandler/InProcessOptions.cpp index a21594468605..157f0dda2265 100644 --- a/src/Servers/IIS/AspNetCoreModuleV2/InProcessRequestHandler/InProcessOptions.cpp +++ b/src/Servers/IIS/AspNetCoreModuleV2/InProcessRequestHandler/InProcessOptions.cpp @@ -15,7 +15,7 @@ HRESULT InProcessOptions::Create( try { const WebConfigConfigurationSource configurationSource(pServer.GetAdminManager(), pHttpApplication); - options = std::make_unique(configurationSource, &pServer, site); + options = std::make_unique(configurationSource, site); } catch (InvalidOperationException& ex) { @@ -40,7 +40,7 @@ HRESULT InProcessOptions::Create( return S_OK; } -InProcessOptions::InProcessOptions(const ConfigurationSource &configurationSource, IHttpServer* server, IHttpSite* pSite) : +InProcessOptions::InProcessOptions(const ConfigurationSource &configurationSource, IHttpSite* pSite) : m_fStdoutLogEnabled(false), m_fWindowsAuthEnabled(false), m_fBasicAuthEnabled(false), @@ -49,12 +49,6 @@ InProcessOptions::InProcessOptions(const ConfigurationSource &configurationSourc m_dwStartupTimeLimitInMS(INFINITE), m_dwShutdownTimeLimitInMS(INFINITE) { - m_dwSiteId = pSite->GetSiteId(); - m_strSiteName = std::wstring(pSite->GetSiteName()); - - m_appPoolId = std::wstring(server->GetAppPoolName()); - m_appPoolConfig = ((IHttpServer2*)server)->GetAppPoolConfigFile(); - auto const aspNetCoreSection = configurationSource.GetRequiredSection(CS_ASPNETCORE_SECTION); m_strArguments = aspNetCoreSection->GetString(CS_ASPNETCORE_PROCESS_ARGUMENTS).value_or(CS_ASPNETCORE_PROCESS_ARGUMENTS_DEFAULT); m_strProcessPath = aspNetCoreSection->GetRequiredString(CS_ASPNETCORE_PROCESS_EXE_PATH); diff --git a/src/Servers/IIS/AspNetCoreModuleV2/InProcessRequestHandler/InProcessOptions.h b/src/Servers/IIS/AspNetCoreModuleV2/InProcessRequestHandler/InProcessOptions.h index dcb7a56a0e1e..fa0e19e84952 100644 --- a/src/Servers/IIS/AspNetCoreModuleV2/InProcessRequestHandler/InProcessOptions.h +++ b/src/Servers/IIS/AspNetCoreModuleV2/InProcessRequestHandler/InProcessOptions.h @@ -12,30 +12,6 @@ class InProcessOptions: NonCopyable { public: - const std::wstring& - QueryAppPoolConfig() const - { - return m_appPoolConfig; - } - - const std::wstring& - QueryAppPoolId() const - { - return m_appPoolId; - } - - const std::wstring& - QuerySiteName() const - { - return m_strSiteName; - } - - const DWORD - QuerySiteId() const - { - return m_dwSiteId; - } - const std::wstring& QueryProcessPath() const { @@ -148,7 +124,7 @@ class InProcessOptions: NonCopyable return m_fSuppressRecycleOnStartupTimeout; } - InProcessOptions(const ConfigurationSource &configurationSource, IHttpServer* server, IHttpSite* pSite); + InProcessOptions(const ConfigurationSource &configurationSource, IHttpSite* pSite); static HRESULT InProcessOptions::Create( @@ -160,11 +136,8 @@ class InProcessOptions: NonCopyable private: std::wstring m_strArguments; std::wstring m_strProcessPath; - std::wstring m_strSiteName; std::wstring m_struStdoutLogFile; std::wstring m_strStackSize; - std::wstring m_appPoolId; - std::wstring m_appPoolConfig; bool m_fStdoutLogEnabled; bool m_fDisableStartUpErrorPage; bool m_fSetCurrentDirectory; @@ -173,7 +146,6 @@ class InProcessOptions: NonCopyable bool m_fBasicAuthEnabled; bool m_fAnonymousAuthEnabled; bool m_fSuppressRecycleOnStartupTimeout; - DWORD m_dwSiteId; DWORD m_dwStartupTimeLimitInMS; DWORD m_dwShutdownTimeLimitInMS; DWORD m_dwMaxRequestBodySize; diff --git a/src/Servers/IIS/AspNetCoreModuleV2/InProcessRequestHandler/managedexports.cpp b/src/Servers/IIS/AspNetCoreModuleV2/InProcessRequestHandler/managedexports.cpp index 974ad494aea9..23639860527a 100644 --- a/src/Servers/IIS/AspNetCoreModuleV2/InProcessRequestHandler/managedexports.cpp +++ b/src/Servers/IIS/AspNetCoreModuleV2/InProcessRequestHandler/managedexports.cpp @@ -222,24 +222,6 @@ http_get_completion_info( *hr = info->GetCompletionStatus(); } -// Attempts to load the IIS version if it is exported from the module. This was added in .NET 8, -// and if it is unavailable to defaults to 0 -DWORD GetIISVersion() { - auto module = GetModuleHandle(L"aspnetcorev2.dll"); - - if (module != nullptr) - { - auto func = (DWORD(_stdcall*)()) GetProcAddress(module, "GetIISVersion"); - - if (func != NULL) - { - return func(); - } - } - - return 0; -} - // // the signature should be changed. application's based address should be passed in // @@ -254,12 +236,6 @@ struct IISConfigurationData BOOL fAnonymousAuthEnable; BSTR pwzBindings; DWORD maxRequestBodySize; - BSTR pwzApplicationId; - BSTR pwzSiteName; - DWORD siteId; - BSTR pwzAppPoolId; - BSTR pwzAppPoolConfig; - DWORD iisVersion; }; EXTERN_C __declspec(dllexport) @@ -282,12 +258,6 @@ http_get_application_properties( pIISConfigurationData->fWindowsAuthEnabled = pConfiguration.QueryWindowsAuthEnabled(); pIISConfigurationData->fBasicAuthEnabled = pConfiguration.QueryBasicAuthEnabled(); pIISConfigurationData->fAnonymousAuthEnable = pConfiguration.QueryAnonymousAuthEnabled(); - pIISConfigurationData->pwzApplicationId = SysAllocString(pInProcessApplication->QueryApplicationId().c_str()); - pIISConfigurationData->siteId = pInProcessApplication->QueryConfig().QuerySiteId(); - pIISConfigurationData->pwzSiteName = SysAllocString(pInProcessApplication->QueryConfig().QuerySiteName().c_str()); - pIISConfigurationData->pwzAppPoolId = SysAllocString(pInProcessApplication->QueryConfig().QueryAppPoolId().c_str()); - pIISConfigurationData->pwzAppPoolConfig = SysAllocString(pInProcessApplication->QueryConfig().QueryAppPoolConfig().c_str()); - pIISConfigurationData->iisVersion = GetIISVersion(); auto const serverAddresses = BindingInformation::Format(pConfiguration.QueryBindings(), pInProcessApplication->QueryApplicationVirtualPath()); pIISConfigurationData->pwzBindings = SysAllocString(serverAddresses.c_str()); diff --git a/src/Servers/IIS/IIS/samples/NativeIISSample/Startup.cs b/src/Servers/IIS/IIS/samples/NativeIISSample/Startup.cs index 55cad0253118..6b81a8787e49 100644 --- a/src/Servers/IIS/IIS/samples/NativeIISSample/Startup.cs +++ b/src/Servers/IIS/IIS/samples/NativeIISSample/Startup.cs @@ -109,10 +109,10 @@ public void Configure(IApplicationBuilder app) await context.Response.WriteAsync("IIS Environment Information:" + Environment.NewLine); await context.Response.WriteAsync("IIS Version: " + envFeature.IISVersion + Environment.NewLine); await context.Response.WriteAsync("ApplicationId: " + envFeature.ApplicationId + Environment.NewLine); - await context.Response.WriteAsync("Application Path: " + envFeature.ApplicationPath + Environment.NewLine); + await context.Response.WriteAsync("Application Path: " + envFeature.ApplicationPhysicalPath + Environment.NewLine); await context.Response.WriteAsync("Application Virtual Path: " + envFeature.ApplicationVirtualPath + Environment.NewLine); - await context.Response.WriteAsync("AppPool Config: " + envFeature.AppPoolConfig + Environment.NewLine); - await context.Response.WriteAsync("AppPool ID: " + envFeature.AppPoolId + Environment.NewLine); + await context.Response.WriteAsync("Application Config Path: " + envFeature.AppConfigPath + Environment.NewLine); + await context.Response.WriteAsync("AppPool ID: " + envFeature.AppPoolName + Environment.NewLine); await context.Response.WriteAsync("Site ID: " + envFeature.SiteId + Environment.NewLine); await context.Response.WriteAsync("Site Name: " + envFeature.SiteName + Environment.NewLine); }); diff --git a/src/Servers/IIS/IIS/src/Core/EnvironmentIISDetails.cs b/src/Servers/IIS/IIS/src/Core/EnvironmentIISDetails.cs new file mode 100644 index 000000000000..fd3c2eea15c9 --- /dev/null +++ b/src/Servers/IIS/IIS/src/Core/EnvironmentIISDetails.cs @@ -0,0 +1,53 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Runtime.CompilerServices; + +namespace Microsoft.AspNetCore.Server.IIS.Core; + +internal sealed class EnvironmentIISDetails : IIISEnvironmentFeature +{ + public bool IsAvailable => IISVersion.Major != 0; + + public EnvironmentIISDetails() + { + if (Version.TryParse(Get(nameof(IISVersion)), out var version)) + { + IISVersion = version; + } + else + { + IISVersion = new Version(); + } + + if (uint.TryParse(Get(nameof(SiteId)), out var siteId)) + { + SiteId = siteId; + } + + AppPoolName = Get(nameof(AppPoolName)); + AppConfigPath = Get(nameof(AppConfigPath)); + ApplicationPhysicalPath = Get(nameof(ApplicationPhysicalPath)); + ApplicationVirtualPath = Get(nameof(ApplicationVirtualPath)); + ApplicationId = Get(nameof(ApplicationId)); + SiteName = Get(nameof(SiteName)); + } + + private static string Get([CallerMemberName] string? name = null!) => Environment.GetEnvironmentVariable($"ANCM_{name}") ?? string.Empty; + + public Version IISVersion { get; } + + public string AppPoolName { get; } + + public string AppConfigPath { get; } + + public string ApplicationPhysicalPath { get; } + + public string ApplicationVirtualPath { get; } + + public string ApplicationId { get; } + + public string SiteName { get; } + + public uint SiteId { get; } +} diff --git a/src/Servers/IIS/IIS/src/Core/IISConfigurationData.cs b/src/Servers/IIS/IIS/src/Core/IISConfigurationData.cs index f58bdbc66d39..41f3aba13f46 100644 --- a/src/Servers/IIS/IIS/src/Core/IISConfigurationData.cs +++ b/src/Servers/IIS/IIS/src/Core/IISConfigurationData.cs @@ -8,7 +8,7 @@ namespace Microsoft.AspNetCore.Server.IIS.Core; [NativeMarshalling(typeof(Marshaller))] [StructLayout(LayoutKind.Sequential)] -internal struct IISConfigurationData : IIISEnvironmentFeature +internal struct IISConfigurationData { public IntPtr pNativeApplication; public string pwzFullApplicationPath; @@ -18,28 +18,6 @@ internal struct IISConfigurationData : IIISEnvironmentFeature public bool fAnonymousAuthEnable; public string pwzBindings; public uint maxRequestBodySize; - public string pwzApplicationId; - public string pwzSiteName; - public uint siteId; - public string pwzAppPoolId; - public string pwzAppPoolConfig; - public Version version; - - Version IIISEnvironmentFeature.IISVersion => version; - - string IIISEnvironmentFeature.AppPoolId => pwzAppPoolId; - - string IIISEnvironmentFeature.AppPoolConfig => pwzAppPoolConfig; - - string IIISEnvironmentFeature.ApplicationId => pwzApplicationId; - - string IIISEnvironmentFeature.SiteName => pwzSiteName; - - uint IIISEnvironmentFeature.SiteId => siteId; - - string IIISEnvironmentFeature.ApplicationPath => pwzFullApplicationPath; - - string IIISEnvironmentFeature.ApplicationVirtualPath => pwzVirtualApplicationPath; [CustomMarshaller(typeof(IISConfigurationData), MarshalMode.Default, typeof(Marshaller))] public static class Marshaller @@ -54,12 +32,6 @@ public struct Native public int fAnonymousAuthEnable; public IntPtr pwzBindings; public uint maxRequestBodySize; - public IntPtr pwzApplicationId; - public IntPtr pwzSiteName; - public uint siteId; - public IntPtr pwzAppPoolId; - public IntPtr pwzAppPoolConfig; - public uint version; } public static Native ConvertToUnmanaged(IISConfigurationData managed) @@ -73,20 +45,9 @@ public static Native ConvertToUnmanaged(IISConfigurationData managed) native.fAnonymousAuthEnable = managed.fAnonymousAuthEnable ? 1 : 0; native.pwzBindings = managed.pwzBindings is null ? IntPtr.Zero : Marshal.StringToBSTR(managed.pwzBindings); native.maxRequestBodySize = managed.maxRequestBodySize; - native.pwzApplicationId = managed.pwzApplicationId is null ? IntPtr.Zero : Marshal.StringToBSTR(managed.pwzApplicationId); - native.pwzSiteName = managed.pwzSiteName is null ? IntPtr.Zero : Marshal.StringToBSTR(managed.pwzApplicationId); - native.siteId = managed.siteId; - native.pwzAppPoolId = managed.pwzAppPoolId is null ? IntPtr.Zero : Marshal.StringToBSTR(managed.pwzAppPoolId); - native.pwzAppPoolConfig = managed.pwzAppPoolConfig is null ? IntPtr.Zero : Marshal.StringToBSTR(managed.pwzAppPoolConfig); - native.version = ConvertFromVersion(managed.version); - return native; } - private static Version ConvertToVersion(uint dwVersion) => new((int)(dwVersion >> 16), (int)(dwVersion & 0xffff)); - - private static uint ConvertFromVersion(Version version) => ((uint)version.Major << 16) | ((uint)version.Minor); - public static void Free(Native native) { if (native.pwzFullApplicationPath != IntPtr.Zero) @@ -101,22 +62,6 @@ public static void Free(Native native) { Marshal.FreeBSTR(native.pwzBindings); } - if (native.pwzApplicationId != IntPtr.Zero) - { - Marshal.FreeBSTR(native.pwzApplicationId); - } - if (native.pwzSiteName != IntPtr.Zero) - { - Marshal.FreeBSTR(native.pwzSiteName); - } - if (native.pwzAppPoolId != IntPtr.Zero) - { - Marshal.FreeBSTR(native.pwzAppPoolId); - } - if (native.pwzAppPoolConfig != IntPtr.Zero) - { - Marshal.FreeBSTR(native.pwzAppPoolConfig); - } } public static IISConfigurationData ConvertToManaged(Native native) @@ -130,13 +75,7 @@ public static IISConfigurationData ConvertToManaged(Native native) fBasicAuthEnabled = native.fBasicAuthEnabled != 0, fAnonymousAuthEnable = native.fAnonymousAuthEnable != 0, pwzBindings = native.pwzBindings == IntPtr.Zero ? string.Empty : Marshal.PtrToStringBSTR(native.pwzBindings), - maxRequestBodySize = native.maxRequestBodySize, - pwzApplicationId = native.pwzApplicationId == IntPtr.Zero ? string.Empty : Marshal.PtrToStringBSTR(native.pwzApplicationId), - pwzSiteName = native.pwzSiteName == IntPtr.Zero ? string.Empty : Marshal.PtrToStringBSTR(native.pwzSiteName), - siteId = native.siteId, - pwzAppPoolConfig = native.pwzAppPoolConfig == IntPtr.Zero ? string.Empty : Marshal.PtrToStringBSTR(native.pwzAppPoolConfig), - pwzAppPoolId = native.pwzAppPoolId == IntPtr.Zero ? string.Empty : Marshal.PtrToStringBSTR(native.pwzAppPoolId), - version = ConvertToVersion(native.version), + maxRequestBodySize = native.maxRequestBodySize }; } } diff --git a/src/Servers/IIS/IIS/src/Core/IISHttpServer.cs b/src/Servers/IIS/IIS/src/Core/IISHttpServer.cs index ce99b8bdc86d..716829e72394 100644 --- a/src/Servers/IIS/IIS/src/Core/IISHttpServer.cs +++ b/src/Servers/IIS/IIS/src/Core/IISHttpServer.cs @@ -76,7 +76,7 @@ ILogger logger } Features.Set(_serverAddressesFeature); - Features.Set(iisConfigData); + Features.Set(new EnvironmentIISDetails()); if (_options.MaxRequestBodySize > _options.IisMaxRequestSizeLimit) { diff --git a/src/Servers/IIS/IIS/src/IIISEnvironmentFeature.cs b/src/Servers/IIS/IIS/src/IIISEnvironmentFeature.cs index c807dca6adc7..fb513b13cba6 100644 --- a/src/Servers/IIS/IIS/src/IIISEnvironmentFeature.cs +++ b/src/Servers/IIS/IIS/src/IIISEnvironmentFeature.cs @@ -16,17 +16,17 @@ public interface IIISEnvironmentFeature /// /// Gets the AppPool Id that is currently running /// - string AppPoolId { get; } + string AppPoolName { get; } /// /// Gets path to the AppPool configuration that is currently running /// - string AppPoolConfig { get; } + string AppConfigPath { get; } /// /// Gets the path of the application. /// - string ApplicationPath { get; } + string ApplicationPhysicalPath { get; } /// /// Gets the virtual path of the application. diff --git a/src/Servers/IIS/IIS/src/IISUtility.cs b/src/Servers/IIS/IIS/src/IISUtility.cs index b1afc373bab2..514825c70b53 100644 --- a/src/Servers/IIS/IIS/src/IISUtility.cs +++ b/src/Servers/IIS/IIS/src/IISUtility.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using Microsoft.AspNetCore.Hosting.Server; +using Microsoft.AspNetCore.Server.IIS.Core; namespace Microsoft.AspNetCore.Server.IIS; @@ -15,12 +16,5 @@ public static class IISUtility /// If possible, prefer to access this value. /// public static IIISEnvironmentFeature? GetEnvironmentFeature() - { - if (NativeMethods.IsAspNetCoreModuleLoaded()) - { - return NativeMethods.HttpGetApplicationProperties(); - } - - return null; - } + => new EnvironmentIISDetails() is { IsAvailable: true } details ? details : null; } diff --git a/src/Servers/IIS/IIS/src/PublicAPI.Unshipped.txt b/src/Servers/IIS/IIS/src/PublicAPI.Unshipped.txt index 123f40bd7e8b..707f07086286 100644 --- a/src/Servers/IIS/IIS/src/PublicAPI.Unshipped.txt +++ b/src/Servers/IIS/IIS/src/PublicAPI.Unshipped.txt @@ -28,13 +28,11 @@ *REMOVED*override Microsoft.AspNetCore.Server.IIS.Core.WriteOnlyStream.Seek(long offset, System.IO.SeekOrigin origin) -> long *REMOVED*override Microsoft.AspNetCore.Server.IIS.Core.WriteOnlyStream.SetLength(long value) -> void Microsoft.AspNetCore.Server.IIS.IIISEnvironmentFeature +Microsoft.AspNetCore.Server.IIS.IIISEnvironmentFeature.AppConfigPath.get -> string! Microsoft.AspNetCore.Server.IIS.IIISEnvironmentFeature.ApplicationId.get -> string! -Microsoft.AspNetCore.Server.IIS.IIISEnvironmentFeature.ApplicationPath.get -> string! +Microsoft.AspNetCore.Server.IIS.IIISEnvironmentFeature.ApplicationPhysicalPath.get -> string! Microsoft.AspNetCore.Server.IIS.IIISEnvironmentFeature.ApplicationVirtualPath.get -> string! -Microsoft.AspNetCore.Server.IIS.IIISEnvironmentFeature.AppPoolConfig.get -> string! -Microsoft.AspNetCore.Server.IIS.IIISEnvironmentFeature.AppPoolId.get -> string! +Microsoft.AspNetCore.Server.IIS.IIISEnvironmentFeature.AppPoolName.get -> string! Microsoft.AspNetCore.Server.IIS.IIISEnvironmentFeature.IISVersion.get -> System.Version! Microsoft.AspNetCore.Server.IIS.IIISEnvironmentFeature.SiteId.get -> uint -Microsoft.AspNetCore.Server.IIS.IIISEnvironmentFeature.SiteName.get -> string! -Microsoft.AspNetCore.Server.IIS.IISUtility -static Microsoft.AspNetCore.Server.IIS.IISUtility.GetEnvironmentFeature() -> Microsoft.AspNetCore.Server.IIS.IIISEnvironmentFeature? +Microsoft.AspNetCore.Server.IIS.IIISEnvironmentFeature.SiteName.get -> string! \ No newline at end of file From 0195515f8ce34e89abf85c86c0554bd1a0a1bfce Mon Sep 17 00:00:00 2001 From: Taylor Southwick Date: Thu, 17 Aug 2023 10:59:45 -0700 Subject: [PATCH 03/15] fix text --- src/Servers/IIS/IIS/src/IIISEnvironmentFeature.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Servers/IIS/IIS/src/IIISEnvironmentFeature.cs b/src/Servers/IIS/IIS/src/IIISEnvironmentFeature.cs index fb513b13cba6..27f8cf53b257 100644 --- a/src/Servers/IIS/IIS/src/IIISEnvironmentFeature.cs +++ b/src/Servers/IIS/IIS/src/IIISEnvironmentFeature.cs @@ -19,7 +19,7 @@ public interface IIISEnvironmentFeature string AppPoolName { get; } /// - /// Gets path to the AppPool configuration that is currently running + /// Gets path to the application configuration that is currently running /// string AppConfigPath { get; } From beb62dfab385908817296fa3c190392ef77f00cd Mon Sep 17 00:00:00 2001 From: Taylor Southwick Date: Thu, 17 Aug 2023 11:12:19 -0700 Subject: [PATCH 04/15] fix formatting --- .../IIS/AspNetCoreModuleV2/AspNetCore/ModuleEnvironment.cpp | 3 +-- src/Servers/IIS/IIS/src/IIISEnvironmentFeature.cs | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/ModuleEnvironment.cpp b/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/ModuleEnvironment.cpp index 2b45d936233b..45ed89498751 100644 --- a/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/ModuleEnvironment.cpp +++ b/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/ModuleEnvironment.cpp @@ -14,8 +14,7 @@ static std::wstring GetIISVersion() { return version.str(); } -static std::wstring ToVirtualPath(const std::wstring& configurationPath) -{ +static std::wstring ToVirtualPath(const std::wstring& configurationPath) { auto segments = 0; auto position = configurationPath.find('/'); // Skip first 4 segments of config path diff --git a/src/Servers/IIS/IIS/src/IIISEnvironmentFeature.cs b/src/Servers/IIS/IIS/src/IIISEnvironmentFeature.cs index 27f8cf53b257..a6d79723ef13 100644 --- a/src/Servers/IIS/IIS/src/IIISEnvironmentFeature.cs +++ b/src/Servers/IIS/IIS/src/IIISEnvironmentFeature.cs @@ -14,7 +14,7 @@ public interface IIISEnvironmentFeature Version IISVersion { get; } /// - /// Gets the AppPool Id that is currently running + /// Gets the AppPool name that is currently running /// string AppPoolName { get; } @@ -24,7 +24,7 @@ public interface IIISEnvironmentFeature string AppConfigPath { get; } /// - /// Gets the path of the application. + /// Gets the physical path of the application. /// string ApplicationPhysicalPath { get; } From 3ea689c26d92547530afb490c9223a02e723242f Mon Sep 17 00:00:00 2001 From: Taylor Southwick Date: Thu, 17 Aug 2023 11:20:46 -0700 Subject: [PATCH 05/15] move to applicationinfo.cpp --- .../IIS/AspNetCoreModuleV2/AspNetCore/ApplicationFactory.h | 3 --- .../IIS/AspNetCoreModuleV2/AspNetCore/applicationinfo.cpp | 3 +++ 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/ApplicationFactory.h b/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/ApplicationFactory.h index fa7231c06273..9906251f532f 100644 --- a/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/ApplicationFactory.h +++ b/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/ApplicationFactory.h @@ -8,7 +8,6 @@ #include #include "iapplication.h" #include "HandleWrapper.h" -#include "ModuleEnvironment.h" typedef HRESULT @@ -47,8 +46,6 @@ class ApplicationFactory } }; - SetApplicationEnvironmentVariables(pServer, pHttpContext); - return m_pfnAspNetCoreCreateApplication(pServer, pHttpContext->GetApplication(), parameters.data(), static_cast(parameters.size()), pApplication); } diff --git a/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/applicationinfo.cpp b/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/applicationinfo.cpp index cecd62a3262e..2412f49c5746 100644 --- a/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/applicationinfo.cpp +++ b/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/applicationinfo.cpp @@ -16,6 +16,7 @@ #include "ConfigurationLoadException.h" #include "resource.h" #include "file_utility.h" +#include "ModuleEnvironment.h" extern HINSTANCE g_hServerModule; extern BOOL g_fInAppOfflineShutdown; @@ -72,6 +73,8 @@ APPLICATION_INFO::CreateHandler( HRESULT APPLICATION_INFO::CreateApplication(IHttpContext& pHttpContext) { + SetApplicationEnvironmentVariables(&m_pServer, &pHttpContext); + auto& pHttpApplication = *pHttpContext.GetApplication(); if (AppOfflineApplication::ShouldBeStarted(pHttpApplication)) { From c401ec5e4a0dd4aa27071072e5bf375a4bd2efd9 Mon Sep 17 00:00:00 2001 From: Taylor Southwick Date: Thu, 17 Aug 2023 11:24:48 -0700 Subject: [PATCH 06/15] add to publicapi --- .../IIS/IIS/src/Core/EnvironmentIISDetails.cs | 12 +++++------- src/Servers/IIS/IIS/src/Core/IISHttpServer.cs | 6 +++++- src/Servers/IIS/IIS/src/IISUtility.cs | 3 +-- src/Servers/IIS/IIS/src/PublicAPI.Unshipped.txt | 4 +++- 4 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src/Servers/IIS/IIS/src/Core/EnvironmentIISDetails.cs b/src/Servers/IIS/IIS/src/Core/EnvironmentIISDetails.cs index fd3c2eea15c9..185c358ff9b8 100644 --- a/src/Servers/IIS/IIS/src/Core/EnvironmentIISDetails.cs +++ b/src/Servers/IIS/IIS/src/Core/EnvironmentIISDetails.cs @@ -7,18 +7,16 @@ namespace Microsoft.AspNetCore.Server.IIS.Core; internal sealed class EnvironmentIISDetails : IIISEnvironmentFeature { - public bool IsAvailable => IISVersion.Major != 0; + public static IIISEnvironmentFeature? Create() => new EnvironmentIISDetails() is { IsAvailable: true } feature ? feature : null; - public EnvironmentIISDetails() + private bool IsAvailable => IISVersion is not null; + + private EnvironmentIISDetails() { if (Version.TryParse(Get(nameof(IISVersion)), out var version)) { IISVersion = version; } - else - { - IISVersion = new Version(); - } if (uint.TryParse(Get(nameof(SiteId)), out var siteId)) { @@ -35,7 +33,7 @@ public EnvironmentIISDetails() private static string Get([CallerMemberName] string? name = null!) => Environment.GetEnvironmentVariable($"ANCM_{name}") ?? string.Empty; - public Version IISVersion { get; } + public Version IISVersion { get; } = null!; public string AppPoolName { get; } diff --git a/src/Servers/IIS/IIS/src/Core/IISHttpServer.cs b/src/Servers/IIS/IIS/src/Core/IISHttpServer.cs index 716829e72394..a8afe5e8f442 100644 --- a/src/Servers/IIS/IIS/src/Core/IISHttpServer.cs +++ b/src/Servers/IIS/IIS/src/Core/IISHttpServer.cs @@ -76,7 +76,11 @@ ILogger logger } Features.Set(_serverAddressesFeature); - Features.Set(new EnvironmentIISDetails()); + + if (EnvironmentIISDetails.Create() is { } iisEnvFeature) + { + Features.Set(iisEnvFeature); + } if (_options.MaxRequestBodySize > _options.IisMaxRequestSizeLimit) { diff --git a/src/Servers/IIS/IIS/src/IISUtility.cs b/src/Servers/IIS/IIS/src/IISUtility.cs index 514825c70b53..dd5bf76b839d 100644 --- a/src/Servers/IIS/IIS/src/IISUtility.cs +++ b/src/Servers/IIS/IIS/src/IISUtility.cs @@ -15,6 +15,5 @@ public static class IISUtility /// Gets the for the current application if available. /// If possible, prefer to access this value. /// - public static IIISEnvironmentFeature? GetEnvironmentFeature() - => new EnvironmentIISDetails() is { IsAvailable: true } details ? details : null; + public static IIISEnvironmentFeature? GetEnvironmentFeature() => EnvironmentIISDetails.Create(); } diff --git a/src/Servers/IIS/IIS/src/PublicAPI.Unshipped.txt b/src/Servers/IIS/IIS/src/PublicAPI.Unshipped.txt index 707f07086286..b3998c870346 100644 --- a/src/Servers/IIS/IIS/src/PublicAPI.Unshipped.txt +++ b/src/Servers/IIS/IIS/src/PublicAPI.Unshipped.txt @@ -35,4 +35,6 @@ Microsoft.AspNetCore.Server.IIS.IIISEnvironmentFeature.ApplicationVirtualPath.ge Microsoft.AspNetCore.Server.IIS.IIISEnvironmentFeature.AppPoolName.get -> string! Microsoft.AspNetCore.Server.IIS.IIISEnvironmentFeature.IISVersion.get -> System.Version! Microsoft.AspNetCore.Server.IIS.IIISEnvironmentFeature.SiteId.get -> uint -Microsoft.AspNetCore.Server.IIS.IIISEnvironmentFeature.SiteName.get -> string! \ No newline at end of file +Microsoft.AspNetCore.Server.IIS.IIISEnvironmentFeature.SiteName.get -> string! +Microsoft.AspNetCore.Server.IIS.IISUtility +static Microsoft.AspNetCore.Server.IIS.IISUtility.GetEnvironmentFeature() -> Microsoft.AspNetCore.Server.IIS.IIISEnvironmentFeature? \ No newline at end of file From 2a69e13a5d95842bfc9a7e9464030a10305e94f4 Mon Sep 17 00:00:00 2001 From: Taylor Southwick Date: Thu, 17 Aug 2023 13:50:05 -0700 Subject: [PATCH 07/15] add app pool config path --- .../IIS/AspNetCoreModuleV2/AspNetCore/ModuleEnvironment.cpp | 1 + src/Servers/IIS/IIS/samples/NativeIISSample/Startup.cs | 1 + src/Servers/IIS/IIS/src/Core/EnvironmentIISDetails.cs | 3 +++ src/Servers/IIS/IIS/src/IIISEnvironmentFeature.cs | 5 +++++ src/Servers/IIS/IIS/src/PublicAPI.Unshipped.txt | 1 + 5 files changed, 11 insertions(+) diff --git a/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/ModuleEnvironment.cpp b/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/ModuleEnvironment.cpp index 45ed89498751..ba4d05c22ea1 100644 --- a/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/ModuleEnvironment.cpp +++ b/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/ModuleEnvironment.cpp @@ -35,6 +35,7 @@ static std::wstring ToVirtualPath(const std::wstring& configurationPath) { void SetApplicationEnvironmentVariables(_In_ IHttpServer* pServer, _In_ IHttpContext* pHttpContext) { SetEnvironmentVariable(L"ANCM_IISVersion", GetIISVersion().c_str()); SetEnvironmentVariable(L"ANCM_AppPoolName", pServer->GetAppPoolName()); + SetEnvironmentVariable(L"ANCM_AppPoolConfigFile", ((IHttpServer2*)pServer)->GetAppPoolConfigFile()); auto site = pHttpContext->GetSite(); SetEnvironmentVariable(L"ANCM_SiteName", site->GetSiteName()); diff --git a/src/Servers/IIS/IIS/samples/NativeIISSample/Startup.cs b/src/Servers/IIS/IIS/samples/NativeIISSample/Startup.cs index 6b81a8787e49..8557c020ca89 100644 --- a/src/Servers/IIS/IIS/samples/NativeIISSample/Startup.cs +++ b/src/Servers/IIS/IIS/samples/NativeIISSample/Startup.cs @@ -113,6 +113,7 @@ public void Configure(IApplicationBuilder app) await context.Response.WriteAsync("Application Virtual Path: " + envFeature.ApplicationVirtualPath + Environment.NewLine); await context.Response.WriteAsync("Application Config Path: " + envFeature.AppConfigPath + Environment.NewLine); await context.Response.WriteAsync("AppPool ID: " + envFeature.AppPoolName + Environment.NewLine); + await context.Response.WriteAsync("AppPool Config File: " + envFeature.AppPoolConfigFile + Environment.NewLine); await context.Response.WriteAsync("Site ID: " + envFeature.SiteId + Environment.NewLine); await context.Response.WriteAsync("Site Name: " + envFeature.SiteName + Environment.NewLine); }); diff --git a/src/Servers/IIS/IIS/src/Core/EnvironmentIISDetails.cs b/src/Servers/IIS/IIS/src/Core/EnvironmentIISDetails.cs index 185c358ff9b8..27a6435f8596 100644 --- a/src/Servers/IIS/IIS/src/Core/EnvironmentIISDetails.cs +++ b/src/Servers/IIS/IIS/src/Core/EnvironmentIISDetails.cs @@ -24,6 +24,7 @@ private EnvironmentIISDetails() } AppPoolName = Get(nameof(AppPoolName)); + AppPoolConfigFile = Get(nameof(AppPoolConfigFile)); AppConfigPath = Get(nameof(AppConfigPath)); ApplicationPhysicalPath = Get(nameof(ApplicationPhysicalPath)); ApplicationVirtualPath = Get(nameof(ApplicationVirtualPath)); @@ -37,6 +38,8 @@ private EnvironmentIISDetails() public string AppPoolName { get; } + public string AppPoolConfigFile { get; } + public string AppConfigPath { get; } public string ApplicationPhysicalPath { get; } diff --git a/src/Servers/IIS/IIS/src/IIISEnvironmentFeature.cs b/src/Servers/IIS/IIS/src/IIISEnvironmentFeature.cs index a6d79723ef13..5f4a3f685f7d 100644 --- a/src/Servers/IIS/IIS/src/IIISEnvironmentFeature.cs +++ b/src/Servers/IIS/IIS/src/IIISEnvironmentFeature.cs @@ -18,6 +18,11 @@ public interface IIISEnvironmentFeature /// string AppPoolName { get; } + /// + /// Gets the path to the AppPool config + /// + string AppPoolConfigFile { get; } + /// /// Gets path to the application configuration that is currently running /// diff --git a/src/Servers/IIS/IIS/src/PublicAPI.Unshipped.txt b/src/Servers/IIS/IIS/src/PublicAPI.Unshipped.txt index b3998c870346..9a3f7baad447 100644 --- a/src/Servers/IIS/IIS/src/PublicAPI.Unshipped.txt +++ b/src/Servers/IIS/IIS/src/PublicAPI.Unshipped.txt @@ -32,6 +32,7 @@ Microsoft.AspNetCore.Server.IIS.IIISEnvironmentFeature.AppConfigPath.get -> stri Microsoft.AspNetCore.Server.IIS.IIISEnvironmentFeature.ApplicationId.get -> string! Microsoft.AspNetCore.Server.IIS.IIISEnvironmentFeature.ApplicationPhysicalPath.get -> string! Microsoft.AspNetCore.Server.IIS.IIISEnvironmentFeature.ApplicationVirtualPath.get -> string! +Microsoft.AspNetCore.Server.IIS.IIISEnvironmentFeature.AppPoolConfigFile.get -> string! Microsoft.AspNetCore.Server.IIS.IIISEnvironmentFeature.AppPoolName.get -> string! Microsoft.AspNetCore.Server.IIS.IIISEnvironmentFeature.IISVersion.get -> System.Version! Microsoft.AspNetCore.Server.IIS.IIISEnvironmentFeature.SiteId.get -> uint From 1d20bf37b8e59117277389452f745aab3ea7aecb Mon Sep 17 00:00:00 2001 From: Taylor Southwick Date: Thu, 17 Aug 2023 16:10:21 -0700 Subject: [PATCH 08/15] react to api feedback --- .../AspNetCore/ModuleEnvironment.cpp | 18 +++++------- .../AspNetCore/ModuleEnvironment.h | 2 +- .../AspNetCore/applicationinfo.cpp | 2 +- .../IIS/samples/NativeIISSample/Startup.cs | 2 +- .../IIS/IIS/src/Core/EnvironmentIISDetails.cs | 29 +++++++++---------- src/Servers/IIS/IIS/src/Core/IISHttpServer.cs | 2 +- .../IIS/IIS/src/IIISEnvironmentFeature.cs | 2 +- src/Servers/IIS/IIS/src/IISUtility.cs | 19 ------------ .../IIS/IIS/src/PublicAPI.Unshipped.txt | 4 +-- 9 files changed, 28 insertions(+), 52 deletions(-) delete mode 100644 src/Servers/IIS/IIS/src/IISUtility.cs diff --git a/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/ModuleEnvironment.cpp b/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/ModuleEnvironment.cpp index ba4d05c22ea1..b5081dcc87e8 100644 --- a/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/ModuleEnvironment.cpp +++ b/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/ModuleEnvironment.cpp @@ -32,18 +32,16 @@ static std::wstring ToVirtualPath(const std::wstring& configurationPath) { return L"/"; } -void SetApplicationEnvironmentVariables(_In_ IHttpServer* pServer, _In_ IHttpContext* pHttpContext) { - SetEnvironmentVariable(L"ANCM_IISVersion", GetIISVersion().c_str()); - SetEnvironmentVariable(L"ANCM_AppPoolName", pServer->GetAppPoolName()); - SetEnvironmentVariable(L"ANCM_AppPoolConfigFile", ((IHttpServer2*)pServer)->GetAppPoolConfigFile()); +void SetApplicationEnvironmentVariables(_In_ IHttpContext* pHttpContext) { + SetEnvironmentVariable(L"ANCM_IIS_VERSION", GetIISVersion().c_str()); auto site = pHttpContext->GetSite(); - SetEnvironmentVariable(L"ANCM_SiteName", site->GetSiteName()); - SetEnvironmentVariable(L"ANCM_SiteId", std::to_wstring(site->GetSiteId()).c_str()); + SetEnvironmentVariable(L"ANCM_SITE_NAME", site->GetSiteName()); + SetEnvironmentVariable(L"ANCM_SITE_ID", std::to_wstring(site->GetSiteId()).c_str()); auto app = pHttpContext->GetApplication(); - SetEnvironmentVariable(L"ANCM_AppConfigPath", app->GetAppConfigPath()); - SetEnvironmentVariable(L"ANCM_ApplicationId", app->GetApplicationId()); - SetEnvironmentVariable(L"ANCM_ApplicationPhysicalPath", app->GetApplicationPhysicalPath()); - SetEnvironmentVariable(L"ANCM_ApplicationVirtualPath", ToVirtualPath(app->GetAppConfigPath()).c_str()); + SetEnvironmentVariable(L"ANCM_APP_CONFIG_PATH", app->GetAppConfigPath()); + SetEnvironmentVariable(L"ANCM_APPLICATION_ID", app->GetApplicationId()); + SetEnvironmentVariable(L"ANCM_APPLICATION_PHYSICAL_PATH", app->GetApplicationPhysicalPath()); + SetEnvironmentVariable(L"ANCM_APPPLICATION_VIRTUAL_PATH", ToVirtualPath(app->GetAppConfigPath()).c_str()); } diff --git a/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/ModuleEnvironment.h b/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/ModuleEnvironment.h index 557ba4a76b25..5966a414de3b 100644 --- a/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/ModuleEnvironment.h +++ b/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/ModuleEnvironment.h @@ -1,3 +1,3 @@ #pragma once -void SetApplicationEnvironmentVariables(_In_ IHttpServer* pServer, _In_ IHttpContext* pHttpContext); +void SetApplicationEnvironmentVariables(_In_ IHttpContext* pHttpContext); diff --git a/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/applicationinfo.cpp b/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/applicationinfo.cpp index 2412f49c5746..959370a64c4f 100644 --- a/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/applicationinfo.cpp +++ b/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/applicationinfo.cpp @@ -73,7 +73,7 @@ APPLICATION_INFO::CreateHandler( HRESULT APPLICATION_INFO::CreateApplication(IHttpContext& pHttpContext) { - SetApplicationEnvironmentVariables(&m_pServer, &pHttpContext); + SetApplicationEnvironmentVariables(&pHttpContext); auto& pHttpApplication = *pHttpContext.GetApplication(); if (AppOfflineApplication::ShouldBeStarted(pHttpApplication)) diff --git a/src/Servers/IIS/IIS/samples/NativeIISSample/Startup.cs b/src/Servers/IIS/IIS/samples/NativeIISSample/Startup.cs index 8557c020ca89..b1bfe39a2701 100644 --- a/src/Servers/IIS/IIS/samples/NativeIISSample/Startup.cs +++ b/src/Servers/IIS/IIS/samples/NativeIISSample/Startup.cs @@ -112,7 +112,7 @@ public void Configure(IApplicationBuilder app) await context.Response.WriteAsync("Application Path: " + envFeature.ApplicationPhysicalPath + Environment.NewLine); await context.Response.WriteAsync("Application Virtual Path: " + envFeature.ApplicationVirtualPath + Environment.NewLine); await context.Response.WriteAsync("Application Config Path: " + envFeature.AppConfigPath + Environment.NewLine); - await context.Response.WriteAsync("AppPool ID: " + envFeature.AppPoolName + Environment.NewLine); + await context.Response.WriteAsync("AppPool ID: " + envFeature.AppPoolId + Environment.NewLine); await context.Response.WriteAsync("AppPool Config File: " + envFeature.AppPoolConfigFile + Environment.NewLine); await context.Response.WriteAsync("Site ID: " + envFeature.SiteId + Environment.NewLine); await context.Response.WriteAsync("Site Name: " + envFeature.SiteName + Environment.NewLine); diff --git a/src/Servers/IIS/IIS/src/Core/EnvironmentIISDetails.cs b/src/Servers/IIS/IIS/src/Core/EnvironmentIISDetails.cs index 27a6435f8596..cf190459d4ca 100644 --- a/src/Servers/IIS/IIS/src/Core/EnvironmentIISDetails.cs +++ b/src/Servers/IIS/IIS/src/Core/EnvironmentIISDetails.cs @@ -2,41 +2,40 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Runtime.CompilerServices; +using Microsoft.Extensions.Configuration; namespace Microsoft.AspNetCore.Server.IIS.Core; internal sealed class EnvironmentIISDetails : IIISEnvironmentFeature { - public static IIISEnvironmentFeature? Create() => new EnvironmentIISDetails() is { IsAvailable: true } feature ? feature : null; + public bool IsAvailable => IISVersion is not null; - private bool IsAvailable => IISVersion is not null; - - private EnvironmentIISDetails() + public EnvironmentIISDetails() { - if (Version.TryParse(Get(nameof(IISVersion)), out var version)) + if (Version.TryParse(Get("ANCM_IIS_VERSION"), out var version)) { IISVersion = version; } - if (uint.TryParse(Get(nameof(SiteId)), out var siteId)) + if (uint.TryParse(Get("ANCM_SITE_ID"), out var siteId)) { SiteId = siteId; } - AppPoolName = Get(nameof(AppPoolName)); - AppPoolConfigFile = Get(nameof(AppPoolConfigFile)); - AppConfigPath = Get(nameof(AppConfigPath)); - ApplicationPhysicalPath = Get(nameof(ApplicationPhysicalPath)); - ApplicationVirtualPath = Get(nameof(ApplicationVirtualPath)); - ApplicationId = Get(nameof(ApplicationId)); - SiteName = Get(nameof(SiteName)); + AppPoolId = Get("APP_POOL_ID"); + AppPoolConfigFile = Get("APP_POOL_CONFIG"); + AppConfigPath = Get("ANCM_APP_CONFIG_PATH"); + ApplicationPhysicalPath = Get("ANCM_APPLICATION_PHYSICAL_PATH"); + ApplicationVirtualPath = Get("ANCM_APPLICATION_VIRTUAL_PATH"); + ApplicationId = Get("ANCM_APPLICATION_VIRTUAL_PATH"); + SiteName = Get("ANCM_SITE_NAME"); } - private static string Get([CallerMemberName] string? name = null!) => Environment.GetEnvironmentVariable($"ANCM_{name}") ?? string.Empty; + private static string Get(string name) => Environment.GetEnvironmentVariable(name) ?? string.Empty; public Version IISVersion { get; } = null!; - public string AppPoolName { get; } + public string AppPoolId { get; } public string AppPoolConfigFile { get; } diff --git a/src/Servers/IIS/IIS/src/Core/IISHttpServer.cs b/src/Servers/IIS/IIS/src/Core/IISHttpServer.cs index a8afe5e8f442..42a36e85b7ca 100644 --- a/src/Servers/IIS/IIS/src/Core/IISHttpServer.cs +++ b/src/Servers/IIS/IIS/src/Core/IISHttpServer.cs @@ -77,7 +77,7 @@ ILogger logger Features.Set(_serverAddressesFeature); - if (EnvironmentIISDetails.Create() is { } iisEnvFeature) + if (new EnvironmentIISDetails() is { IsAvailable: true } iisEnvFeature) { Features.Set(iisEnvFeature); } diff --git a/src/Servers/IIS/IIS/src/IIISEnvironmentFeature.cs b/src/Servers/IIS/IIS/src/IIISEnvironmentFeature.cs index 5f4a3f685f7d..3ff93153c971 100644 --- a/src/Servers/IIS/IIS/src/IIISEnvironmentFeature.cs +++ b/src/Servers/IIS/IIS/src/IIISEnvironmentFeature.cs @@ -16,7 +16,7 @@ public interface IIISEnvironmentFeature /// /// Gets the AppPool name that is currently running /// - string AppPoolName { get; } + string AppPoolId { get; } /// /// Gets the path to the AppPool config diff --git a/src/Servers/IIS/IIS/src/IISUtility.cs b/src/Servers/IIS/IIS/src/IISUtility.cs deleted file mode 100644 index dd5bf76b839d..000000000000 --- a/src/Servers/IIS/IIS/src/IISUtility.cs +++ /dev/null @@ -1,19 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using Microsoft.AspNetCore.Hosting.Server; -using Microsoft.AspNetCore.Server.IIS.Core; - -namespace Microsoft.AspNetCore.Server.IIS; - -/// -/// Utility to access IIS details. -/// -public static class IISUtility -{ - /// - /// Gets the for the current application if available. - /// If possible, prefer to access this value. - /// - public static IIISEnvironmentFeature? GetEnvironmentFeature() => EnvironmentIISDetails.Create(); -} diff --git a/src/Servers/IIS/IIS/src/PublicAPI.Unshipped.txt b/src/Servers/IIS/IIS/src/PublicAPI.Unshipped.txt index 9a3f7baad447..76ef88049f41 100644 --- a/src/Servers/IIS/IIS/src/PublicAPI.Unshipped.txt +++ b/src/Servers/IIS/IIS/src/PublicAPI.Unshipped.txt @@ -33,9 +33,7 @@ Microsoft.AspNetCore.Server.IIS.IIISEnvironmentFeature.ApplicationId.get -> stri Microsoft.AspNetCore.Server.IIS.IIISEnvironmentFeature.ApplicationPhysicalPath.get -> string! Microsoft.AspNetCore.Server.IIS.IIISEnvironmentFeature.ApplicationVirtualPath.get -> string! Microsoft.AspNetCore.Server.IIS.IIISEnvironmentFeature.AppPoolConfigFile.get -> string! -Microsoft.AspNetCore.Server.IIS.IIISEnvironmentFeature.AppPoolName.get -> string! +Microsoft.AspNetCore.Server.IIS.IIISEnvironmentFeature.AppPoolId.get -> string! Microsoft.AspNetCore.Server.IIS.IIISEnvironmentFeature.IISVersion.get -> System.Version! Microsoft.AspNetCore.Server.IIS.IIISEnvironmentFeature.SiteId.get -> uint Microsoft.AspNetCore.Server.IIS.IIISEnvironmentFeature.SiteName.get -> string! -Microsoft.AspNetCore.Server.IIS.IISUtility -static Microsoft.AspNetCore.Server.IIS.IISUtility.GetEnvironmentFeature() -> Microsoft.AspNetCore.Server.IIS.IIISEnvironmentFeature? \ No newline at end of file From 8dd3702e70334af0f2ae288862eaffb8e4fc4cff Mon Sep 17 00:00:00 2001 From: Taylor Southwick Date: Thu, 17 Aug 2023 16:58:39 -0700 Subject: [PATCH 09/15] use ASPNETCORE_ prefix --- .../AspNetCore/ModuleEnvironment.cpp | 26 ++++---- .../AspNetCore/ModuleEnvironment.h | 2 +- .../AspNetCore/applicationinfo.cpp | 2 +- .../IIS/samples/NativeIISSample/Startup.cs | 30 +++++---- .../IIS/IIS/src/Core/EnvironmentIISDetails.cs | 53 ---------------- .../IIS/IIS/src/Core/IISEnvironmentFeature.cs | 63 +++++++++++++++++++ src/Servers/IIS/IIS/src/Core/IISHttpServer.cs | 4 +- 7 files changed, 100 insertions(+), 80 deletions(-) delete mode 100644 src/Servers/IIS/IIS/src/Core/EnvironmentIISDetails.cs create mode 100644 src/Servers/IIS/IIS/src/Core/IISEnvironmentFeature.cs diff --git a/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/ModuleEnvironment.cpp b/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/ModuleEnvironment.cpp index b5081dcc87e8..7290656088b0 100644 --- a/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/ModuleEnvironment.cpp +++ b/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/ModuleEnvironment.cpp @@ -32,16 +32,18 @@ static std::wstring ToVirtualPath(const std::wstring& configurationPath) { return L"/"; } -void SetApplicationEnvironmentVariables(_In_ IHttpContext* pHttpContext) { - SetEnvironmentVariable(L"ANCM_IIS_VERSION", GetIISVersion().c_str()); - - auto site = pHttpContext->GetSite(); - SetEnvironmentVariable(L"ANCM_SITE_NAME", site->GetSiteName()); - SetEnvironmentVariable(L"ANCM_SITE_ID", std::to_wstring(site->GetSiteId()).c_str()); - - auto app = pHttpContext->GetApplication(); - SetEnvironmentVariable(L"ANCM_APP_CONFIG_PATH", app->GetAppConfigPath()); - SetEnvironmentVariable(L"ANCM_APPLICATION_ID", app->GetApplicationId()); - SetEnvironmentVariable(L"ANCM_APPLICATION_PHYSICAL_PATH", app->GetApplicationPhysicalPath()); - SetEnvironmentVariable(L"ANCM_APPPLICATION_VIRTUAL_PATH", ToVirtualPath(app->GetAppConfigPath()).c_str()); +void SetApplicationEnvironmentVariables(_In_ IHttpServer &server, _In_ IHttpContext &pHttpContext) { + SetEnvironmentVariable(L"ASPNETCORE_IIS_VERSION", GetIISVersion().c_str()); + + SetEnvironmentVariable(L"ASPNETCORE_IIS_APP_POOL_ID", server.GetAppPoolName()); + SetEnvironmentVariable(L"ASPNETCORE_IIS_APP_POOL_CONFIG_FILE", ((IHttpServer2&)server).GetAppPoolConfigFile()); + + auto site = pHttpContext.GetSite(); + SetEnvironmentVariable(L"ASPNETCORE_IIS_SITE_NAME", site->GetSiteName()); + SetEnvironmentVariable(L"ASPNETCORE_IIS_SITE_ID", std::to_wstring(site->GetSiteId()).c_str()); + + auto app = pHttpContext.GetApplication(); + SetEnvironmentVariable(L"ASPNETCORE_IIS_APP_CONFIG_PATH", app->GetAppConfigPath()); + SetEnvironmentVariable(L"ASPNETCORE_IIS_APPLICATION_ID", app->GetApplicationId()); + SetEnvironmentVariable(L"ASPNETCORE_IIS_APPLICATION_VIRTUAL_PATH", ToVirtualPath(app->GetAppConfigPath()).c_str()); } diff --git a/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/ModuleEnvironment.h b/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/ModuleEnvironment.h index 5966a414de3b..72f74f5e6c9d 100644 --- a/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/ModuleEnvironment.h +++ b/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/ModuleEnvironment.h @@ -1,3 +1,3 @@ #pragma once -void SetApplicationEnvironmentVariables(_In_ IHttpContext* pHttpContext); +void SetApplicationEnvironmentVariables(_In_ IHttpServer& server, _In_ IHttpContext& pHttpContext); diff --git a/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/applicationinfo.cpp b/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/applicationinfo.cpp index 959370a64c4f..519a36da628e 100644 --- a/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/applicationinfo.cpp +++ b/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/applicationinfo.cpp @@ -73,7 +73,7 @@ APPLICATION_INFO::CreateHandler( HRESULT APPLICATION_INFO::CreateApplication(IHttpContext& pHttpContext) { - SetApplicationEnvironmentVariables(&pHttpContext); + SetApplicationEnvironmentVariables(m_pServer, pHttpContext); auto& pHttpApplication = *pHttpContext.GetApplication(); if (AppOfflineApplication::ShouldBeStarted(pHttpApplication)) diff --git a/src/Servers/IIS/IIS/samples/NativeIISSample/Startup.cs b/src/Servers/IIS/IIS/samples/NativeIISSample/Startup.cs index b1bfe39a2701..0ff3b86369c6 100644 --- a/src/Servers/IIS/IIS/samples/NativeIISSample/Startup.cs +++ b/src/Servers/IIS/IIS/samples/NativeIISSample/Startup.cs @@ -104,18 +104,24 @@ public void Configure(IApplicationBuilder app) await context.Response.WriteAsync(key + Environment.NewLine); } - var envFeature = server.Features.Get(); - await context.Response.WriteAsync(Environment.NewLine); - await context.Response.WriteAsync("IIS Environment Information:" + Environment.NewLine); - await context.Response.WriteAsync("IIS Version: " + envFeature.IISVersion + Environment.NewLine); - await context.Response.WriteAsync("ApplicationId: " + envFeature.ApplicationId + Environment.NewLine); - await context.Response.WriteAsync("Application Path: " + envFeature.ApplicationPhysicalPath + Environment.NewLine); - await context.Response.WriteAsync("Application Virtual Path: " + envFeature.ApplicationVirtualPath + Environment.NewLine); - await context.Response.WriteAsync("Application Config Path: " + envFeature.AppConfigPath + Environment.NewLine); - await context.Response.WriteAsync("AppPool ID: " + envFeature.AppPoolId + Environment.NewLine); - await context.Response.WriteAsync("AppPool Config File: " + envFeature.AppPoolConfigFile + Environment.NewLine); - await context.Response.WriteAsync("Site ID: " + envFeature.SiteId + Environment.NewLine); - await context.Response.WriteAsync("Site Name: " + envFeature.SiteName + Environment.NewLine); + if (server.Features.Get() is { } envFeature) + { + await context.Response.WriteAsync(Environment.NewLine); + await context.Response.WriteAsync("IIS Environment Information:" + Environment.NewLine); + await context.Response.WriteAsync("IIS Version: " + envFeature.IISVersion + Environment.NewLine); + await context.Response.WriteAsync("ApplicationId: " + envFeature.ApplicationId + Environment.NewLine); + await context.Response.WriteAsync("Application Path: " + envFeature.ApplicationPhysicalPath + Environment.NewLine); + await context.Response.WriteAsync("Application Virtual Path: " + envFeature.ApplicationVirtualPath + Environment.NewLine); + await context.Response.WriteAsync("Application Config Path: " + envFeature.AppConfigPath + Environment.NewLine); + await context.Response.WriteAsync("AppPool ID: " + envFeature.AppPoolId + Environment.NewLine); + await context.Response.WriteAsync("AppPool Config File: " + envFeature.AppPoolConfigFile + Environment.NewLine); + await context.Response.WriteAsync("Site ID: " + envFeature.SiteId + Environment.NewLine); + await context.Response.WriteAsync("Site Name: " + envFeature.SiteName + Environment.NewLine); + } + else + { + await context.Response.WriteAsync($"No {nameof(IIISEnvironmentFeature)} available." + Environment.NewLine); + } }); } diff --git a/src/Servers/IIS/IIS/src/Core/EnvironmentIISDetails.cs b/src/Servers/IIS/IIS/src/Core/EnvironmentIISDetails.cs deleted file mode 100644 index cf190459d4ca..000000000000 --- a/src/Servers/IIS/IIS/src/Core/EnvironmentIISDetails.cs +++ /dev/null @@ -1,53 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Runtime.CompilerServices; -using Microsoft.Extensions.Configuration; - -namespace Microsoft.AspNetCore.Server.IIS.Core; - -internal sealed class EnvironmentIISDetails : IIISEnvironmentFeature -{ - public bool IsAvailable => IISVersion is not null; - - public EnvironmentIISDetails() - { - if (Version.TryParse(Get("ANCM_IIS_VERSION"), out var version)) - { - IISVersion = version; - } - - if (uint.TryParse(Get("ANCM_SITE_ID"), out var siteId)) - { - SiteId = siteId; - } - - AppPoolId = Get("APP_POOL_ID"); - AppPoolConfigFile = Get("APP_POOL_CONFIG"); - AppConfigPath = Get("ANCM_APP_CONFIG_PATH"); - ApplicationPhysicalPath = Get("ANCM_APPLICATION_PHYSICAL_PATH"); - ApplicationVirtualPath = Get("ANCM_APPLICATION_VIRTUAL_PATH"); - ApplicationId = Get("ANCM_APPLICATION_VIRTUAL_PATH"); - SiteName = Get("ANCM_SITE_NAME"); - } - - private static string Get(string name) => Environment.GetEnvironmentVariable(name) ?? string.Empty; - - public Version IISVersion { get; } = null!; - - public string AppPoolId { get; } - - public string AppPoolConfigFile { get; } - - public string AppConfigPath { get; } - - public string ApplicationPhysicalPath { get; } - - public string ApplicationVirtualPath { get; } - - public string ApplicationId { get; } - - public string SiteName { get; } - - public uint SiteId { get; } -} diff --git a/src/Servers/IIS/IIS/src/Core/IISEnvironmentFeature.cs b/src/Servers/IIS/IIS/src/Core/IISEnvironmentFeature.cs new file mode 100644 index 000000000000..597237f08719 --- /dev/null +++ b/src/Servers/IIS/IIS/src/Core/IISEnvironmentFeature.cs @@ -0,0 +1,63 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Diagnostics.CodeAnalysis; +using Microsoft.Extensions.Configuration; + +namespace Microsoft.AspNetCore.Server.IIS.Core; + +internal sealed class IISEnvironmentFeature : IIISEnvironmentFeature +{ + public static bool TryCreate(IConfiguration configuration, [MaybeNullWhen(false)] out IIISEnvironmentFeature result) + { + var feature = new IISEnvironmentFeature(configuration); + + if (feature.IISVersion is not null) + { + result = feature; + return true; + } + + result = null; + return false; + } + + private IISEnvironmentFeature(IConfiguration configuration) + { + if (Version.TryParse(configuration["IIS_VERSION"], out var version)) + { + IISVersion = version; + } + + if (uint.TryParse(configuration["IIS_SITE_ID"], out var siteId)) + { + SiteId = siteId; + } + + AppPoolId = configuration["IIS_APP_POOL_ID"] ?? string.Empty; + AppPoolConfigFile = configuration["IIS_APP_POOL_CONFIG_FILE"] ?? string.Empty; + AppConfigPath = configuration["IIS_APP_CONFIG_PATH"] ?? string.Empty; + ApplicationPhysicalPath = configuration["IIS_PHYSICAL_PATH"] ?? string.Empty; + ApplicationVirtualPath = configuration["IIS_APPLICATION_VIRTUAL_PATH"] ?? string.Empty; + ApplicationId = configuration["IIS_APPLICATION_ID"] ?? string.Empty; + SiteName = configuration["IIS_SITE_NAME"] ?? string.Empty; + } + + public Version IISVersion { get; } = null!; + + public string AppPoolId { get; } + + public string AppPoolConfigFile { get; } + + public string AppConfigPath { get; } + + public string ApplicationPhysicalPath { get; } + + public string ApplicationVirtualPath { get; } + + public string ApplicationId { get; } + + public string SiteName { get; } + + public uint SiteId { get; } +} diff --git a/src/Servers/IIS/IIS/src/Core/IISHttpServer.cs b/src/Servers/IIS/IIS/src/Core/IISHttpServer.cs index 42a36e85b7ca..3390478626a5 100644 --- a/src/Servers/IIS/IIS/src/Core/IISHttpServer.cs +++ b/src/Servers/IIS/IIS/src/Core/IISHttpServer.cs @@ -9,6 +9,7 @@ using Microsoft.AspNetCore.Hosting.Server; using Microsoft.AspNetCore.Hosting.Server.Features; using Microsoft.AspNetCore.Http.Features; +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; @@ -58,6 +59,7 @@ public IISHttpServer( IISNativeApplication nativeApplication, IHostApplicationLifetime applicationLifetime, IAuthenticationSchemeProvider authentication, + IConfiguration configuration, IOptions options, ILogger logger ) @@ -77,7 +79,7 @@ ILogger logger Features.Set(_serverAddressesFeature); - if (new EnvironmentIISDetails() is { IsAvailable: true } iisEnvFeature) + if (IISEnvironmentFeature.TryCreate(configuration, out var iisEnvFeature)) { Features.Set(iisEnvFeature); } From 68325c93caa61a5adfc2ce6bfe5d34c5d686440d Mon Sep 17 00:00:00 2001 From: Taylor Southwick Date: Sun, 27 Aug 2023 12:33:55 -0700 Subject: [PATCH 10/15] Update src/Servers/IIS/IIS/src/Core/IISEnvironmentFeature.cs Co-authored-by: Brennan --- src/Servers/IIS/IIS/src/Core/IISEnvironmentFeature.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Servers/IIS/IIS/src/Core/IISEnvironmentFeature.cs b/src/Servers/IIS/IIS/src/Core/IISEnvironmentFeature.cs index 597237f08719..703ce1825489 100644 --- a/src/Servers/IIS/IIS/src/Core/IISEnvironmentFeature.cs +++ b/src/Servers/IIS/IIS/src/Core/IISEnvironmentFeature.cs @@ -8,7 +8,7 @@ namespace Microsoft.AspNetCore.Server.IIS.Core; internal sealed class IISEnvironmentFeature : IIISEnvironmentFeature { - public static bool TryCreate(IConfiguration configuration, [MaybeNullWhen(false)] out IIISEnvironmentFeature result) + public static bool TryCreate(IConfiguration configuration, [NotNullWhen(true)] out IIISEnvironmentFeature? result) { var feature = new IISEnvironmentFeature(configuration); From 568b674f25e6c2bd863c8a18ab37902666ec1565 Mon Sep 17 00:00:00 2001 From: Taylor Southwick Date: Sun, 27 Aug 2023 12:36:41 -0700 Subject: [PATCH 11/15] respond to feedback --- .../AspNetCore/ModuleEnvironment.cpp | 15 +++++++++++---- .../AspNetCore/ModuleEnvironment.h | 3 +++ .../IIS/AspNetCoreModuleV2/AspNetCore/dllmain.cpp | 6 +++--- 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/ModuleEnvironment.cpp b/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/ModuleEnvironment.cpp index 7290656088b0..7c60614bbec0 100644 --- a/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/ModuleEnvironment.cpp +++ b/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/ModuleEnvironment.cpp @@ -1,12 +1,15 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. + #include "ModuleEnvironment.h" #include #include -extern DWORD dwIISServerVersion; +extern DWORD g_dwIISServerVersion; static std::wstring GetIISVersion() { - auto major = (int)(dwIISServerVersion >> 16); - auto minor = (int)(dwIISServerVersion & 0xffff); + auto major = (int)(g_dwIISServerVersion >> 16); + auto minor = (int)(g_dwIISServerVersion & 0xffff); std::wstringstream version; version << major << "." << minor; @@ -36,7 +39,11 @@ void SetApplicationEnvironmentVariables(_In_ IHttpServer &server, _In_ IHttpCont SetEnvironmentVariable(L"ASPNETCORE_IIS_VERSION", GetIISVersion().c_str()); SetEnvironmentVariable(L"ASPNETCORE_IIS_APP_POOL_ID", server.GetAppPoolName()); - SetEnvironmentVariable(L"ASPNETCORE_IIS_APP_POOL_CONFIG_FILE", ((IHttpServer2&)server).GetAppPoolConfigFile()); + + IHttpServer2* server2; + if (SUCCEEDED(HttpGetExtendedInterface(&server, &server, &server2))) { + SetEnvironmentVariable(L"ASPNETCORE_IIS_APP_POOL_CONFIG_FILE", server2->GetAppPoolConfigFile()); + } auto site = pHttpContext.GetSite(); SetEnvironmentVariable(L"ASPNETCORE_IIS_SITE_NAME", site->GetSiteName()); diff --git a/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/ModuleEnvironment.h b/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/ModuleEnvironment.h index 72f74f5e6c9d..449ef41688bf 100644 --- a/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/ModuleEnvironment.h +++ b/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/ModuleEnvironment.h @@ -1,3 +1,6 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. + #pragma once void SetApplicationEnvironmentVariables(_In_ IHttpServer& server, _In_ IHttpContext& pHttpContext); diff --git a/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/dllmain.cpp b/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/dllmain.cpp index c8026430a5d5..51383598d813 100644 --- a/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/dllmain.cpp +++ b/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/dllmain.cpp @@ -19,6 +19,8 @@ BOOL g_fRecycleProcessCalled = FALSE; BOOL g_fInShutdown = FALSE; BOOL g_fInAppOfflineShutdown = FALSE; HINSTANCE g_hServerModule; +DWORD g_dwIISServerVersion; + VOID StaticCleanup() @@ -63,8 +65,6 @@ BOOL WINAPI DllMain(HMODULE hModule, return TRUE; } -DWORD dwIISServerVersion; - HRESULT __stdcall RegisterModule( @@ -92,7 +92,7 @@ HRESULT --*/ { - dwIISServerVersion = dwServerVersion; + g_dwIISServerVersion = dwServerVersion; if (pHttpServer->IsCommandLineLaunch()) { From 28566c0b2737b7f4184d4932743ea2ee57dd8b4e Mon Sep 17 00:00:00 2001 From: Taylor Southwick Date: Sun, 27 Aug 2023 12:41:04 -0700 Subject: [PATCH 12/15] add comment --- .../IIS/AspNetCoreModuleV2/AspNetCore/ModuleEnvironment.cpp | 1 + src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/dllmain.cpp | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/ModuleEnvironment.cpp b/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/ModuleEnvironment.cpp index 7c60614bbec0..f49707395e6c 100644 --- a/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/ModuleEnvironment.cpp +++ b/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/ModuleEnvironment.cpp @@ -5,6 +5,7 @@ #include #include +// Set in the RegisterModule call IIS uses to initiate the module extern DWORD g_dwIISServerVersion; static std::wstring GetIISVersion() { diff --git a/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/dllmain.cpp b/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/dllmain.cpp index 51383598d813..1fde8723bd77 100644 --- a/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/dllmain.cpp +++ b/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/dllmain.cpp @@ -21,7 +21,6 @@ BOOL g_fInAppOfflineShutdown = FALSE; HINSTANCE g_hServerModule; DWORD g_dwIISServerVersion; - VOID StaticCleanup() { From 68be21bc93148d86fa23cae99e1143f693ff9c5a Mon Sep 17 00:00:00 2001 From: Taylor Southwick Date: Tue, 29 Aug 2023 11:28:38 -0700 Subject: [PATCH 13/15] Add tests --- .../RequestResponseTests.cs | 20 +++++++++++ .../testassets/InProcessWebSite/Startup.cs | 36 +++++++++++++++++-- 2 files changed, 54 insertions(+), 2 deletions(-) diff --git a/src/Servers/IIS/IIS/test/Common.FunctionalTests/RequestResponseTests.cs b/src/Servers/IIS/IIS/test/Common.FunctionalTests/RequestResponseTests.cs index b56e6c734e83..0494a5d0013c 100644 --- a/src/Servers/IIS/IIS/test/Common.FunctionalTests/RequestResponseTests.cs +++ b/src/Servers/IIS/IIS/test/Common.FunctionalTests/RequestResponseTests.cs @@ -611,6 +611,26 @@ public async Task HostingEnvironmentIsCorrect() Assert.Equal(_fixture.DeploymentResult.ContentRoot + "\\", await _fixture.Client.GetStringAsync("/ASPNETCORE_IIS_PHYSICAL_PATH")); } + [ConditionalTheory] + [InlineData("IIISEnvironmentFeature")] + [InlineData("IIISEnvironmentFeatureConfig")] + public async Task IISEnvironmentFeatureIsAvailable(string endpoint) + { + var expected = $""" + IIS Version: 10.0 + ApplicationId: /LM/W3SVC/1/ROOT + Application Path: {_fixture.DeploymentResult.ContentRoot}\ + Application Virtual Path: / + Application Config Path: MACHINE/WEBROOT/APPHOST/HTTPTESTSITE + AppPool ID: IISExpressAppPool + AppPool Config File: {_fixture.DeploymentResult.DeploymentParameters.ServerConfigLocation} + Site ID: 1 + Site Name: {_fixture.DeploymentResult.DeploymentParameters.SiteName.ToUpperInvariant()} + """; + + Assert.Equal(expected, await _fixture.Client.GetStringAsync($"/{endpoint}")); + } + [ConditionalTheory] [InlineData(65000)] [InlineData(1000000)] diff --git a/src/Servers/IIS/IIS/test/testassets/InProcessWebSite/Startup.cs b/src/Servers/IIS/IIS/test/testassets/InProcessWebSite/Startup.cs index 90e154eeb95f..fba1940f881e 100644 --- a/src/Servers/IIS/IIS/test/testassets/InProcessWebSite/Startup.cs +++ b/src/Servers/IIS/IIS/test/testassets/InProcessWebSite/Startup.cs @@ -67,6 +67,38 @@ public void ConfigureServices(IServiceCollection serviceCollection) private async Task BaseDirectory(HttpContext ctx) => await ctx.Response.WriteAsync(AppContext.BaseDirectory); + private async Task IIISEnvironmentFeatureConfig(HttpContext ctx) + { + var config = ctx.RequestServices.GetService(); + + await ctx.Response.WriteAsync("IIS Version: " + config["IIS_VERSION"] + Environment.NewLine); + await ctx.Response.WriteAsync("ApplicationId: " + config["IIS_APPLICATION_ID"] + Environment.NewLine); + await ctx.Response.WriteAsync("Application Path: " + config["IIS_PHYSICAL_PATH"] + Environment.NewLine); + await ctx.Response.WriteAsync("Application Virtual Path: " + config["IIS_APPLICATION_VIRTUAL_PATH"] + Environment.NewLine); + await ctx.Response.WriteAsync("Application Config Path: " + config["IIS_APP_CONFIG_PATH"] + Environment.NewLine); + await ctx.Response.WriteAsync("AppPool ID: " + config["IIS_APP_POOL_ID"] + Environment.NewLine); + await ctx.Response.WriteAsync("AppPool Config File: " + config["IIS_APP_POOL_CONFIG_FILE"] + Environment.NewLine); + await ctx.Response.WriteAsync("Site ID: " + config["IIS_SITE_ID"] + Environment.NewLine); + await ctx.Response.WriteAsync("Site Name: " + config["IIS_SITE_NAME"]); + } + +#if !FORWARDCOMPAT + private async Task IIISEnvironmentFeature(HttpContext ctx) + { + var envFeature = ctx.RequestServices.GetService().Features.Get(); + + await ctx.Response.WriteAsync("IIS Version: " + envFeature.IISVersion + Environment.NewLine); + await ctx.Response.WriteAsync("ApplicationId: " + envFeature.ApplicationId + Environment.NewLine); + await ctx.Response.WriteAsync("Application Path: " + envFeature.ApplicationPhysicalPath + Environment.NewLine); + await ctx.Response.WriteAsync("Application Virtual Path: " + envFeature.ApplicationVirtualPath + Environment.NewLine); + await ctx.Response.WriteAsync("Application Config Path: " + envFeature.AppConfigPath + Environment.NewLine); + await ctx.Response.WriteAsync("AppPool ID: " + envFeature.AppPoolId + Environment.NewLine); + await ctx.Response.WriteAsync("AppPool Config File: " + envFeature.AppPoolConfigFile + Environment.NewLine); + await ctx.Response.WriteAsync("Site ID: " + envFeature.SiteId + Environment.NewLine); + await ctx.Response.WriteAsync("Site Name: " + envFeature.SiteName); + } +#endif + private async Task ASPNETCORE_IIS_PHYSICAL_PATH(HttpContext ctx) => await ctx.Response.WriteAsync(Environment.GetEnvironmentVariable("ASPNETCORE_IIS_PHYSICAL_PATH")); private async Task ServerAddresses(HttpContext ctx) @@ -1128,7 +1160,7 @@ private async Task TransferEncodingHeadersWithMultipleValues(HttpContext ctx) try { #if !FORWARDCOMPAT - Assert.True(ctx.Request.CanHaveBody()); + Assert.True(ctx.Request.CanHaveBody()); #endif Assert.True(ctx.Request.Headers.ContainsKey("Transfer-Encoding")); Assert.Equal("gzip, chunked", ctx.Request.Headers["Transfer-Encoding"]); @@ -1146,7 +1178,7 @@ private async Task TransferEncodingAndContentLengthShouldBeRemove(HttpContext ct try { #if !FORWARDCOMPAT - Assert.True(ctx.Request.CanHaveBody()); + Assert.True(ctx.Request.CanHaveBody()); #endif Assert.True(ctx.Request.Headers.ContainsKey("Transfer-Encoding")); Assert.Equal("gzip, chunked", ctx.Request.Headers["Transfer-Encoding"]); From c44a5cb8929a5f87f92b707eefd2e14c91c0790c Mon Sep 17 00:00:00 2001 From: Taylor Southwick Date: Tue, 29 Aug 2023 15:13:38 -0700 Subject: [PATCH 14/15] add properties to deployer --- .../Common.FunctionalTests/RequestResponseTests.cs | 8 +++++--- .../IIS/IntegrationTesting.IIS/src/IISDeployer.cs | 11 +++++++++-- .../IntegrationTesting.IIS/src/IISDeploymentResult.cs | 5 +++++ .../IntegrationTesting.IIS/src/IISExpressDeployer.cs | 1 + 4 files changed, 20 insertions(+), 5 deletions(-) diff --git a/src/Servers/IIS/IIS/test/Common.FunctionalTests/RequestResponseTests.cs b/src/Servers/IIS/IIS/test/Common.FunctionalTests/RequestResponseTests.cs index 0494a5d0013c..f919d911891b 100644 --- a/src/Servers/IIS/IIS/test/Common.FunctionalTests/RequestResponseTests.cs +++ b/src/Servers/IIS/IIS/test/Common.FunctionalTests/RequestResponseTests.cs @@ -616,16 +616,18 @@ public async Task HostingEnvironmentIsCorrect() [InlineData("IIISEnvironmentFeatureConfig")] public async Task IISEnvironmentFeatureIsAvailable(string endpoint) { + var siteName = _fixture.DeploymentResult.DeploymentParameters.SiteName.ToUpperInvariant(); + var expected = $""" IIS Version: 10.0 ApplicationId: /LM/W3SVC/1/ROOT Application Path: {_fixture.DeploymentResult.ContentRoot}\ Application Virtual Path: / - Application Config Path: MACHINE/WEBROOT/APPHOST/HTTPTESTSITE - AppPool ID: IISExpressAppPool + Application Config Path: MACHINE/WEBROOT/APPHOST/{siteName} + AppPool ID: {_fixture.DeploymentResult.AppPoolName} AppPool Config File: {_fixture.DeploymentResult.DeploymentParameters.ServerConfigLocation} Site ID: 1 - Site Name: {_fixture.DeploymentResult.DeploymentParameters.SiteName.ToUpperInvariant()} + Site Name: {siteName} """; Assert.Equal(expected, await _fixture.Client.GetStringAsync($"/{endpoint}")); diff --git a/src/Servers/IIS/IntegrationTesting.IIS/src/IISDeployer.cs b/src/Servers/IIS/IntegrationTesting.IIS/src/IISDeployer.cs index 509f81db631c..20a4de0ca368 100644 --- a/src/Servers/IIS/IntegrationTesting.IIS/src/IISDeployer.cs +++ b/src/Servers/IIS/IntegrationTesting.IIS/src/IISDeployer.cs @@ -28,6 +28,7 @@ public class IISDeployer : IISDeployerBase private string _configPath; private string _applicationHostConfig; private string _debugLogFile; + private string _appPoolName; private bool _disposed; public Process HostProcess { get; set; } @@ -109,6 +110,8 @@ public override Task DeployAsync() var uri = TestUriHelper.BuildTestUri(ServerType.IIS, DeploymentParameters.ApplicationBaseUriHint); StartIIS(uri, contentRoot); + IISDeploymentParameters.ServerConfigLocation = Path.Combine(@"C:\inetpub\temp\apppools", _appPoolName, $"{_appPoolName}.config"); + // Warm up time for IIS setup. Logger.LogInformation("Successfully finished IIS application directory setup."); return Task.FromResult(new IISDeploymentResult( @@ -117,7 +120,8 @@ public override Task DeployAsync() applicationBaseUri: uri.ToString(), contentRoot: contentRoot, hostShutdownToken: _hostShutdownToken.Token, - hostProcess: HostProcess + hostProcess: HostProcess, + appPoolName: _appPoolName )); } } @@ -239,6 +243,8 @@ private void WaitUntilSiteStarted(string contentRoot) RetryServerManagerAction(serverManager => { var site = FindSite(serverManager, contentRoot); + IISDeploymentParameters.SiteName = site.Name; + if (site == null) { PreserveConfigFiles("nositetostart"); @@ -246,6 +252,7 @@ private void WaitUntilSiteStarted(string contentRoot) } var appPool = serverManager.ApplicationPools.Single(); + _appPoolName = appPool.Name; if (appPool.State != ObjectState.Started && appPool.State != ObjectState.Starting) { var state = appPool.Start(); @@ -500,7 +507,7 @@ private void RetryServerManagerAction(Action action) private void PreserveConfigFiles(string fileNamePrefix) { - HelixHelper.PreserveFile(Path.Combine(DeploymentParameters.PublishedApplicationRootPath, "web.config"), fileNamePrefix+".web.config"); + HelixHelper.PreserveFile(Path.Combine(DeploymentParameters.PublishedApplicationRootPath, "web.config"), fileNamePrefix + ".web.config"); HelixHelper.PreserveFile(Path.Combine(_configPath, "applicationHost.config"), fileNamePrefix + ".applicationHost.config"); HelixHelper.PreserveFile(Path.Combine(Environment.SystemDirectory, @"inetsrv\config\ApplicationHost.config"), fileNamePrefix + ".inetsrv.applicationHost.config"); HelixHelper.PreserveFile(Path.Combine(Environment.SystemDirectory, @"inetsrv\config\redirection.config"), fileNamePrefix + ".inetsrv.redirection.config"); diff --git a/src/Servers/IIS/IntegrationTesting.IIS/src/IISDeploymentResult.cs b/src/Servers/IIS/IntegrationTesting.IIS/src/IISDeploymentResult.cs index 043852daa874..1cf6072b547d 100644 --- a/src/Servers/IIS/IntegrationTesting.IIS/src/IISDeploymentResult.cs +++ b/src/Servers/IIS/IntegrationTesting.IIS/src/IISDeploymentResult.cs @@ -10,12 +10,16 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting.IIS; public class IISDeploymentResult : DeploymentResult { public ILogger Logger { get; set; } + public Process HostProcess { get; } + public string AppPoolName { get; } + public IISDeploymentResult(ILoggerFactory loggerFactory, IISDeploymentParameters deploymentParameters, string applicationBaseUri, string contentRoot, + string appPoolName, CancellationToken hostShutdownToken, Process hostProcess) : base(loggerFactory, @@ -24,6 +28,7 @@ public IISDeploymentResult(ILoggerFactory loggerFactory, contentRoot, hostShutdownToken) { + AppPoolName = appPoolName; HostProcess = hostProcess; Logger = loggerFactory.CreateLogger(deploymentParameters.SiteName); HttpClient = CreateClient(new HttpClientHandler()); diff --git a/src/Servers/IIS/IntegrationTesting.IIS/src/IISExpressDeployer.cs b/src/Servers/IIS/IntegrationTesting.IIS/src/IISExpressDeployer.cs index 951491335c54..edfdee36baa4 100644 --- a/src/Servers/IIS/IntegrationTesting.IIS/src/IISExpressDeployer.cs +++ b/src/Servers/IIS/IntegrationTesting.IIS/src/IISExpressDeployer.cs @@ -105,6 +105,7 @@ public override async Task DeployAsync() applicationBaseUri: actualUri.ToString(), contentRoot: contentRoot, hostShutdownToken: hostExitToken, + appPoolName: "IISExpressAppPool", hostProcess: _hostProcess); } } From 27b94d9551662cea6a90d7cd8dd4437a9ba6e744 Mon Sep 17 00:00:00 2001 From: Taylor Southwick Date: Tue, 29 Aug 2023 16:36:36 -0700 Subject: [PATCH 15/15] don't use auto --- .../AspNetCore/ModuleEnvironment.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/ModuleEnvironment.cpp b/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/ModuleEnvironment.cpp index f49707395e6c..7b333bdda889 100644 --- a/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/ModuleEnvironment.cpp +++ b/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/ModuleEnvironment.cpp @@ -9,8 +9,8 @@ extern DWORD g_dwIISServerVersion; static std::wstring GetIISVersion() { - auto major = (int)(g_dwIISServerVersion >> 16); - auto minor = (int)(g_dwIISServerVersion & 0xffff); + int major = (int)(g_dwIISServerVersion >> 16); + int minor = (int)(g_dwIISServerVersion & 0xffff); std::wstringstream version; version << major << "." << minor; @@ -19,8 +19,9 @@ static std::wstring GetIISVersion() { } static std::wstring ToVirtualPath(const std::wstring& configurationPath) { - auto segments = 0; - auto position = configurationPath.find('/'); + int segments = 0; + size_t position = configurationPath.find('/'); + // Skip first 4 segments of config path while (segments != 3 && position != std::wstring::npos) { @@ -46,11 +47,11 @@ void SetApplicationEnvironmentVariables(_In_ IHttpServer &server, _In_ IHttpCont SetEnvironmentVariable(L"ASPNETCORE_IIS_APP_POOL_CONFIG_FILE", server2->GetAppPoolConfigFile()); } - auto site = pHttpContext.GetSite(); + IHttpSite* site = pHttpContext.GetSite(); SetEnvironmentVariable(L"ASPNETCORE_IIS_SITE_NAME", site->GetSiteName()); SetEnvironmentVariable(L"ASPNETCORE_IIS_SITE_ID", std::to_wstring(site->GetSiteId()).c_str()); - auto app = pHttpContext.GetApplication(); + IHttpApplication* app = pHttpContext.GetApplication(); SetEnvironmentVariable(L"ASPNETCORE_IIS_APP_CONFIG_PATH", app->GetAppConfigPath()); SetEnvironmentVariable(L"ASPNETCORE_IIS_APPLICATION_ID", app->GetApplicationId()); SetEnvironmentVariable(L"ASPNETCORE_IIS_APPLICATION_VIRTUAL_PATH", ToVirtualPath(app->GetAppConfigPath()).c_str());