Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
<ClInclude Include="AppOfflineApplication.h" />
<ClInclude Include="AppOfflineHandler.h" />
<ClInclude Include="DisconnectHandler.h" />
<ClInclude Include="ModuleEnvironment.h" />
<ClInclude Include="ShimOptions.h" />
<ClInclude Include="globalmodule.h" />
<ClInclude Include="resource.h" />
Expand All @@ -49,6 +50,7 @@
<ClCompile Include="AppOfflineApplication.cpp" />
<ClCompile Include="AppOfflineHandler.cpp" />
<ClCompile Include="DisconnectHandler.cpp" />
<ClCompile Include="ModuleEnvironment.cpp" />
<ClCompile Include="ShimOptions.cpp" />
<ClCompile Include="dllmain.cpp" />
<ClCompile Include="globalmodule.cpp" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// 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 <string>
#include <sstream>

// Set in the RegisterModule call IIS uses to initiate the module
extern DWORD g_dwIISServerVersion;

static std::wstring GetIISVersion() {
int major = (int)(g_dwIISServerVersion >> 16);
int minor = (int)(g_dwIISServerVersion & 0xffff);

std::wstringstream version;
version << major << "." << minor;

return version.str();
}

static std::wstring ToVirtualPath(const std::wstring& configurationPath) {
int segments = 0;
size_t 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 &server, _In_ IHttpContext &pHttpContext) {
SetEnvironmentVariable(L"ASPNETCORE_IIS_VERSION", GetIISVersion().c_str());

SetEnvironmentVariable(L"ASPNETCORE_IIS_APP_POOL_ID", server.GetAppPoolName());

IHttpServer2* server2;
if (SUCCEEDED(HttpGetExtendedInterface(&server, &server, &server2))) {
SetEnvironmentVariable(L"ASPNETCORE_IIS_APP_POOL_CONFIG_FILE", server2->GetAppPoolConfigFile());
}

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());

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());
}
Original file line number Diff line number Diff line change
@@ -0,0 +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);
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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))
{
Expand Down
3 changes: 2 additions & 1 deletion src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/dllmain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ BOOL g_fRecycleProcessCalled = FALSE;
BOOL g_fInShutdown = FALSE;
BOOL g_fInAppOfflineShutdown = FALSE;
HINSTANCE g_hServerModule;
DWORD g_dwIISServerVersion;

VOID
StaticCleanup()
Expand Down Expand Up @@ -90,7 +91,7 @@ HRESULT

--*/
{
UNREFERENCED_PARAMETER(dwServerVersion);
g_dwIISServerVersion = dwServerVersion;

if (pHttpServer->IsCommandLineLaunch())
{
Expand Down
23 changes: 22 additions & 1 deletion src/Servers/IIS/IIS/samples/NativeIISSample/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -96,11 +96,32 @@ public void Configure(IApplicationBuilder app)
}

await context.Response.WriteAsync(Environment.NewLine);
var addresses = context.RequestServices.GetService<IServer>().Features.Get<IServerAddressesFeature>();
var server = context.RequestServices.GetService<IServer>();

var addresses = server.Features.Get<IServerAddressesFeature>();
foreach (var key in addresses.Addresses)
{
await context.Response.WriteAsync(key + Environment.NewLine);
}

if (server.Features.Get<IIISEnvironmentFeature>() 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);
}
});
}

Expand Down
63 changes: 63 additions & 0 deletions src/Servers/IIS/IIS/src/Core/IISEnvironmentFeature.cs
Original file line number Diff line number Diff line change
@@ -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, [NotNullWhen(true)] 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; }
}
7 changes: 7 additions & 0 deletions src/Servers/IIS/IIS/src/Core/IISHttpServer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -58,6 +59,7 @@ public IISHttpServer(
IISNativeApplication nativeApplication,
IHostApplicationLifetime applicationLifetime,
IAuthenticationSchemeProvider authentication,
IConfiguration configuration,
IOptions<IISServerOptions> options,
ILogger<IISHttpServer> logger
)
Expand All @@ -77,6 +79,11 @@ ILogger<IISHttpServer> logger

Features.Set<IServerAddressesFeature>(_serverAddressesFeature);

if (IISEnvironmentFeature.TryCreate(configuration, out var iisEnvFeature))
{
Features.Set<IIISEnvironmentFeature>(iisEnvFeature);
}

if (_options.MaxRequestBodySize > _options.IisMaxRequestSizeLimit)
{
_logger.LogWarning(CoreStrings.MaxRequestLimitWarning);
Expand Down
55 changes: 55 additions & 0 deletions src/Servers/IIS/IIS/src/IIISEnvironmentFeature.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// 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;

/// <summary>
/// This feature provides access to IIS application information
/// </summary>
public interface IIISEnvironmentFeature
{
/// <summary>
/// Gets the version of IIS that is being used.
/// </summary>
Version IISVersion { get; }

/// <summary>
/// Gets the AppPool name that is currently running
/// </summary>
string AppPoolId { get; }

/// <summary>
/// Gets the path to the AppPool config
/// </summary>
string AppPoolConfigFile { get; }

/// <summary>
/// Gets path to the application configuration that is currently running
/// </summary>
string AppConfigPath { get; }

/// <summary>
/// Gets the physical path of the application.
/// </summary>
string ApplicationPhysicalPath { get; }

/// <summary>
/// Gets the virtual path of the application.
/// </summary>
string ApplicationVirtualPath { get; }

/// <summary>
/// Gets ID of the current application.
/// </summary>
string ApplicationId { get; }

/// <summary>
/// Gets the name of the current site.
/// </summary>
string SiteName { get; }

/// <summary>
/// Gets the id of the current site.
/// </summary>
uint SiteId { get; }
}
12 changes: 11 additions & 1 deletion src/Servers/IIS/IIS/src/PublicAPI.Unshipped.txt
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,14 @@
*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
*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.ApplicationPhysicalPath.get -> string!
Microsoft.AspNetCore.Server.IIS.IIISEnvironmentFeature.ApplicationVirtualPath.get -> string!
Microsoft.AspNetCore.Server.IIS.IIISEnvironmentFeature.AppPoolConfigFile.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!
Original file line number Diff line number Diff line change
Expand Up @@ -611,6 +611,28 @@ 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 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/{siteName}
AppPool ID: {_fixture.DeploymentResult.AppPoolName}
AppPool Config File: {_fixture.DeploymentResult.DeploymentParameters.ServerConfigLocation}
Site ID: 1
Site Name: {siteName}
""";

Assert.Equal(expected, await _fixture.Client.GetStringAsync($"/{endpoint}"));
}

[ConditionalTheory]
[InlineData(65000)]
[InlineData(1000000)]
Expand Down
Loading