Skip to content

Commit 45d1c05

Browse files
authored
Add IServerAddressesFeature support (#4685)
1 parent 5ab3c89 commit 45d1c05

39 files changed

+585
-137
lines changed

src/Servers/IIS/IISIntegration.NoV1.sln

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IISExpress.FunctionalTests"
5353
EndProject
5454
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NativeIISSample", "samples\NativeIISSample\NativeIISSample.csproj", "{9BC4AFCB-325D-4C81-8228-8CF301CE2F97}"
5555
EndProject
56-
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "InProcessWebSite", "test\WebSites\InProcessWebSite\InProcessWebSite.csproj", "{679FA2A2-898B-4320-884E-C2D294A97CE1}"
56+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "InProcessWebSite", "test\testassets\InProcessWebSite\InProcessWebSite.csproj", "{679FA2A2-898B-4320-884E-C2D294A97CE1}"
5757
EndProject
5858
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Server.IIS", "src\Microsoft.AspNetCore.Server.IIS\Microsoft.AspNetCore.Server.IIS.csproj", "{46A8612B-418B-4D70-B3A7-A21DD0627473}"
5959
ProjectSection(ProjectDependencies) = postProject
@@ -63,7 +63,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Server
6363
{D57EA297-6DC2-4BC0-8C91-334863327863} = {D57EA297-6DC2-4BC0-8C91-334863327863}
6464
EndProjectSection
6565
EndProject
66-
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StressTestWebSite", "test\WebSites\StressTestWebSite\StressTestWebSite.csproj", "{13FD8F12-FFBE-4D01-B4AC-444F2994B04F}"
66+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StressTestWebSite", "test\testassets\StressTestWebSite\StressTestWebSite.csproj", "{13FD8F12-FFBE-4D01-B4AC-444F2994B04F}"
6767
ProjectSection(ProjectDependencies) = postProject
6868
{46A8612B-418B-4D70-B3A7-A21DD0627473} = {46A8612B-418B-4D70-B3A7-A21DD0627473}
6969
EndProjectSection
@@ -82,7 +82,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CommonLib", "src\AspNetCore
8282
EndProject
8383
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "IISLib", "src\AspNetCoreModuleV2\IISLib\IISLib.vcxproj", "{09D9D1D6-2951-4E14-BC35-76A23CF9391A}"
8484
EndProject
85-
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OutOfProcessWebSite", "test\WebSites\OutOfProcessWebSite\OutOfProcessWebSite.csproj", "{42E60F88-E23F-417A-8143-0CCEC05E1D02}"
85+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OutOfProcessWebSite", "test\testassets\OutOfProcessWebSite\OutOfProcessWebSite.csproj", "{42E60F88-E23F-417A-8143-0CCEC05E1D02}"
8686
EndProject
8787
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "benchmarks", "benchmarks", "{622D35C9-627B-466E-8D15-752968CC79AF}"
8888
EndProject
@@ -114,7 +114,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IIS.BackwardsCompatibility.
114114
EndProject
115115
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IIS.ForwardsCompatibility.FunctionalTests", "test\IIS.ForwardsCompatibility.FunctionalTests\IIS.ForwardsCompatibility.FunctionalTests.csproj", "{D1EA5D99-28FD-4197-81DE-17098846B38B}"
116116
EndProject
117-
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "InProcessWebSite", "test\WebSites\InProcessForwardsCompatWebSite\InProcessWebSite.csproj", "{BBBC85B2-5D7A-4D09-90B1-8DBCC9059493}"
117+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "InProcessWebSite", "test\testassets\InProcessForwardsCompatWebSite\InProcessWebSite.csproj", "{BBBC85B2-5D7A-4D09-90B1-8DBCC9059493}"
118118
EndProject
119119
Global
120120
GlobalSection(SolutionConfigurationPlatforms) = preSolution

src/Servers/IIS/build/launchSettings.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
"IIS_SITE_PATH": "$(MSBuildThisFileDirectory)",
1717
"ANCM_PATH": "$(AspNetCoreModuleV1ShimDll)",
1818
"ANCMV2_PATH": "$(AspNetCoreModuleV2ShimDll)",
19-
"ANCM_OUTOFPROCESS_HANDLER": "$(AspNetCoreModuleV2OutOfProcessHandlerDll)",
19+
"ASPNETCORE_MODULE_OUTOFPROCESS_HANDLER": "$(AspNetCoreModuleV2OutOfProcessHandlerDll)",
2020
"LAUNCHER_ARGS": "$(TargetPath)",
2121
"ASPNETCORE_ENVIRONMENT": "Development",
2222
"LAUNCHER_PATH": "$(DotNetPath)",

src/Servers/IIS/samples/NativeIISSample/Startup.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,12 @@
66
using Microsoft.AspNetCore.Authentication;
77
using Microsoft.AspNetCore.Builder;
88
using Microsoft.AspNetCore.Hosting;
9+
using Microsoft.AspNetCore.Hosting.Server;
10+
using Microsoft.AspNetCore.Hosting.Server.Features;
911
using Microsoft.AspNetCore.Http;
1012
using Microsoft.AspNetCore.Http.Features;
1113
using Microsoft.AspNetCore.Server.IIS;
14+
using Microsoft.Extensions.DependencyInjection;
1215

1316
namespace NativeIISSample
1417
{
@@ -89,6 +92,13 @@ public void Configure(IApplicationBuilder app, IHostingEnvironment env)
8992
{
9093
await context.Response.WriteAsync("Websocket feature is disabled.");
9194
}
95+
96+
await context.Response.WriteAsync(Environment.NewLine);
97+
var addresses = context.RequestServices.GetService<IServer>().Features.Get<IServerAddressesFeature>();
98+
foreach (var key in addresses.Addresses)
99+
{
100+
await context.Response.WriteAsync(key + Environment.NewLine);
101+
}
92102
});
93103
}
94104

src/Servers/IIS/src/AspNetCoreModuleV2/AspNetCore/ApplicationFactory.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,11 @@ class ApplicationFactory
3636
{
3737
// m_location.data() is const ptr copy to local to get mutable pointer
3838
auto location = m_location;
39-
std::array<APPLICATION_PARAMETER, 2> parameters {
39+
std::array<APPLICATION_PARAMETER, 3> parameters {
4040
{
4141
{"InProcessExeLocation", location.data()},
42-
{"TraceContext", pHttpContext->GetTraceContext()}
42+
{"TraceContext", pHttpContext->GetTraceContext()},
43+
{"Site", pHttpContext->GetSite()}
4344
}
4445
};
4546

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the MIT License. See License.txt in the project root for license information.
3+
4+
#pragma once
5+
6+
#include <string>
7+
#include "ConfigurationSource.h"
8+
#include "StringHelpers.h"
9+
#include "WebConfigConfigurationSource.h"
10+
11+
#define CS_SITE_SECTION L"system.applicationHost/sites"
12+
#define CS_SITE_NAME L"name"
13+
#define CS_SITE_BINDINGS L"bindings"
14+
#define CS_SITE_BINDING_INFORMATION L"bindingInformation"
15+
#define CS_SITE_BINDING_INFORMATION_ALL_HOSTS L"*"
16+
#define CS_SITE_BINDING_PROTOCOL L"protocol"
17+
#define CS_SITE_BINDING_PROTOCOL_HTTPS L"https"
18+
#define CS_SITE_BINDING_INFORMATION_DELIMITER L':'
19+
20+
class BindingInformation
21+
{
22+
public:
23+
BindingInformation(std::wstring protocol, std::wstring host, std::wstring port)
24+
{
25+
m_protocol = protocol;
26+
m_host = host;
27+
m_port = port;
28+
}
29+
30+
BindingInformation(std::wstring protocol, std::wstring bindingInformation)
31+
{
32+
// Expected format:
33+
// IP:PORT:HOST
34+
// where IP or HOST can be empty
35+
36+
m_protocol = protocol;
37+
38+
const auto portStart = bindingInformation.find(CS_SITE_BINDING_INFORMATION_DELIMITER) + 1;
39+
const auto lastColon = bindingInformation.find_last_of(CS_SITE_BINDING_INFORMATION_DELIMITER);
40+
auto const hostStart = lastColon + 1;
41+
m_host = bindingInformation.substr(hostStart, bindingInformation.length() - hostStart);
42+
if (m_host.length() == 0)
43+
{
44+
m_host = CS_SITE_BINDING_INFORMATION_ALL_HOSTS;
45+
}
46+
m_port = bindingInformation.substr(portStart, lastColon - portStart);
47+
}
48+
49+
std::wstring& QueryProtocol()
50+
{
51+
return m_protocol;
52+
}
53+
54+
std::wstring& QueryPort()
55+
{
56+
return m_port;
57+
}
58+
59+
std::wstring& QueryHost()
60+
{
61+
return m_host;
62+
}
63+
64+
static
65+
std::vector<BindingInformation>
66+
Load(const ConfigurationSource &configurationSource, const IHttpSite& pSite)
67+
{
68+
std::vector<BindingInformation> items;
69+
70+
const std::wstring runningSiteName = pSite.GetSiteName();
71+
72+
auto const siteSection = configurationSource.GetRequiredSection(CS_SITE_SECTION);
73+
auto sites = siteSection->GetCollection();
74+
for (const auto& site: sites)
75+
{
76+
auto siteName = site->GetRequiredString(CS_SITE_NAME);
77+
if (equals_ignore_case(runningSiteName, siteName))
78+
{
79+
auto bindings = site->GetRequiredSection(CS_SITE_BINDINGS)->GetCollection();
80+
for (const auto& binding : bindings)
81+
{
82+
items.emplace_back(
83+
binding->GetRequiredString(CS_SITE_BINDING_PROTOCOL),
84+
binding->GetRequiredString(CS_SITE_BINDING_INFORMATION)
85+
);
86+
}
87+
}
88+
}
89+
90+
return items;
91+
}
92+
93+
static
94+
std::wstring Format(const std::vector<BindingInformation> & bindings, const std::wstring & basePath)
95+
{
96+
std::wstring result;
97+
98+
for (auto binding : bindings)
99+
{
100+
result += binding.QueryProtocol() + L"://" + binding.QueryHost() + L":" + binding.QueryPort() + basePath + L";";
101+
}
102+
103+
return result;
104+
}
105+
106+
static
107+
std::wstring GetHttpsPort(const std::vector<BindingInformation> & bindings)
108+
{
109+
std::wstring selectedPort;
110+
for (auto binding : bindings)
111+
{
112+
if (equals_ignore_case(binding.QueryProtocol(), CS_SITE_BINDING_PROTOCOL_HTTPS))
113+
{
114+
const auto bindingPort = binding.QueryPort();
115+
if (selectedPort.empty())
116+
{
117+
selectedPort = binding.QueryPort();
118+
}
119+
else if (selectedPort != bindingPort)
120+
{
121+
// If there are multiple endpoints configured return empty port
122+
return L"";
123+
}
124+
}
125+
}
126+
return selectedPort;
127+
}
128+
129+
private:
130+
std::wstring m_protocol;
131+
std::wstring m_port;
132+
std::wstring m_host;
133+
};

src/Servers/IIS/src/AspNetCoreModuleV2/CommonLib/CommonLib.vcxproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,7 @@
200200
<ItemGroup>
201201
<ClInclude Include="application.h" />
202202
<ClInclude Include="baseoutputmanager.h" />
203+
<ClInclude Include="BindingInformation.h" />
203204
<ClInclude Include="ConfigurationSection.h" />
204205
<ClInclude Include="ConfigurationSource.h" />
205206
<ClInclude Include="config_utility.h" />

src/Servers/IIS/src/AspNetCoreModuleV2/CommonLib/ConfigurationSection.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,28 @@ void ConfigurationSection::ThrowRequiredException(const std::wstring& name)
5151
throw ConfigurationLoadException(format(L"Attribute '%s' is required.", name.c_str()));
5252
}
5353

54+
std::vector<std::pair<std::wstring, std::wstring>> ConfigurationSection::GetKeyValuePairs(const std::wstring& name) const
55+
{
56+
std::vector<std::pair<std::wstring, std::wstring>> pairs;
57+
58+
for (auto const element : GetRequiredSection(name)->GetCollection())
59+
{
60+
pairs.emplace_back(element->GetRequiredString(CS_ASPNETCORE_COLLECTION_ITEM_NAME),
61+
element->GetString(CS_ASPNETCORE_COLLECTION_ITEM_VALUE).value_or(L""));
62+
}
63+
return pairs;
64+
}
65+
66+
std::shared_ptr<ConfigurationSection> ConfigurationSection::GetRequiredSection(const std::wstring& name) const
67+
{
68+
auto section = GetSection(name);
69+
if (!section)
70+
{
71+
throw ConfigurationLoadException(format(L"Unable to get required configuration section '%s'. Possible reason is web.config authoring error.", name.c_str()));
72+
}
73+
return section.value();
74+
}
75+
5476
std::optional<std::wstring> find_element(const std::vector<std::pair<std::wstring, std::wstring>>& pairs, const std::wstring& name)
5577
{
5678
const auto iter = std::find_if(

src/Servers/IIS/src/AspNetCoreModuleV2/CommonLib/ConfigurationSection.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,17 @@ class ConfigurationSection: NonCopyable
3737
virtual std::optional<DWORD> GetLong(const std::wstring& name) const = 0;
3838
virtual std::optional<DWORD> GetTimespan(const std::wstring& name) const = 0;
3939

40+
virtual std::optional<std::shared_ptr<ConfigurationSection>> GetSection(const std::wstring& name) const = 0;
41+
virtual std::vector<std::shared_ptr<ConfigurationSection>> GetCollection() const = 0;
42+
4043
std::wstring GetRequiredString(const std::wstring& name) const;
4144
bool GetRequiredBool(const std::wstring& name) const;
4245
DWORD GetRequiredLong(const std::wstring& name) const;
4346
DWORD GetRequiredTimespan(const std::wstring& name) const;
4447

45-
virtual std::vector<std::pair<std::wstring, std::wstring>> GetKeyValuePairs(const std::wstring& name) const = 0;
48+
virtual std::vector<std::pair<std::wstring, std::wstring>> GetKeyValuePairs(const std::wstring& name) const;
49+
50+
virtual std::shared_ptr<ConfigurationSection> GetRequiredSection(const std::wstring & name) const;
4651

4752
protected:
4853
static void ThrowRequiredException(const std::wstring& name);

src/Servers/IIS/src/AspNetCoreModuleV2/CommonLib/WebConfigConfigurationSection.cpp

Lines changed: 17 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -50,43 +50,38 @@ std::optional<DWORD> WebConfigConfigurationSection::GetTimespan(const std::wstri
5050
return std::make_optional(static_cast<DWORD>(result / 10000ull));
5151
}
5252

53-
std::vector<std::pair<std::wstring, std::wstring>> WebConfigConfigurationSection::GetKeyValuePairs(const std::wstring& name) const
53+
std::optional<std::shared_ptr<ConfigurationSection>> WebConfigConfigurationSection::GetSection(const std::wstring& name) const
5454
{
55-
std::vector<std::pair<std::wstring, std::wstring>> pairs;
56-
HRESULT findElementResult;
57-
CComPtr<IAppHostElement> element = nullptr;
58-
CComPtr<IAppHostElementCollection> elementCollection = nullptr;
59-
CComPtr<IAppHostElement> collectionEntry = nullptr;
60-
ENUM_INDEX index{};
55+
CComPtr<IAppHostElement> element = nullptr;
6156

6257
if (FAILED_LOG(GetElementChildByName(m_element, name.c_str(), &element)))
6358
{
64-
return pairs;
59+
return std::nullopt;
6560
}
6661

67-
THROW_IF_FAILED(element->get_Collection(&elementCollection));
62+
return std::make_optional(std::make_shared<WebConfigConfigurationSection>(element.Detach()));
63+
}
64+
65+
std::vector<std::shared_ptr<ConfigurationSection>> WebConfigConfigurationSection::GetCollection() const
66+
{
67+
std::vector<std::shared_ptr<ConfigurationSection>> elements;
68+
HRESULT findElementResult;
69+
CComPtr<IAppHostElementCollection> elementCollection = nullptr;
70+
CComPtr<IAppHostElement> collectionEntry = nullptr;
71+
ENUM_INDEX index{};
72+
73+
THROW_IF_FAILED(m_element->get_Collection(&elementCollection));
6874
THROW_IF_FAILED(findElementResult = FindFirstElement(elementCollection, &index, &collectionEntry));
6975

7076
while (findElementResult != S_FALSE)
7177
{
72-
CComBSTR strHandlerName;
73-
if (LOG_IF_FAILED(GetElementStringProperty(collectionEntry, CS_ASPNETCORE_COLLECTION_ITEM_NAME, &strHandlerName.m_str)))
74-
{
75-
ThrowRequiredException(CS_ASPNETCORE_COLLECTION_ITEM_NAME);
76-
}
77-
78-
CComBSTR strHandlerValue;
79-
if (LOG_IF_FAILED(GetElementStringProperty(collectionEntry, CS_ASPNETCORE_COLLECTION_ITEM_VALUE, &strHandlerValue.m_str)))
80-
{
81-
ThrowRequiredException(CS_ASPNETCORE_COLLECTION_ITEM_VALUE);
82-
}
8378

84-
pairs.emplace_back(strHandlerName, strHandlerValue);
79+
elements.emplace_back(std::make_shared<WebConfigConfigurationSection>(collectionEntry.Detach()));
8580

8681
collectionEntry.Release();
8782

8883
THROW_IF_FAILED(findElementResult = FindNextElement(elementCollection, &index, &collectionEntry));
8984
}
9085

91-
return pairs;
86+
return elements;
9287
}

src/Servers/IIS/src/AspNetCoreModuleV2/CommonLib/WebConfigConfigurationSection.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ class WebConfigConfigurationSection: public ConfigurationSection
1919
std::optional<bool> GetBool(const std::wstring& name) const override;
2020
std::optional<DWORD> GetLong(const std::wstring& name) const override;
2121
std::optional<DWORD> GetTimespan(const std::wstring& name) const override;
22-
std::vector<std::pair<std::wstring, std::wstring>> GetKeyValuePairs(const std::wstring& name) const override;
22+
std::optional<std::shared_ptr<ConfigurationSection>> GetSection(const std::wstring& name) const override;
23+
std::vector<std::shared_ptr<ConfigurationSection>> GetCollection() const override;
2324

2425
private:
2526
CComPtr<IAppHostElement> m_element;

src/Servers/IIS/src/AspNetCoreModuleV2/InProcessRequestHandler/InProcessOptions.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,14 @@
77

88
HRESULT InProcessOptions::Create(
99
IHttpServer& pServer,
10+
IHttpSite* site,
1011
IHttpApplication& pHttpApplication,
1112
std::unique_ptr<InProcessOptions>& options)
1213
{
1314
try
1415
{
1516
const WebConfigConfigurationSource configurationSource(pServer.GetAdminManager(), pHttpApplication);
16-
options = std::make_unique<InProcessOptions>(configurationSource);
17+
options = std::make_unique<InProcessOptions>(configurationSource, site);
1718
}
1819
catch (InvalidOperationException& ex)
1920
{
@@ -38,7 +39,7 @@ HRESULT InProcessOptions::Create(
3839
return S_OK;
3940
}
4041

41-
InProcessOptions::InProcessOptions(const ConfigurationSource &configurationSource) :
42+
InProcessOptions::InProcessOptions(const ConfigurationSource &configurationSource, IHttpSite* pSite) :
4243
m_fStdoutLogEnabled(false),
4344
m_fWindowsAuthEnabled(false),
4445
m_fBasicAuthEnabled(false),
@@ -68,4 +69,9 @@ InProcessOptions::InProcessOptions(const ConfigurationSource &configurationSourc
6869

6970
const auto anonAuthSection = configurationSource.GetSection(CS_ANONYMOUS_AUTHENTICATION_SECTION);
7071
m_fAnonymousAuthEnabled = anonAuthSection && anonAuthSection->GetBool(CS_ENABLED).value_or(false);
72+
73+
if (pSite != nullptr)
74+
{
75+
m_bindingInformation = BindingInformation::Load(configurationSource, *pSite);
76+
}
7177
}

0 commit comments

Comments
 (0)