Add IServerAddressesFeature support (#4685)
This commit is contained in:
parent
5ab3c89be3
commit
45d1c054b2
|
|
@ -53,7 +53,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IISExpress.FunctionalTests"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NativeIISSample", "samples\NativeIISSample\NativeIISSample.csproj", "{9BC4AFCB-325D-4C81-8228-8CF301CE2F97}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NativeIISSample", "samples\NativeIISSample\NativeIISSample.csproj", "{9BC4AFCB-325D-4C81-8228-8CF301CE2F97}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "InProcessWebSite", "test\WebSites\InProcessWebSite\InProcessWebSite.csproj", "{679FA2A2-898B-4320-884E-C2D294A97CE1}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "InProcessWebSite", "test\testassets\InProcessWebSite\InProcessWebSite.csproj", "{679FA2A2-898B-4320-884E-C2D294A97CE1}"
|
||||||
EndProject
|
EndProject
|
||||||
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}"
|
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}"
|
||||||
ProjectSection(ProjectDependencies) = postProject
|
ProjectSection(ProjectDependencies) = postProject
|
||||||
|
|
@ -63,7 +63,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Server
|
||||||
{D57EA297-6DC2-4BC0-8C91-334863327863} = {D57EA297-6DC2-4BC0-8C91-334863327863}
|
{D57EA297-6DC2-4BC0-8C91-334863327863} = {D57EA297-6DC2-4BC0-8C91-334863327863}
|
||||||
EndProjectSection
|
EndProjectSection
|
||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StressTestWebSite", "test\WebSites\StressTestWebSite\StressTestWebSite.csproj", "{13FD8F12-FFBE-4D01-B4AC-444F2994B04F}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StressTestWebSite", "test\testassets\StressTestWebSite\StressTestWebSite.csproj", "{13FD8F12-FFBE-4D01-B4AC-444F2994B04F}"
|
||||||
ProjectSection(ProjectDependencies) = postProject
|
ProjectSection(ProjectDependencies) = postProject
|
||||||
{46A8612B-418B-4D70-B3A7-A21DD0627473} = {46A8612B-418B-4D70-B3A7-A21DD0627473}
|
{46A8612B-418B-4D70-B3A7-A21DD0627473} = {46A8612B-418B-4D70-B3A7-A21DD0627473}
|
||||||
EndProjectSection
|
EndProjectSection
|
||||||
|
|
@ -82,7 +82,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CommonLib", "src\AspNetCore
|
||||||
EndProject
|
EndProject
|
||||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "IISLib", "src\AspNetCoreModuleV2\IISLib\IISLib.vcxproj", "{09D9D1D6-2951-4E14-BC35-76A23CF9391A}"
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "IISLib", "src\AspNetCoreModuleV2\IISLib\IISLib.vcxproj", "{09D9D1D6-2951-4E14-BC35-76A23CF9391A}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OutOfProcessWebSite", "test\WebSites\OutOfProcessWebSite\OutOfProcessWebSite.csproj", "{42E60F88-E23F-417A-8143-0CCEC05E1D02}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OutOfProcessWebSite", "test\testassets\OutOfProcessWebSite\OutOfProcessWebSite.csproj", "{42E60F88-E23F-417A-8143-0CCEC05E1D02}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "benchmarks", "benchmarks", "{622D35C9-627B-466E-8D15-752968CC79AF}"
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "benchmarks", "benchmarks", "{622D35C9-627B-466E-8D15-752968CC79AF}"
|
||||||
EndProject
|
EndProject
|
||||||
|
|
@ -114,7 +114,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IIS.BackwardsCompatibility.
|
||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IIS.ForwardsCompatibility.FunctionalTests", "test\IIS.ForwardsCompatibility.FunctionalTests\IIS.ForwardsCompatibility.FunctionalTests.csproj", "{D1EA5D99-28FD-4197-81DE-17098846B38B}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IIS.ForwardsCompatibility.FunctionalTests", "test\IIS.ForwardsCompatibility.FunctionalTests\IIS.ForwardsCompatibility.FunctionalTests.csproj", "{D1EA5D99-28FD-4197-81DE-17098846B38B}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "InProcessWebSite", "test\WebSites\InProcessForwardsCompatWebSite\InProcessWebSite.csproj", "{BBBC85B2-5D7A-4D09-90B1-8DBCC9059493}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "InProcessWebSite", "test\testassets\InProcessForwardsCompatWebSite\InProcessWebSite.csproj", "{BBBC85B2-5D7A-4D09-90B1-8DBCC9059493}"
|
||||||
EndProject
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@
|
||||||
"IIS_SITE_PATH": "$(MSBuildThisFileDirectory)",
|
"IIS_SITE_PATH": "$(MSBuildThisFileDirectory)",
|
||||||
"ANCM_PATH": "$(AspNetCoreModuleV1ShimDll)",
|
"ANCM_PATH": "$(AspNetCoreModuleV1ShimDll)",
|
||||||
"ANCMV2_PATH": "$(AspNetCoreModuleV2ShimDll)",
|
"ANCMV2_PATH": "$(AspNetCoreModuleV2ShimDll)",
|
||||||
"ANCM_OUTOFPROCESS_HANDLER": "$(AspNetCoreModuleV2OutOfProcessHandlerDll)",
|
"ASPNETCORE_MODULE_OUTOFPROCESS_HANDLER": "$(AspNetCoreModuleV2OutOfProcessHandlerDll)",
|
||||||
"LAUNCHER_ARGS": "$(TargetPath)",
|
"LAUNCHER_ARGS": "$(TargetPath)",
|
||||||
"ASPNETCORE_ENVIRONMENT": "Development",
|
"ASPNETCORE_ENVIRONMENT": "Development",
|
||||||
"LAUNCHER_PATH": "$(DotNetPath)",
|
"LAUNCHER_PATH": "$(DotNetPath)",
|
||||||
|
|
|
||||||
|
|
@ -6,9 +6,12 @@ using System.Linq;
|
||||||
using Microsoft.AspNetCore.Authentication;
|
using Microsoft.AspNetCore.Authentication;
|
||||||
using Microsoft.AspNetCore.Builder;
|
using Microsoft.AspNetCore.Builder;
|
||||||
using Microsoft.AspNetCore.Hosting;
|
using Microsoft.AspNetCore.Hosting;
|
||||||
|
using Microsoft.AspNetCore.Hosting.Server;
|
||||||
|
using Microsoft.AspNetCore.Hosting.Server.Features;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Http.Features;
|
using Microsoft.AspNetCore.Http.Features;
|
||||||
using Microsoft.AspNetCore.Server.IIS;
|
using Microsoft.AspNetCore.Server.IIS;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
namespace NativeIISSample
|
namespace NativeIISSample
|
||||||
{
|
{
|
||||||
|
|
@ -89,6 +92,13 @@ namespace NativeIISSample
|
||||||
{
|
{
|
||||||
await context.Response.WriteAsync("Websocket feature is disabled.");
|
await context.Response.WriteAsync("Websocket feature is disabled.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await context.Response.WriteAsync(Environment.NewLine);
|
||||||
|
var addresses = context.RequestServices.GetService<IServer>().Features.Get<IServerAddressesFeature>();
|
||||||
|
foreach (var key in addresses.Addresses)
|
||||||
|
{
|
||||||
|
await context.Response.WriteAsync(key + Environment.NewLine);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -36,10 +36,11 @@ public:
|
||||||
{
|
{
|
||||||
// m_location.data() is const ptr copy to local to get mutable pointer
|
// m_location.data() is const ptr copy to local to get mutable pointer
|
||||||
auto location = m_location;
|
auto location = m_location;
|
||||||
std::array<APPLICATION_PARAMETER, 2> parameters {
|
std::array<APPLICATION_PARAMETER, 3> parameters {
|
||||||
{
|
{
|
||||||
{"InProcessExeLocation", location.data()},
|
{"InProcessExeLocation", location.data()},
|
||||||
{"TraceContext", pHttpContext->GetTraceContext()}
|
{"TraceContext", pHttpContext->GetTraceContext()},
|
||||||
|
{"Site", pHttpContext->GetSite()}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,133 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include "ConfigurationSource.h"
|
||||||
|
#include "StringHelpers.h"
|
||||||
|
#include "WebConfigConfigurationSource.h"
|
||||||
|
|
||||||
|
#define CS_SITE_SECTION L"system.applicationHost/sites"
|
||||||
|
#define CS_SITE_NAME L"name"
|
||||||
|
#define CS_SITE_BINDINGS L"bindings"
|
||||||
|
#define CS_SITE_BINDING_INFORMATION L"bindingInformation"
|
||||||
|
#define CS_SITE_BINDING_INFORMATION_ALL_HOSTS L"*"
|
||||||
|
#define CS_SITE_BINDING_PROTOCOL L"protocol"
|
||||||
|
#define CS_SITE_BINDING_PROTOCOL_HTTPS L"https"
|
||||||
|
#define CS_SITE_BINDING_INFORMATION_DELIMITER L':'
|
||||||
|
|
||||||
|
class BindingInformation
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
BindingInformation(std::wstring protocol, std::wstring host, std::wstring port)
|
||||||
|
{
|
||||||
|
m_protocol = protocol;
|
||||||
|
m_host = host;
|
||||||
|
m_port = port;
|
||||||
|
}
|
||||||
|
|
||||||
|
BindingInformation(std::wstring protocol, std::wstring bindingInformation)
|
||||||
|
{
|
||||||
|
// Expected format:
|
||||||
|
// IP:PORT:HOST
|
||||||
|
// where IP or HOST can be empty
|
||||||
|
|
||||||
|
m_protocol = protocol;
|
||||||
|
|
||||||
|
const auto portStart = bindingInformation.find(CS_SITE_BINDING_INFORMATION_DELIMITER) + 1;
|
||||||
|
const auto lastColon = bindingInformation.find_last_of(CS_SITE_BINDING_INFORMATION_DELIMITER);
|
||||||
|
auto const hostStart = lastColon + 1;
|
||||||
|
m_host = bindingInformation.substr(hostStart, bindingInformation.length() - hostStart);
|
||||||
|
if (m_host.length() == 0)
|
||||||
|
{
|
||||||
|
m_host = CS_SITE_BINDING_INFORMATION_ALL_HOSTS;
|
||||||
|
}
|
||||||
|
m_port = bindingInformation.substr(portStart, lastColon - portStart);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::wstring& QueryProtocol()
|
||||||
|
{
|
||||||
|
return m_protocol;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::wstring& QueryPort()
|
||||||
|
{
|
||||||
|
return m_port;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::wstring& QueryHost()
|
||||||
|
{
|
||||||
|
return m_host;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
std::vector<BindingInformation>
|
||||||
|
Load(const ConfigurationSource &configurationSource, const IHttpSite& pSite)
|
||||||
|
{
|
||||||
|
std::vector<BindingInformation> items;
|
||||||
|
|
||||||
|
const std::wstring runningSiteName = pSite.GetSiteName();
|
||||||
|
|
||||||
|
auto const siteSection = configurationSource.GetRequiredSection(CS_SITE_SECTION);
|
||||||
|
auto sites = siteSection->GetCollection();
|
||||||
|
for (const auto& site: sites)
|
||||||
|
{
|
||||||
|
auto siteName = site->GetRequiredString(CS_SITE_NAME);
|
||||||
|
if (equals_ignore_case(runningSiteName, siteName))
|
||||||
|
{
|
||||||
|
auto bindings = site->GetRequiredSection(CS_SITE_BINDINGS)->GetCollection();
|
||||||
|
for (const auto& binding : bindings)
|
||||||
|
{
|
||||||
|
items.emplace_back(
|
||||||
|
binding->GetRequiredString(CS_SITE_BINDING_PROTOCOL),
|
||||||
|
binding->GetRequiredString(CS_SITE_BINDING_INFORMATION)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
std::wstring Format(const std::vector<BindingInformation> & bindings, const std::wstring & basePath)
|
||||||
|
{
|
||||||
|
std::wstring result;
|
||||||
|
|
||||||
|
for (auto binding : bindings)
|
||||||
|
{
|
||||||
|
result += binding.QueryProtocol() + L"://" + binding.QueryHost() + L":" + binding.QueryPort() + basePath + L";";
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
std::wstring GetHttpsPort(const std::vector<BindingInformation> & bindings)
|
||||||
|
{
|
||||||
|
std::wstring selectedPort;
|
||||||
|
for (auto binding : bindings)
|
||||||
|
{
|
||||||
|
if (equals_ignore_case(binding.QueryProtocol(), CS_SITE_BINDING_PROTOCOL_HTTPS))
|
||||||
|
{
|
||||||
|
const auto bindingPort = binding.QueryPort();
|
||||||
|
if (selectedPort.empty())
|
||||||
|
{
|
||||||
|
selectedPort = binding.QueryPort();
|
||||||
|
}
|
||||||
|
else if (selectedPort != bindingPort)
|
||||||
|
{
|
||||||
|
// If there are multiple endpoints configured return empty port
|
||||||
|
return L"";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return selectedPort;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::wstring m_protocol;
|
||||||
|
std::wstring m_port;
|
||||||
|
std::wstring m_host;
|
||||||
|
};
|
||||||
|
|
@ -200,6 +200,7 @@
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="application.h" />
|
<ClInclude Include="application.h" />
|
||||||
<ClInclude Include="baseoutputmanager.h" />
|
<ClInclude Include="baseoutputmanager.h" />
|
||||||
|
<ClInclude Include="BindingInformation.h" />
|
||||||
<ClInclude Include="ConfigurationSection.h" />
|
<ClInclude Include="ConfigurationSection.h" />
|
||||||
<ClInclude Include="ConfigurationSource.h" />
|
<ClInclude Include="ConfigurationSource.h" />
|
||||||
<ClInclude Include="config_utility.h" />
|
<ClInclude Include="config_utility.h" />
|
||||||
|
|
|
||||||
|
|
@ -51,6 +51,28 @@ void ConfigurationSection::ThrowRequiredException(const std::wstring& name)
|
||||||
throw ConfigurationLoadException(format(L"Attribute '%s' is required.", name.c_str()));
|
throw ConfigurationLoadException(format(L"Attribute '%s' is required.", name.c_str()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<std::pair<std::wstring, std::wstring>> ConfigurationSection::GetKeyValuePairs(const std::wstring& name) const
|
||||||
|
{
|
||||||
|
std::vector<std::pair<std::wstring, std::wstring>> pairs;
|
||||||
|
|
||||||
|
for (auto const element : GetRequiredSection(name)->GetCollection())
|
||||||
|
{
|
||||||
|
pairs.emplace_back(element->GetRequiredString(CS_ASPNETCORE_COLLECTION_ITEM_NAME),
|
||||||
|
element->GetString(CS_ASPNETCORE_COLLECTION_ITEM_VALUE).value_or(L""));
|
||||||
|
}
|
||||||
|
return pairs;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<ConfigurationSection> ConfigurationSection::GetRequiredSection(const std::wstring& name) const
|
||||||
|
{
|
||||||
|
auto section = GetSection(name);
|
||||||
|
if (!section)
|
||||||
|
{
|
||||||
|
throw ConfigurationLoadException(format(L"Unable to get required configuration section '%s'. Possible reason is web.config authoring error.", name.c_str()));
|
||||||
|
}
|
||||||
|
return section.value();
|
||||||
|
}
|
||||||
|
|
||||||
std::optional<std::wstring> find_element(const std::vector<std::pair<std::wstring, std::wstring>>& pairs, const std::wstring& name)
|
std::optional<std::wstring> find_element(const std::vector<std::pair<std::wstring, std::wstring>>& pairs, const std::wstring& name)
|
||||||
{
|
{
|
||||||
const auto iter = std::find_if(
|
const auto iter = std::find_if(
|
||||||
|
|
|
||||||
|
|
@ -37,12 +37,17 @@ public:
|
||||||
virtual std::optional<DWORD> GetLong(const std::wstring& name) const = 0;
|
virtual std::optional<DWORD> GetLong(const std::wstring& name) const = 0;
|
||||||
virtual std::optional<DWORD> GetTimespan(const std::wstring& name) const = 0;
|
virtual std::optional<DWORD> GetTimespan(const std::wstring& name) const = 0;
|
||||||
|
|
||||||
|
virtual std::optional<std::shared_ptr<ConfigurationSection>> GetSection(const std::wstring& name) const = 0;
|
||||||
|
virtual std::vector<std::shared_ptr<ConfigurationSection>> GetCollection() const = 0;
|
||||||
|
|
||||||
std::wstring GetRequiredString(const std::wstring& name) const;
|
std::wstring GetRequiredString(const std::wstring& name) const;
|
||||||
bool GetRequiredBool(const std::wstring& name) const;
|
bool GetRequiredBool(const std::wstring& name) const;
|
||||||
DWORD GetRequiredLong(const std::wstring& name) const;
|
DWORD GetRequiredLong(const std::wstring& name) const;
|
||||||
DWORD GetRequiredTimespan(const std::wstring& name) const;
|
DWORD GetRequiredTimespan(const std::wstring& name) const;
|
||||||
|
|
||||||
virtual std::vector<std::pair<std::wstring, std::wstring>> GetKeyValuePairs(const std::wstring& name) const = 0;
|
virtual std::vector<std::pair<std::wstring, std::wstring>> GetKeyValuePairs(const std::wstring& name) const;
|
||||||
|
|
||||||
|
virtual std::shared_ptr<ConfigurationSection> GetRequiredSection(const std::wstring & name) const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
static void ThrowRequiredException(const std::wstring& name);
|
static void ThrowRequiredException(const std::wstring& name);
|
||||||
|
|
|
||||||
|
|
@ -50,43 +50,38 @@ std::optional<DWORD> WebConfigConfigurationSection::GetTimespan(const std::wstri
|
||||||
return std::make_optional(static_cast<DWORD>(result / 10000ull));
|
return std::make_optional(static_cast<DWORD>(result / 10000ull));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::pair<std::wstring, std::wstring>> WebConfigConfigurationSection::GetKeyValuePairs(const std::wstring& name) const
|
std::optional<std::shared_ptr<ConfigurationSection>> WebConfigConfigurationSection::GetSection(const std::wstring& name) const
|
||||||
{
|
{
|
||||||
std::vector<std::pair<std::wstring, std::wstring>> pairs;
|
CComPtr<IAppHostElement> element = nullptr;
|
||||||
|
|
||||||
|
if (FAILED_LOG(GetElementChildByName(m_element, name.c_str(), &element)))
|
||||||
|
{
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::make_optional(std::make_shared<WebConfigConfigurationSection>(element.Detach()));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::shared_ptr<ConfigurationSection>> WebConfigConfigurationSection::GetCollection() const
|
||||||
|
{
|
||||||
|
std::vector<std::shared_ptr<ConfigurationSection>> elements;
|
||||||
HRESULT findElementResult;
|
HRESULT findElementResult;
|
||||||
CComPtr<IAppHostElement> element = nullptr;
|
|
||||||
CComPtr<IAppHostElementCollection> elementCollection = nullptr;
|
CComPtr<IAppHostElementCollection> elementCollection = nullptr;
|
||||||
CComPtr<IAppHostElement> collectionEntry = nullptr;
|
CComPtr<IAppHostElement> collectionEntry = nullptr;
|
||||||
ENUM_INDEX index{};
|
ENUM_INDEX index{};
|
||||||
|
|
||||||
if (FAILED_LOG(GetElementChildByName(m_element, name.c_str(), &element)))
|
THROW_IF_FAILED(m_element->get_Collection(&elementCollection));
|
||||||
{
|
|
||||||
return pairs;
|
|
||||||
}
|
|
||||||
|
|
||||||
THROW_IF_FAILED(element->get_Collection(&elementCollection));
|
|
||||||
THROW_IF_FAILED(findElementResult = FindFirstElement(elementCollection, &index, &collectionEntry));
|
THROW_IF_FAILED(findElementResult = FindFirstElement(elementCollection, &index, &collectionEntry));
|
||||||
|
|
||||||
while (findElementResult != S_FALSE)
|
while (findElementResult != S_FALSE)
|
||||||
{
|
{
|
||||||
CComBSTR strHandlerName;
|
|
||||||
if (LOG_IF_FAILED(GetElementStringProperty(collectionEntry, CS_ASPNETCORE_COLLECTION_ITEM_NAME, &strHandlerName.m_str)))
|
|
||||||
{
|
|
||||||
ThrowRequiredException(CS_ASPNETCORE_COLLECTION_ITEM_NAME);
|
|
||||||
}
|
|
||||||
|
|
||||||
CComBSTR strHandlerValue;
|
elements.emplace_back(std::make_shared<WebConfigConfigurationSection>(collectionEntry.Detach()));
|
||||||
if (LOG_IF_FAILED(GetElementStringProperty(collectionEntry, CS_ASPNETCORE_COLLECTION_ITEM_VALUE, &strHandlerValue.m_str)))
|
|
||||||
{
|
|
||||||
ThrowRequiredException(CS_ASPNETCORE_COLLECTION_ITEM_VALUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
pairs.emplace_back(strHandlerName, strHandlerValue);
|
|
||||||
|
|
||||||
collectionEntry.Release();
|
collectionEntry.Release();
|
||||||
|
|
||||||
THROW_IF_FAILED(findElementResult = FindNextElement(elementCollection, &index, &collectionEntry));
|
THROW_IF_FAILED(findElementResult = FindNextElement(elementCollection, &index, &collectionEntry));
|
||||||
}
|
}
|
||||||
|
|
||||||
return pairs;
|
return elements;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,8 @@ public:
|
||||||
std::optional<bool> GetBool(const std::wstring& name) const override;
|
std::optional<bool> GetBool(const std::wstring& name) const override;
|
||||||
std::optional<DWORD> GetLong(const std::wstring& name) const override;
|
std::optional<DWORD> GetLong(const std::wstring& name) const override;
|
||||||
std::optional<DWORD> GetTimespan(const std::wstring& name) const override;
|
std::optional<DWORD> GetTimespan(const std::wstring& name) const override;
|
||||||
std::vector<std::pair<std::wstring, std::wstring>> GetKeyValuePairs(const std::wstring& name) const override;
|
std::optional<std::shared_ptr<ConfigurationSection>> GetSection(const std::wstring& name) const override;
|
||||||
|
std::vector<std::shared_ptr<ConfigurationSection>> GetCollection() const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
CComPtr<IAppHostElement> m_element;
|
CComPtr<IAppHostElement> m_element;
|
||||||
|
|
|
||||||
|
|
@ -7,13 +7,14 @@
|
||||||
|
|
||||||
HRESULT InProcessOptions::Create(
|
HRESULT InProcessOptions::Create(
|
||||||
IHttpServer& pServer,
|
IHttpServer& pServer,
|
||||||
|
IHttpSite* site,
|
||||||
IHttpApplication& pHttpApplication,
|
IHttpApplication& pHttpApplication,
|
||||||
std::unique_ptr<InProcessOptions>& options)
|
std::unique_ptr<InProcessOptions>& options)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
const WebConfigConfigurationSource configurationSource(pServer.GetAdminManager(), pHttpApplication);
|
const WebConfigConfigurationSource configurationSource(pServer.GetAdminManager(), pHttpApplication);
|
||||||
options = std::make_unique<InProcessOptions>(configurationSource);
|
options = std::make_unique<InProcessOptions>(configurationSource, site);
|
||||||
}
|
}
|
||||||
catch (InvalidOperationException& ex)
|
catch (InvalidOperationException& ex)
|
||||||
{
|
{
|
||||||
|
|
@ -38,7 +39,7 @@ HRESULT InProcessOptions::Create(
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
InProcessOptions::InProcessOptions(const ConfigurationSource &configurationSource) :
|
InProcessOptions::InProcessOptions(const ConfigurationSource &configurationSource, IHttpSite* pSite) :
|
||||||
m_fStdoutLogEnabled(false),
|
m_fStdoutLogEnabled(false),
|
||||||
m_fWindowsAuthEnabled(false),
|
m_fWindowsAuthEnabled(false),
|
||||||
m_fBasicAuthEnabled(false),
|
m_fBasicAuthEnabled(false),
|
||||||
|
|
@ -68,4 +69,9 @@ InProcessOptions::InProcessOptions(const ConfigurationSource &configurationSourc
|
||||||
|
|
||||||
const auto anonAuthSection = configurationSource.GetSection(CS_ANONYMOUS_AUTHENTICATION_SECTION);
|
const auto anonAuthSection = configurationSource.GetSection(CS_ANONYMOUS_AUTHENTICATION_SECTION);
|
||||||
m_fAnonymousAuthEnabled = anonAuthSection && anonAuthSection->GetBool(CS_ENABLED).value_or(false);
|
m_fAnonymousAuthEnabled = anonAuthSection && anonAuthSection->GetBool(CS_ENABLED).value_or(false);
|
||||||
|
|
||||||
|
if (pSite != nullptr)
|
||||||
|
{
|
||||||
|
m_bindingInformation = BindingInformation::Load(configurationSource, *pSite);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include "BindingInformation.h"
|
||||||
#include "ConfigurationSource.h"
|
#include "ConfigurationSource.h"
|
||||||
#include "WebConfigConfigurationSource.h"
|
#include "WebConfigConfigurationSource.h"
|
||||||
|
|
||||||
|
|
@ -92,11 +93,18 @@ public:
|
||||||
return m_environmentVariables;
|
return m_environmentVariables;
|
||||||
}
|
}
|
||||||
|
|
||||||
InProcessOptions(const ConfigurationSource &configurationSource);
|
const std::vector<BindingInformation>&
|
||||||
|
QueryBindings() const
|
||||||
|
{
|
||||||
|
return m_bindingInformation;
|
||||||
|
}
|
||||||
|
|
||||||
|
InProcessOptions(const ConfigurationSource &configurationSource, IHttpSite* pSite);
|
||||||
|
|
||||||
static
|
static
|
||||||
HRESULT InProcessOptions::Create(
|
HRESULT InProcessOptions::Create(
|
||||||
IHttpServer& pServer,
|
IHttpServer& pServer,
|
||||||
|
IHttpSite* site,
|
||||||
IHttpApplication& pHttpApplication,
|
IHttpApplication& pHttpApplication,
|
||||||
std::unique_ptr<InProcessOptions>& options);
|
std::unique_ptr<InProcessOptions>& options);
|
||||||
|
|
||||||
|
|
@ -113,6 +121,7 @@ private:
|
||||||
DWORD m_dwStartupTimeLimitInMS;
|
DWORD m_dwStartupTimeLimitInMS;
|
||||||
DWORD m_dwShutdownTimeLimitInMS;
|
DWORD m_dwShutdownTimeLimitInMS;
|
||||||
std::vector<std::pair<std::wstring, std::wstring>> m_environmentVariables;
|
std::vector<std::pair<std::wstring, std::wstring>> m_environmentVariables;
|
||||||
|
std::vector<BindingInformation> m_bindingInformation;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
InProcessOptions() = default;
|
InProcessOptions() = default;
|
||||||
|
|
|
||||||
|
|
@ -100,6 +100,8 @@ CreateApplication(
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
TraceContextScope traceScope(FindParameter<IHttpTraceContext*>("TraceContext", pParameters, nParameters));
|
TraceContextScope traceScope(FindParameter<IHttpTraceContext*>("TraceContext", pParameters, nParameters));
|
||||||
|
const auto pSite = FindParameter<IHttpSite*>("Site", pParameters, nParameters);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
HRESULT hr = S_OK;
|
HRESULT hr = S_OK;
|
||||||
|
|
@ -117,14 +119,14 @@ CreateApplication(
|
||||||
g_fInProcessApplicationCreated = true;
|
g_fInProcessApplicationCreated = true;
|
||||||
|
|
||||||
std::unique_ptr<IN_PROCESS_APPLICATION, IAPPLICATION_DELETER> inProcessApplication;
|
std::unique_ptr<IN_PROCESS_APPLICATION, IAPPLICATION_DELETER> inProcessApplication;
|
||||||
if (!FAILED_LOG(hr = IN_PROCESS_APPLICATION::Start(*pServer, *pHttpApplication, pParameters, nParameters, inProcessApplication)))
|
if (!FAILED_LOG(hr = IN_PROCESS_APPLICATION::Start(*pServer, pSite, *pHttpApplication, pParameters, nParameters, inProcessApplication)))
|
||||||
{
|
{
|
||||||
*ppApplication = inProcessApplication.release();
|
*ppApplication = inProcessApplication.release();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
std::unique_ptr<InProcessOptions> options;
|
std::unique_ptr<InProcessOptions> options;
|
||||||
THROW_IF_FAILED(InProcessOptions::Create(*pServer, *pHttpApplication, options));
|
THROW_IF_FAILED(InProcessOptions::Create(*pServer, pSite, *pHttpApplication, options));
|
||||||
// Set the currently running application to a fake application that returns startup exceptions.
|
// Set the currently running application to a fake application that returns startup exceptions.
|
||||||
auto pErrorApplication = std::make_unique<StartupExceptionApplication>(*pServer, *pHttpApplication, g_hServerModule, options->QueryDisableStartUpErrorPage(), hr);
|
auto pErrorApplication = std::make_unique<StartupExceptionApplication>(*pServer, *pHttpApplication, g_hServerModule, options->QueryDisableStartUpErrorPage(), hr);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -344,6 +344,7 @@ void IN_PROCESS_APPLICATION::QueueStop()
|
||||||
|
|
||||||
HRESULT IN_PROCESS_APPLICATION::Start(
|
HRESULT IN_PROCESS_APPLICATION::Start(
|
||||||
IHttpServer& pServer,
|
IHttpServer& pServer,
|
||||||
|
IHttpSite* pSite,
|
||||||
IHttpApplication& pHttpApplication,
|
IHttpApplication& pHttpApplication,
|
||||||
APPLICATION_PARAMETER* pParameters,
|
APPLICATION_PARAMETER* pParameters,
|
||||||
DWORD nParameters,
|
DWORD nParameters,
|
||||||
|
|
@ -352,7 +353,7 @@ HRESULT IN_PROCESS_APPLICATION::Start(
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
std::unique_ptr<InProcessOptions> options;
|
std::unique_ptr<InProcessOptions> options;
|
||||||
THROW_IF_FAILED(InProcessOptions::Create(pServer, pHttpApplication, options));
|
THROW_IF_FAILED(InProcessOptions::Create(pServer, pSite, pHttpApplication, options));
|
||||||
application = std::unique_ptr<IN_PROCESS_APPLICATION, IAPPLICATION_DELETER>(
|
application = std::unique_ptr<IN_PROCESS_APPLICATION, IAPPLICATION_DELETER>(
|
||||||
new IN_PROCESS_APPLICATION(pServer, pHttpApplication, std::move(options), pParameters, nParameters));
|
new IN_PROCESS_APPLICATION(pServer, pHttpApplication, std::move(options), pParameters, nParameters));
|
||||||
THROW_IF_FAILED(application->LoadManagedApplication());
|
THROW_IF_FAILED(application->LoadManagedApplication());
|
||||||
|
|
@ -444,6 +445,7 @@ IN_PROCESS_APPLICATION::SetEnvironmentVariablesOnWorkerProcess()
|
||||||
m_pConfig->QueryBasicAuthEnabled(),
|
m_pConfig->QueryBasicAuthEnabled(),
|
||||||
m_pConfig->QueryAnonymousAuthEnabled(),
|
m_pConfig->QueryAnonymousAuthEnabled(),
|
||||||
QueryApplicationPhysicalPath().c_str(),
|
QueryApplicationPhysicalPath().c_str(),
|
||||||
|
nullptr, /* pHttpsPort */
|
||||||
&pHashTable));
|
&pHashTable));
|
||||||
|
|
||||||
table.reset(pHashTable);
|
table.reset(pHashTable);
|
||||||
|
|
|
||||||
|
|
@ -104,6 +104,7 @@ public:
|
||||||
static
|
static
|
||||||
HRESULT Start(
|
HRESULT Start(
|
||||||
IHttpServer& pServer,
|
IHttpServer& pServer,
|
||||||
|
IHttpSite* pSite,
|
||||||
IHttpApplication& pHttpApplication,
|
IHttpApplication& pHttpApplication,
|
||||||
APPLICATION_PARAMETER* pParameters,
|
APPLICATION_PARAMETER* pParameters,
|
||||||
DWORD nParameters,
|
DWORD nParameters,
|
||||||
|
|
|
||||||
|
|
@ -185,6 +185,7 @@ struct IISConfigurationData
|
||||||
BOOL fWindowsAuthEnabled;
|
BOOL fWindowsAuthEnabled;
|
||||||
BOOL fBasicAuthEnabled;
|
BOOL fBasicAuthEnabled;
|
||||||
BOOL fAnonymousAuthEnable;
|
BOOL fAnonymousAuthEnable;
|
||||||
|
BSTR pwzBindings;
|
||||||
};
|
};
|
||||||
|
|
||||||
EXTERN_C __MIDL_DECLSPEC_DLLEXPORT
|
EXTERN_C __MIDL_DECLSPEC_DLLEXPORT
|
||||||
|
|
@ -208,6 +209,8 @@ http_get_application_properties(
|
||||||
pIISCofigurationData->fBasicAuthEnabled = pConfiguration.QueryBasicAuthEnabled();
|
pIISCofigurationData->fBasicAuthEnabled = pConfiguration.QueryBasicAuthEnabled();
|
||||||
pIISCofigurationData->fAnonymousAuthEnable = pConfiguration.QueryAnonymousAuthEnabled();
|
pIISCofigurationData->fAnonymousAuthEnable = pConfiguration.QueryAnonymousAuthEnabled();
|
||||||
|
|
||||||
|
auto const serverAddresses = BindingInformation::Format(pConfiguration.QueryBindings(), pInProcessApplication->QueryApplicationVirtualPath());
|
||||||
|
pIISCofigurationData->pwzBindings = SysAllocString(serverAddresses.c_str());
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -251,11 +251,12 @@ CreateApplication(
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
TraceContextScope traceScope(FindParameter<IHttpTraceContext*>("TraceContext", pParameters, nParameters));
|
TraceContextScope traceScope(FindParameter<IHttpTraceContext*>("TraceContext", pParameters, nParameters));
|
||||||
|
auto pSite = FindParameter<IHttpSite*>("Site", pParameters, nParameters);
|
||||||
|
|
||||||
InitializeGlobalConfiguration(pServer);
|
InitializeGlobalConfiguration(pServer);
|
||||||
|
|
||||||
REQUESTHANDLER_CONFIG *pConfig = nullptr;
|
REQUESTHANDLER_CONFIG *pConfig = nullptr;
|
||||||
RETURN_IF_FAILED(REQUESTHANDLER_CONFIG::CreateRequestHandlerConfig(pServer, pHttpApplication, &pConfig));
|
RETURN_IF_FAILED(REQUESTHANDLER_CONFIG::CreateRequestHandlerConfig(pServer, pSite, pHttpApplication, &pConfig));
|
||||||
std::unique_ptr<REQUESTHANDLER_CONFIG> pRequestHandlerConfig(pConfig);
|
std::unique_ptr<REQUESTHANDLER_CONFIG> pRequestHandlerConfig(pConfig);
|
||||||
|
|
||||||
RETURN_IF_FAILED(EnsureOutOfProcessInitializtion(pHttpApplication));
|
RETURN_IF_FAILED(EnsureOutOfProcessInitializtion(pHttpApplication));
|
||||||
|
|
|
||||||
|
|
@ -162,7 +162,8 @@ PROCESS_MANAGER::GetProcess(
|
||||||
pConfig->QueryStdoutLogFile(),
|
pConfig->QueryStdoutLogFile(),
|
||||||
pConfig->QueryApplicationPhysicalPath(), // physical path
|
pConfig->QueryApplicationPhysicalPath(), // physical path
|
||||||
pConfig->QueryApplicationPath(), // app path
|
pConfig->QueryApplicationPath(), // app path
|
||||||
pConfig->QueryApplicationVirtualPath() // App relative virtual path
|
pConfig->QueryApplicationVirtualPath(), // App relative virtual path,
|
||||||
|
pConfig->QueryBindings()
|
||||||
));
|
));
|
||||||
RETURN_IF_FAILED(pSelectedServerProcess->StartProcess());
|
RETURN_IF_FAILED(pSelectedServerProcess->StartProcess());
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,8 @@ SERVER_PROCESS::Initialize(
|
||||||
STRU *pstruStdoutLogFile,
|
STRU *pstruStdoutLogFile,
|
||||||
STRU *pszAppPhysicalPath,
|
STRU *pszAppPhysicalPath,
|
||||||
STRU *pszAppPath,
|
STRU *pszAppPath,
|
||||||
STRU *pszAppVirtualPath
|
STRU *pszAppVirtualPath,
|
||||||
|
STRU *pszHttpsPort
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
HRESULT hr = S_OK;
|
HRESULT hr = S_OK;
|
||||||
|
|
@ -52,6 +53,7 @@ SERVER_PROCESS::Initialize(
|
||||||
FAILED_LOG(hr = m_struAppFullPath.Copy(*pszAppPath))||
|
FAILED_LOG(hr = m_struAppFullPath.Copy(*pszAppPath))||
|
||||||
FAILED_LOG(hr = m_struAppVirtualPath.Copy(*pszAppVirtualPath))||
|
FAILED_LOG(hr = m_struAppVirtualPath.Copy(*pszAppVirtualPath))||
|
||||||
FAILED_LOG(hr = m_Arguments.Copy(*pszArguments)) ||
|
FAILED_LOG(hr = m_Arguments.Copy(*pszArguments)) ||
|
||||||
|
FAILED_LOG(hr = m_struHttpsPort.Copy(*pszHttpsPort)) ||
|
||||||
FAILED_LOG(hr = SetupJobObject()))
|
FAILED_LOG(hr = SetupJobObject()))
|
||||||
{
|
{
|
||||||
goto Finished;
|
goto Finished;
|
||||||
|
|
@ -786,6 +788,7 @@ SERVER_PROCESS::StartProcess(
|
||||||
m_fBasicAuthEnabled,
|
m_fBasicAuthEnabled,
|
||||||
m_fAnonymousAuthEnabled,
|
m_fAnonymousAuthEnabled,
|
||||||
m_struAppFullPath.QueryStr(),
|
m_struAppFullPath.QueryStr(),
|
||||||
|
m_struHttpsPort.QueryStr(),
|
||||||
&pHashTable)))
|
&pHashTable)))
|
||||||
{
|
{
|
||||||
pStrStage = L"InitEnvironmentVariablesTable";
|
pStrStage = L"InitEnvironmentVariablesTable";
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,8 @@ public:
|
||||||
_In_ STRU *pstruStdoutLogFile,
|
_In_ STRU *pstruStdoutLogFile,
|
||||||
_In_ STRU *pszAppPhysicalPath,
|
_In_ STRU *pszAppPhysicalPath,
|
||||||
_In_ STRU *pszAppPath,
|
_In_ STRU *pszAppPath,
|
||||||
_In_ STRU *pszAppVirtualPath
|
_In_ STRU *pszAppVirtualPath,
|
||||||
|
_In_ STRU *pszHttpsPort
|
||||||
);
|
);
|
||||||
|
|
||||||
HRESULT
|
HRESULT
|
||||||
|
|
@ -98,7 +99,7 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual
|
virtual
|
||||||
~SERVER_PROCESS();
|
~SERVER_PROCESS();
|
||||||
|
|
||||||
static
|
static
|
||||||
|
|
@ -129,7 +130,7 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
VOID
|
VOID
|
||||||
SendSignal(
|
SendSignal(
|
||||||
VOID
|
VOID
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -142,7 +143,7 @@ private:
|
||||||
VOID
|
VOID
|
||||||
);
|
);
|
||||||
|
|
||||||
BOOL
|
BOOL
|
||||||
IsDebuggerIsAttached(
|
IsDebuggerIsAttached(
|
||||||
VOID
|
VOID
|
||||||
);
|
);
|
||||||
|
|
@ -164,13 +165,13 @@ private:
|
||||||
_Out_ BOOL * pfReady
|
_Out_ BOOL * pfReady
|
||||||
);
|
);
|
||||||
|
|
||||||
HRESULT
|
HRESULT
|
||||||
RegisterProcessWait(
|
RegisterProcessWait(
|
||||||
_In_ PHANDLE phWaitHandle,
|
_In_ PHANDLE phWaitHandle,
|
||||||
_In_ HANDLE hProcessToWaitOn
|
_In_ HANDLE hProcessToWaitOn
|
||||||
);
|
);
|
||||||
|
|
||||||
HRESULT
|
HRESULT
|
||||||
GetChildProcessHandles(
|
GetChildProcessHandles(
|
||||||
VOID
|
VOID
|
||||||
);
|
);
|
||||||
|
|
@ -252,6 +253,7 @@ private:
|
||||||
STRU m_struAppVirtualPath; // e.g., '/' for site
|
STRU m_struAppVirtualPath; // e.g., '/' for site
|
||||||
STRU m_struAppFullPath; // e.g., /LM/W3SVC/4/ROOT/Inproc
|
STRU m_struAppFullPath; // e.g., /LM/W3SVC/4/ROOT/Inproc
|
||||||
STRU m_struPhysicalPath; // e.g., c:/test/mysite
|
STRU m_struPhysicalPath; // e.g., c:/test/mysite
|
||||||
|
STRU m_struHttpsPort; // e.g., /LM/W3SVC/4/ROOT/Inproc
|
||||||
STRU m_struPort;
|
STRU m_struPort;
|
||||||
STRU m_struCommandLine;
|
STRU m_struCommandLine;
|
||||||
|
|
||||||
|
|
@ -281,7 +283,7 @@ private:
|
||||||
HANDLE m_hProcessWaitHandle;
|
HANDLE m_hProcessWaitHandle;
|
||||||
HANDLE m_hShutdownHandle;
|
HANDLE m_hShutdownHandle;
|
||||||
//
|
//
|
||||||
// m_hChildProcessHandle is the handle to process created by
|
// m_hChildProcessHandle is the handle to process created by
|
||||||
// m_hProcessHandle process if it does.
|
// m_hProcessHandle process if it does.
|
||||||
//
|
//
|
||||||
HANDLE m_hChildProcessHandles[MAX_ACTIVE_CHILD_PROCESSES];
|
HANDLE m_hChildProcessHandles[MAX_ACTIVE_CHILD_PROCESSES];
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@
|
||||||
#define ASPNETCORE_IIS_AUTH_ENV_STR L"ASPNETCORE_IIS_HTTPAUTH="
|
#define ASPNETCORE_IIS_AUTH_ENV_STR L"ASPNETCORE_IIS_HTTPAUTH="
|
||||||
#define ASPNETCORE_IIS_WEBSOCKETS_SUPPORTED_ENV_STR L"ASPNETCORE_IIS_WEBSOCKETS_SUPPORTED="
|
#define ASPNETCORE_IIS_WEBSOCKETS_SUPPORTED_ENV_STR L"ASPNETCORE_IIS_WEBSOCKETS_SUPPORTED="
|
||||||
#define ASPNETCORE_IIS_PHYSICAL_PATH_ENV_STR L"ASPNETCORE_IIS_PHYSICAL_PATH="
|
#define ASPNETCORE_IIS_PHYSICAL_PATH_ENV_STR L"ASPNETCORE_IIS_PHYSICAL_PATH="
|
||||||
|
#define ASPNETCORE_HTTPS_PORT_ENV_STR L"ASPNETCORE_HTTPS_PORT="
|
||||||
#define ASPNETCORE_IIS_AUTH_WINDOWS L"windows;"
|
#define ASPNETCORE_IIS_AUTH_WINDOWS L"windows;"
|
||||||
#define ASPNETCORE_IIS_AUTH_BASIC L"basic;"
|
#define ASPNETCORE_IIS_AUTH_BASIC L"basic;"
|
||||||
#define ASPNETCORE_IIS_AUTH_ANONYMOUS L"anonymous;"
|
#define ASPNETCORE_IIS_AUTH_ANONYMOUS L"anonymous;"
|
||||||
|
|
|
||||||
|
|
@ -192,6 +192,7 @@ public:
|
||||||
_In_ BOOL fBasicAuthEnabled,
|
_In_ BOOL fBasicAuthEnabled,
|
||||||
_In_ BOOL fAnonymousAuthEnabled,
|
_In_ BOOL fAnonymousAuthEnabled,
|
||||||
_In_ PCWSTR pApplicationPhysicalPath,
|
_In_ PCWSTR pApplicationPhysicalPath,
|
||||||
|
_In_ PCWSTR pHttpsPort,
|
||||||
_Out_ ENVIRONMENT_VAR_HASH** ppEnvironmentVarTable
|
_Out_ ENVIRONMENT_VAR_HASH** ppEnvironmentVarTable
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
|
@ -203,6 +204,7 @@ public:
|
||||||
ENVIRONMENT_VAR_ENTRY* pHostingEntry = NULL;
|
ENVIRONMENT_VAR_ENTRY* pHostingEntry = NULL;
|
||||||
ENVIRONMENT_VAR_ENTRY* pIISAuthEntry = NULL;
|
ENVIRONMENT_VAR_ENTRY* pIISAuthEntry = NULL;
|
||||||
ENVIRONMENT_VAR_ENTRY* pIISPathEntry = NULL;
|
ENVIRONMENT_VAR_ENTRY* pIISPathEntry = NULL;
|
||||||
|
ENVIRONMENT_VAR_ENTRY* pIISHttpsPort = NULL;
|
||||||
ENVIRONMENT_VAR_HASH* pEnvironmentVarTable = NULL;
|
ENVIRONMENT_VAR_HASH* pEnvironmentVarTable = NULL;
|
||||||
|
|
||||||
pEnvironmentVarTable = new ENVIRONMENT_VAR_HASH();
|
pEnvironmentVarTable = new ENVIRONMENT_VAR_HASH();
|
||||||
|
|
@ -240,6 +242,26 @@ public:
|
||||||
goto Finished;
|
goto Finished;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (pHttpsPort != nullptr)
|
||||||
|
{
|
||||||
|
pEnvironmentVarTable->FindKey((PWSTR)ASPNETCORE_HTTPS_PORT_ENV_STR, &pIISHttpsPort);
|
||||||
|
if (pIISHttpsPort != NULL)
|
||||||
|
{
|
||||||
|
// user defined ASPNETCORE_HTTPS_PORT in configuration, don't override it
|
||||||
|
pIISHttpsPort->Dereference();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pIISHttpsPort = new ENVIRONMENT_VAR_ENTRY();
|
||||||
|
|
||||||
|
if (FAILED(hr = pIISHttpsPort->Initialize(ASPNETCORE_HTTPS_PORT_ENV_STR, pHttpsPort)) ||
|
||||||
|
FAILED(hr = pEnvironmentVarTable->InsertRecord(pIISHttpsPort)))
|
||||||
|
{
|
||||||
|
goto Finished;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pEnvironmentVarTable->FindKey((PWSTR)ASPNETCORE_IIS_AUTH_ENV_STR, &pIISAuthEntry);
|
pEnvironmentVarTable->FindKey((PWSTR)ASPNETCORE_IIS_AUTH_ENV_STR, &pIISAuthEntry);
|
||||||
if (pIISAuthEntry != NULL)
|
if (pIISAuthEntry != NULL)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,6 @@
|
||||||
#include "exceptions.h"
|
#include "exceptions.h"
|
||||||
#include "config_utility.h"
|
#include "config_utility.h"
|
||||||
|
|
||||||
|
|
||||||
REQUESTHANDLER_CONFIG::~REQUESTHANDLER_CONFIG()
|
REQUESTHANDLER_CONFIG::~REQUESTHANDLER_CONFIG()
|
||||||
{
|
{
|
||||||
if (m_ppStrArguments != NULL)
|
if (m_ppStrArguments != NULL)
|
||||||
|
|
@ -28,6 +27,7 @@ REQUESTHANDLER_CONFIG::~REQUESTHANDLER_CONFIG()
|
||||||
HRESULT
|
HRESULT
|
||||||
REQUESTHANDLER_CONFIG::CreateRequestHandlerConfig(
|
REQUESTHANDLER_CONFIG::CreateRequestHandlerConfig(
|
||||||
_In_ IHttpServer *pHttpServer,
|
_In_ IHttpServer *pHttpServer,
|
||||||
|
_In_ IHttpSite *pSite,
|
||||||
_In_ IHttpApplication *pHttpApplication,
|
_In_ IHttpApplication *pHttpApplication,
|
||||||
_Out_ REQUESTHANDLER_CONFIG **ppAspNetCoreConfig
|
_Out_ REQUESTHANDLER_CONFIG **ppAspNetCoreConfig
|
||||||
)
|
)
|
||||||
|
|
@ -49,7 +49,7 @@ REQUESTHANDLER_CONFIG::CreateRequestHandlerConfig(
|
||||||
|
|
||||||
pRequestHandlerConfig = new REQUESTHANDLER_CONFIG;
|
pRequestHandlerConfig = new REQUESTHANDLER_CONFIG;
|
||||||
|
|
||||||
hr = pRequestHandlerConfig->Populate(pHttpServer, pHttpApplication);
|
hr = pRequestHandlerConfig->Populate(pHttpServer, pSite, pHttpApplication);
|
||||||
if (FAILED(hr))
|
if (FAILED(hr))
|
||||||
{
|
{
|
||||||
goto Finished;
|
goto Finished;
|
||||||
|
|
@ -85,6 +85,7 @@ Finished:
|
||||||
HRESULT
|
HRESULT
|
||||||
REQUESTHANDLER_CONFIG::Populate(
|
REQUESTHANDLER_CONFIG::Populate(
|
||||||
IHttpServer *pHttpServer,
|
IHttpServer *pHttpServer,
|
||||||
|
IHttpSite *pSite,
|
||||||
IHttpApplication *pHttpApplication
|
IHttpApplication *pHttpApplication
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
|
@ -122,6 +123,19 @@ REQUESTHANDLER_CONFIG::Populate(
|
||||||
}
|
}
|
||||||
|
|
||||||
pAdminManager = pHttpServer->GetAdminManager();
|
pAdminManager = pHttpServer->GetAdminManager();
|
||||||
|
if (pSite != nullptr)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
WebConfigConfigurationSource source(pAdminManager, *pHttpApplication);
|
||||||
|
m_struHttpsPort.Copy(BindingInformation::GetHttpsPort(BindingInformation::Load(source, *pSite)).c_str());
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
FINISHED_IF_FAILED(OBSERVE_CAUGHT_EXCEPTION());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
hr = m_struConfigPath.Copy(pHttpApplication->GetAppConfigPath());
|
hr = m_struConfigPath.Copy(pHttpApplication->GetAppConfigPath());
|
||||||
if (FAILED(hr))
|
if (FAILED(hr))
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,7 @@
|
||||||
|
|
||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
#include "environmentvariablehash.h"
|
#include "environmentvariablehash.h"
|
||||||
|
#include "BindingInformation.h"
|
||||||
|
|
||||||
enum APP_HOSTING_MODEL
|
enum APP_HOSTING_MODEL
|
||||||
{
|
{
|
||||||
|
|
@ -62,6 +63,7 @@ public:
|
||||||
HRESULT
|
HRESULT
|
||||||
CreateRequestHandlerConfig(
|
CreateRequestHandlerConfig(
|
||||||
_In_ IHttpServer *pHttpServer,
|
_In_ IHttpServer *pHttpServer,
|
||||||
|
_In_ IHttpSite *pSite,
|
||||||
_In_ IHttpApplication *pHttpApplication,
|
_In_ IHttpApplication *pHttpApplication,
|
||||||
_Out_ REQUESTHANDLER_CONFIG **ppAspNetCoreConfig
|
_Out_ REQUESTHANDLER_CONFIG **ppAspNetCoreConfig
|
||||||
);
|
);
|
||||||
|
|
@ -114,6 +116,12 @@ public:
|
||||||
return m_dwRequestTimeoutInMS;
|
return m_dwRequestTimeoutInMS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
STRU*
|
||||||
|
QueryBindings()
|
||||||
|
{
|
||||||
|
return &m_struHttpsPort;
|
||||||
|
}
|
||||||
|
|
||||||
STRU*
|
STRU*
|
||||||
QueryArguments(
|
QueryArguments(
|
||||||
VOID
|
VOID
|
||||||
|
|
@ -226,6 +234,7 @@ protected:
|
||||||
HRESULT
|
HRESULT
|
||||||
Populate(
|
Populate(
|
||||||
IHttpServer *pHttpServer,
|
IHttpServer *pHttpServer,
|
||||||
|
IHttpSite *pSite,
|
||||||
IHttpApplication *pHttpApplication
|
IHttpApplication *pHttpApplication
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -252,5 +261,5 @@ protected:
|
||||||
STRU m_struHostFxrLocation;
|
STRU m_struHostFxrLocation;
|
||||||
PWSTR* m_ppStrArguments;
|
PWSTR* m_ppStrArguments;
|
||||||
DWORD m_dwArgc;
|
DWORD m_dwArgc;
|
||||||
|
STRU m_struHttpsPort;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -17,5 +17,7 @@ namespace Microsoft.AspNetCore.Server.IIS.Core
|
||||||
public bool fWindowsAuthEnabled;
|
public bool fWindowsAuthEnabled;
|
||||||
public bool fBasicAuthEnabled;
|
public bool fBasicAuthEnabled;
|
||||||
public bool fAnonymousAuthEnable;
|
public bool fAnonymousAuthEnable;
|
||||||
|
[MarshalAs(UnmanagedType.BStr)]
|
||||||
|
public string pwzBindings;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Buffers;
|
using System.Buffers;
|
||||||
|
|
@ -10,6 +8,7 @@ using Microsoft.AspNetCore.Authentication;
|
||||||
using Microsoft.AspNetCore.Builder;
|
using Microsoft.AspNetCore.Builder;
|
||||||
using Microsoft.AspNetCore.Hosting;
|
using Microsoft.AspNetCore.Hosting;
|
||||||
using Microsoft.AspNetCore.Hosting.Server;
|
using Microsoft.AspNetCore.Hosting.Server;
|
||||||
|
using Microsoft.AspNetCore.Hosting.Server.Features;
|
||||||
using Microsoft.AspNetCore.Http.Features;
|
using Microsoft.AspNetCore.Http.Features;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
|
|
@ -32,6 +31,7 @@ namespace Microsoft.AspNetCore.Server.IIS.Core
|
||||||
private readonly ILogger<IISHttpServer> _logger;
|
private readonly ILogger<IISHttpServer> _logger;
|
||||||
private readonly IISServerOptions _options;
|
private readonly IISServerOptions _options;
|
||||||
private readonly IISNativeApplication _nativeApplication;
|
private readonly IISNativeApplication _nativeApplication;
|
||||||
|
private readonly ServerAddressesFeature _serverAddressesFeature;
|
||||||
|
|
||||||
private volatile int _stopping;
|
private volatile int _stopping;
|
||||||
private bool Stopping => _stopping == 1;
|
private bool Stopping => _stopping == 1;
|
||||||
|
|
@ -71,11 +71,14 @@ namespace Microsoft.AspNetCore.Server.IIS.Core
|
||||||
_applicationLifetime = applicationLifetime;
|
_applicationLifetime = applicationLifetime;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_options = options.Value;
|
_options = options.Value;
|
||||||
|
_serverAddressesFeature = new ServerAddressesFeature();
|
||||||
|
|
||||||
if (_options.ForwardWindowsAuthentication)
|
if (_options.ForwardWindowsAuthentication)
|
||||||
{
|
{
|
||||||
authentication.AddScheme(new AuthenticationScheme(IISServerDefaults.AuthenticationScheme, _options.AuthenticationDisplayName, typeof(IISServerAuthenticationHandler)));
|
authentication.AddScheme(new AuthenticationScheme(IISServerDefaults.AuthenticationScheme, _options.AuthenticationDisplayName, typeof(IISServerAuthenticationHandler)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Features.Set<IServerAddressesFeature>(_serverAddressesFeature);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task StartAsync<TContext>(IHttpApplication<TContext> application, CancellationToken cancellationToken)
|
public Task StartAsync<TContext>(IHttpApplication<TContext> application, CancellationToken cancellationToken)
|
||||||
|
|
@ -84,6 +87,9 @@ namespace Microsoft.AspNetCore.Server.IIS.Core
|
||||||
|
|
||||||
_iisContextFactory = new IISContextFactory<TContext>(_memoryPool, application, _options, this, _logger);
|
_iisContextFactory = new IISContextFactory<TContext>(_memoryPool, application, _options, this, _logger);
|
||||||
_nativeApplication.RegisterCallbacks(_requestHandler, _shutdownHandler, _onDisconnect, _onAsyncCompletion, (IntPtr)_httpServerHandle, (IntPtr)_httpServerHandle);
|
_nativeApplication.RegisterCallbacks(_requestHandler, _shutdownHandler, _onDisconnect, _onAsyncCompletion, (IntPtr)_httpServerHandle, (IntPtr)_httpServerHandle);
|
||||||
|
|
||||||
|
_serverAddressesFeature.Addresses = _options.ServerAddresses;
|
||||||
|
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,16 +2,18 @@
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using Microsoft.AspNetCore.Builder;
|
using Microsoft.AspNetCore.Builder;
|
||||||
using Microsoft.AspNetCore.Hosting;
|
using Microsoft.AspNetCore.Hosting;
|
||||||
using Microsoft.AspNetCore.Hosting.Server;
|
using Microsoft.AspNetCore.Hosting.Server;
|
||||||
|
using Microsoft.AspNetCore.Hosting.Server.Features;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Server.IIS.Core
|
namespace Microsoft.AspNetCore.Server.IIS.Core
|
||||||
{
|
{
|
||||||
internal class IISServerSetupFilter : IStartupFilter
|
internal class IISServerSetupFilter : IStartupFilter
|
||||||
{
|
{
|
||||||
private string _virtualPath;
|
private readonly string _virtualPath;
|
||||||
|
|
||||||
public IISServerSetupFilter(string virtualPath)
|
public IISServerSetupFilter(string virtualPath)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Microsoft.AspNetCore.Hosting.Server.Features;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Server.IIS.Core
|
||||||
|
{
|
||||||
|
internal class ServerAddressesFeature : IServerAddressesFeature
|
||||||
|
{
|
||||||
|
public ICollection<string> Addresses { get; set; } = Array.Empty<string>();
|
||||||
|
public bool PreferHostingUrls { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -22,5 +22,7 @@ namespace Microsoft.AspNetCore.Builder
|
||||||
/// IIS has a non-anonymous authentication enabled, or for back compat with ANCMs that did not provide this information.
|
/// IIS has a non-anonymous authentication enabled, or for back compat with ANCMs that did not provide this information.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal bool ForwardWindowsAuthentication { get; set; } = true;
|
internal bool ForwardWindowsAuthentication { get; set; } = true;
|
||||||
|
|
||||||
|
internal string[] ServerAddresses { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,10 @@ namespace Microsoft.AspNetCore.Hosting
|
||||||
services.AddSingleton<IStartupFilter>(new IISServerSetupFilter(iisConfigData.pwzVirtualApplicationPath));
|
services.AddSingleton<IStartupFilter>(new IISServerSetupFilter(iisConfigData.pwzVirtualApplicationPath));
|
||||||
services.AddAuthenticationCore();
|
services.AddAuthenticationCore();
|
||||||
services.Configure<IISServerOptions>(
|
services.Configure<IISServerOptions>(
|
||||||
options => { options.ForwardWindowsAuthentication = iisConfigData.fWindowsAuthEnabled || iisConfigData.fBasicAuthEnabled; }
|
options => {
|
||||||
|
options.ServerAddresses = iisConfigData.pwzBindings.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
|
||||||
|
options.ForwardWindowsAuthentication = iisConfigData.fWindowsAuthEnabled || iisConfigData.fBasicAuthEnabled;
|
||||||
|
}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,177 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Net.Sockets;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Xml.Linq;
|
||||||
|
using Microsoft.AspNetCore.Server.IIS.FunctionalTests.Utilities;
|
||||||
|
using Microsoft.AspNetCore.Server.IntegrationTesting;
|
||||||
|
using Microsoft.AspNetCore.Server.IntegrationTesting.Common;
|
||||||
|
using Microsoft.AspNetCore.Server.IntegrationTesting.IIS;
|
||||||
|
using Microsoft.AspNetCore.Testing.xunit;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
||||||
|
{
|
||||||
|
[Collection(PublishedSitesCollection.Name)]
|
||||||
|
public class HttpsTests : IISFunctionalTestBase
|
||||||
|
{
|
||||||
|
private readonly PublishedSitesFixture _fixture;
|
||||||
|
|
||||||
|
public HttpsTests(PublishedSitesFixture fixture)
|
||||||
|
{
|
||||||
|
_fixture = fixture;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TestMatrix TestVariants
|
||||||
|
=> TestMatrix.ForServers(DeployerSelector.ServerType)
|
||||||
|
.WithTfms(Tfm.NetCoreApp30)
|
||||||
|
.WithAllApplicationTypes()
|
||||||
|
.WithAllAncmVersions()
|
||||||
|
.WithAllHostingModels();
|
||||||
|
|
||||||
|
[ConditionalTheory]
|
||||||
|
[MemberData(nameof(TestVariants))]
|
||||||
|
public async Task HttpsHelloWorld(TestVariant variant)
|
||||||
|
{
|
||||||
|
var port = TestPortHelper.GetNextSSLPort();
|
||||||
|
var deploymentParameters = _fixture.GetBaseDeploymentParameters(variant);
|
||||||
|
deploymentParameters.ApplicationBaseUriHint = $"https://localhost:{port}/";
|
||||||
|
deploymentParameters.AddHttpsToServerConfig();
|
||||||
|
|
||||||
|
var deploymentResult = await DeployAsync(deploymentParameters);
|
||||||
|
|
||||||
|
var handler = new HttpClientHandler
|
||||||
|
{
|
||||||
|
ServerCertificateCustomValidationCallback = (a, b, c, d) => true
|
||||||
|
};
|
||||||
|
var client = deploymentResult.CreateClient(handler);
|
||||||
|
var response = await client.GetAsync("HttpsHelloWorld");
|
||||||
|
var responseText = await response.Content.ReadAsStringAsync();
|
||||||
|
if (variant.HostingModel == HostingModel.OutOfProcess)
|
||||||
|
{
|
||||||
|
Assert.Equal("Scheme:https; Original:http", responseText);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Assert.Equal("Scheme:https; Original:", responseText);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (variant.AncmVersion == AncmVersion.AspNetCoreModuleV2 &&
|
||||||
|
DeployerSelector.HasNewHandler &&
|
||||||
|
DeployerSelector.HasNewShim)
|
||||||
|
{
|
||||||
|
// We expect ServerAddress to be set for InProcess and HTTPS_PORT for OutOfProcess
|
||||||
|
if (variant.HostingModel == HostingModel.InProcess)
|
||||||
|
{
|
||||||
|
Assert.Equal(deploymentParameters.ApplicationBaseUriHint, await client.GetStringAsync("/ServerAddresses"));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Assert.Equal(port.ToString(), await client.GetStringAsync("/HTTPS_PORT"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[ConditionalFact]
|
||||||
|
[RequiresNewHandler]
|
||||||
|
[RequiresNewShim]
|
||||||
|
public async Task ServerAddressesIncludesBaseAddress()
|
||||||
|
{
|
||||||
|
var appName = "\u041C\u043E\u0451\u041F\u0440\u0438\u043B\u043E\u0436\u0435\u043D\u0438\u0435";
|
||||||
|
|
||||||
|
var port = TestPortHelper.GetNextSSLPort();
|
||||||
|
var deploymentParameters = _fixture.GetBaseDeploymentParameters(HostingModel.InProcess, publish: true);
|
||||||
|
deploymentParameters.ApplicationBaseUriHint = $"https://localhost:{port}/";
|
||||||
|
deploymentParameters.AddHttpsToServerConfig();
|
||||||
|
deploymentParameters.AddServerConfigAction(
|
||||||
|
(element, root) => {
|
||||||
|
element.Descendants("site").Single().Element("application").SetAttributeValue("path", "/" + appName);
|
||||||
|
Helpers.CreateEmptyApplication(element, root);
|
||||||
|
});
|
||||||
|
|
||||||
|
var deploymentResult = await DeployAsync(deploymentParameters);
|
||||||
|
Assert.Equal(deploymentParameters.ApplicationBaseUriHint + appName, await deploymentResult.HttpClient.GetStringAsync($"/{appName}/ServerAddresses"));
|
||||||
|
}
|
||||||
|
|
||||||
|
[ConditionalFact]
|
||||||
|
[RequiresNewHandler]
|
||||||
|
[RequiresNewShim]
|
||||||
|
public async Task HttpsPortCanBeOverriden()
|
||||||
|
{
|
||||||
|
var deploymentParameters = _fixture.GetBaseDeploymentParameters(HostingModel.OutOfProcess, publish: true);
|
||||||
|
|
||||||
|
deploymentParameters.AddServerConfigAction(
|
||||||
|
element => {
|
||||||
|
element.Descendants("bindings")
|
||||||
|
.Single()
|
||||||
|
.GetOrAdd("binding", "protocol", "https")
|
||||||
|
.SetAttributeValue("bindingInformation", $":{TestPortHelper.GetNextSSLPort()}:localhost");
|
||||||
|
});
|
||||||
|
|
||||||
|
deploymentParameters.WebConfigBasedEnvironmentVariables["ASPNETCORE_HTTPS_PORT"] = "123";
|
||||||
|
|
||||||
|
var deploymentResult = await DeployAsync(deploymentParameters);
|
||||||
|
Assert.Equal("123", await deploymentResult.HttpClient.GetStringAsync("/HTTPS_PORT"));
|
||||||
|
}
|
||||||
|
|
||||||
|
[ConditionalFact]
|
||||||
|
[RequiresNewHandler]
|
||||||
|
[RequiresNewShim]
|
||||||
|
public async Task MultipleHttpsPortsProduceNoEnvVar()
|
||||||
|
{
|
||||||
|
var sslPort = GetNextSSLPort();
|
||||||
|
var anotherSslPort = GetNextSSLPort(sslPort);
|
||||||
|
|
||||||
|
var deploymentParameters = _fixture.GetBaseDeploymentParameters(HostingModel.OutOfProcess, publish: true);
|
||||||
|
|
||||||
|
deploymentParameters.AddServerConfigAction(
|
||||||
|
element => {
|
||||||
|
element.Descendants("bindings")
|
||||||
|
.Single()
|
||||||
|
.Add(
|
||||||
|
new XElement("binding",
|
||||||
|
new XAttribute("protocol", "https"),
|
||||||
|
new XAttribute("bindingInformation", $":{sslPort}:localhost")),
|
||||||
|
new XElement("binding",
|
||||||
|
new XAttribute("protocol", "https"),
|
||||||
|
new XAttribute("bindingInformation", $":{anotherSslPort}:localhost")));
|
||||||
|
});
|
||||||
|
|
||||||
|
var deploymentResult = await DeployAsync(deploymentParameters);
|
||||||
|
Assert.Equal("NOVALUE", await deploymentResult.HttpClient.GetStringAsync("/HTTPS_PORT"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int GetNextSSLPort(int avoid = 0)
|
||||||
|
{
|
||||||
|
var next = 44300;
|
||||||
|
using (var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
|
||||||
|
{
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var port = next++;
|
||||||
|
if (port == avoid)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
socket.Bind(new IPEndPoint(IPAddress.Loopback, port));
|
||||||
|
return port;
|
||||||
|
}
|
||||||
|
catch (SocketException)
|
||||||
|
{
|
||||||
|
// Retry unless exhausted
|
||||||
|
if (next > 44399)
|
||||||
|
{
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Testing.xunit;
|
using Microsoft.AspNetCore.Testing.xunit;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
@ -25,5 +26,13 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
||||||
{
|
{
|
||||||
Assert.Equal("Success", await _fixture.Client.GetStringAsync(path + "/path" + "?query"));
|
Assert.Equal("Success", await _fixture.Client.GetStringAsync(path + "/path" + "?query"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[ConditionalFact]
|
||||||
|
[RequiresNewHandler]
|
||||||
|
[RequiresNewShim]
|
||||||
|
public async Task ExposesIServerAddressesFeature()
|
||||||
|
{
|
||||||
|
Assert.Equal(_fixture.Client.BaseAddress.ToString(), await _fixture.Client.GetStringAsync("/ServerAddresses"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -115,18 +115,8 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
||||||
siteElement.Add(newApplication);
|
siteElement.Add(newApplication);
|
||||||
|
|
||||||
// IIS Express requires root application to exist
|
// IIS Express requires root application to exist
|
||||||
var rootApplicationDirectory = new DirectoryInfo(contentRoot + "rootApp");
|
|
||||||
rootApplicationDirectory.Create();
|
|
||||||
|
|
||||||
_rootApplication = new PublishedApplication(rootApplicationDirectory.FullName, Logger);
|
_rootApplication = new PublishedApplication(Helpers.CreateEmptyApplication(config, contentRoot), Logger);
|
||||||
File.WriteAllText(GetWebConfigLocation(rootApplicationDirectory.FullName), "<configuration></configuration>");
|
|
||||||
|
|
||||||
var rootApplication = new XElement(application);
|
|
||||||
rootApplication.SetAttributeValue("path", "/");
|
|
||||||
rootApplication.RequiredElement("virtualDirectory")
|
|
||||||
.SetAttributeValue("physicalPath", rootApplicationDirectory.FullName);
|
|
||||||
|
|
||||||
siteElement.Add(rootApplication);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string GetWebConfigLocation(string siteRoot)
|
private static string GetWebConfigLocation(string siteRoot)
|
||||||
|
|
|
||||||
|
|
@ -237,5 +237,30 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
||||||
throw ex;
|
throw ex;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static string CreateEmptyApplication(XElement config, string contentRoot)
|
||||||
|
{
|
||||||
|
var siteElement = config
|
||||||
|
.RequiredElement("system.applicationHost")
|
||||||
|
.RequiredElement("sites")
|
||||||
|
.RequiredElement("site");
|
||||||
|
|
||||||
|
var application = siteElement
|
||||||
|
.RequiredElement("application");
|
||||||
|
|
||||||
|
var rootApplicationDirectory = new DirectoryInfo(contentRoot + "rootApp");
|
||||||
|
rootApplicationDirectory.Create();
|
||||||
|
|
||||||
|
File.WriteAllText(Path.Combine(rootApplicationDirectory.FullName, "web.config"), "<configuration></configuration>");
|
||||||
|
|
||||||
|
var rootApplication = new XElement(application);
|
||||||
|
rootApplication.SetAttributeValue("path", "/");
|
||||||
|
rootApplication.RequiredElement("virtualDirectory")
|
||||||
|
.SetAttributeValue("physicalPath", rootApplicationDirectory.FullName);
|
||||||
|
|
||||||
|
siteElement.Add(rootApplication);
|
||||||
|
|
||||||
|
return rootApplicationDirectory.FullName;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
#include "stdafx.h"
|
||||||
|
|
||||||
|
namespace BindingInformationTest
|
||||||
|
{
|
||||||
|
class BindingInformationTest : public testing::Test
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
void
|
||||||
|
ParseBindingInformation(std::wstring protocol, std::wstring info, std::wstring expectedHost, std::wstring expectedPort)
|
||||||
|
{
|
||||||
|
BindingInformation information(protocol, info);
|
||||||
|
|
||||||
|
EXPECT_STREQ(information.QueryHost().c_str(), expectedHost.c_str());
|
||||||
|
EXPECT_STREQ(information.QueryPort().c_str(), expectedPort.c_str());
|
||||||
|
EXPECT_STREQ(information.QueryProtocol().c_str(), protocol.c_str());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST_F(BindingInformationTest, ParsesInformationCorrectly)
|
||||||
|
{
|
||||||
|
ParseBindingInformation(L"https", L":80:", L"*", L"80");
|
||||||
|
ParseBindingInformation(L"https", L":80:host", L"host", L"80");
|
||||||
|
ParseBindingInformation(L"http", L":80:host", L"host", L"80");
|
||||||
|
ParseBindingInformation(L"http", L"RANDOM_IP:5:", L"*", L"5");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
|
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
|
||||||
<ItemGroup Label="ProjectConfigurations">
|
<ItemGroup Label="ProjectConfigurations">
|
||||||
<ProjectConfiguration Include="Debug|Win32">
|
<ProjectConfiguration Include="Debug|Win32">
|
||||||
<Configuration>Debug</Configuration>
|
<Configuration>Debug</Configuration>
|
||||||
|
|
@ -58,6 +57,7 @@
|
||||||
<ClCompile Include="inprocess_application_tests.cpp" />
|
<ClCompile Include="inprocess_application_tests.cpp" />
|
||||||
<ClCompile Include="main.cpp" />
|
<ClCompile Include="main.cpp" />
|
||||||
<ClCompile Include="PipeOutputManagerTests.cpp" />
|
<ClCompile Include="PipeOutputManagerTests.cpp" />
|
||||||
|
<ClCompile Include="BindingInformationTest.cpp" />
|
||||||
<ClCompile Include="utility_tests.cpp" />
|
<ClCompile Include="utility_tests.cpp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
@ -195,4 +195,4 @@
|
||||||
</Lib>
|
</Lib>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<Import Project=".\NativeTests.targets" />
|
<Import Project=".\NativeTests.targets" />
|
||||||
</Project>
|
</Project>
|
||||||
|
|
@ -1,60 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
using System.Net.Http;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Microsoft.AspNetCore.Server.IIS.FunctionalTests.Utilities;
|
|
||||||
using Microsoft.AspNetCore.Server.IntegrationTesting;
|
|
||||||
using Microsoft.AspNetCore.Server.IntegrationTesting.Common;
|
|
||||||
using Microsoft.AspNetCore.Server.IntegrationTesting.IIS;
|
|
||||||
using Microsoft.AspNetCore.Testing.xunit;
|
|
||||||
using Xunit;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
|
||||||
{
|
|
||||||
[Collection(PublishedSitesCollection.Name)]
|
|
||||||
public class HttpsTests : IISFunctionalTestBase
|
|
||||||
{
|
|
||||||
private readonly PublishedSitesFixture _fixture;
|
|
||||||
|
|
||||||
public HttpsTests(PublishedSitesFixture fixture)
|
|
||||||
{
|
|
||||||
_fixture = fixture;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static TestMatrix TestVariants
|
|
||||||
=> TestMatrix.ForServers(DeployerSelector.ServerType)
|
|
||||||
.WithTfms(Tfm.NetCoreApp30)
|
|
||||||
.WithAllApplicationTypes()
|
|
||||||
.WithAllAncmVersions()
|
|
||||||
.WithAllHostingModels();
|
|
||||||
|
|
||||||
[ConditionalTheory]
|
|
||||||
[MemberData(nameof(TestVariants))]
|
|
||||||
public async Task HttpsHelloWorld(TestVariant variant)
|
|
||||||
{
|
|
||||||
var port = TestPortHelper.GetNextSSLPort();
|
|
||||||
var deploymentParameters = _fixture.GetBaseDeploymentParameters(variant);
|
|
||||||
deploymentParameters.ApplicationBaseUriHint = $"https://localhost:{port}/";
|
|
||||||
deploymentParameters.AddHttpsToServerConfig();
|
|
||||||
|
|
||||||
var deploymentResult = await DeployAsync(deploymentParameters);
|
|
||||||
|
|
||||||
var handler = new HttpClientHandler
|
|
||||||
{
|
|
||||||
ServerCertificateCustomValidationCallback = (a, b, c, d) => true
|
|
||||||
};
|
|
||||||
var client = deploymentResult.CreateClient(handler);
|
|
||||||
var response = await client.GetAsync("HttpsHelloWorld");
|
|
||||||
var responseText = await response.Content.ReadAsStringAsync();
|
|
||||||
if (variant.HostingModel == HostingModel.OutOfProcess)
|
|
||||||
{
|
|
||||||
Assert.Equal("Scheme:https; Original:http", responseText);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Assert.Equal("Scheme:https; Original:", responseText);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -4,16 +4,15 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
|
||||||
using System.Security.Principal;
|
using System.Security.Principal;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Authentication;
|
using Microsoft.AspNetCore.Authentication;
|
||||||
using Microsoft.AspNetCore.Builder;
|
using Microsoft.AspNetCore.Builder;
|
||||||
using Microsoft.AspNetCore.Hosting.Server.Features;
|
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Http.Features;
|
using Microsoft.AspNetCore.Http.Features;
|
||||||
using Microsoft.AspNetCore.IISIntegration.FunctionalTests;
|
using Microsoft.AspNetCore.IISIntegration.FunctionalTests;
|
||||||
using Microsoft.AspNetCore.Server.IISIntegration;
|
using Microsoft.AspNetCore.Server.IISIntegration;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
|
|
@ -21,13 +20,9 @@ namespace TestSite
|
||||||
{
|
{
|
||||||
public partial class Startup
|
public partial class Startup
|
||||||
{
|
{
|
||||||
private IServerAddressesFeature _serverAddresses;
|
|
||||||
|
|
||||||
public void Configure(IApplicationBuilder app)
|
public void Configure(IApplicationBuilder app)
|
||||||
{
|
{
|
||||||
TestStartup.Register(app, this);
|
TestStartup.Register(app, this);
|
||||||
|
|
||||||
_serverAddresses = app.ServerFeatures.Get<IServerAddressesFeature>();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task Path(HttpContext ctx) => ctx.Response.WriteAsync(ctx.Request.Path.Value);
|
public Task Path(HttpContext ctx) => ctx.Response.WriteAsync(ctx.Request.Path.Value);
|
||||||
|
|
@ -36,7 +31,6 @@ namespace TestSite
|
||||||
|
|
||||||
public Task BodyLimit(HttpContext ctx) => ctx.Response.WriteAsync(ctx.Features.Get<IHttpMaxRequestBodySizeFeature>()?.MaxRequestBodySize?.ToString() ?? "null");
|
public Task BodyLimit(HttpContext ctx) => ctx.Response.WriteAsync(ctx.Features.Get<IHttpMaxRequestBodySizeFeature>()?.MaxRequestBodySize?.ToString() ?? "null");
|
||||||
|
|
||||||
|
|
||||||
public Task HelloWorld(HttpContext ctx) => ctx.Response.WriteAsync("Hello World");
|
public Task HelloWorld(HttpContext ctx) => ctx.Response.WriteAsync("Hello World");
|
||||||
|
|
||||||
public Task HttpsHelloWorld(HttpContext ctx) =>
|
public Task HttpsHelloWorld(HttpContext ctx) =>
|
||||||
|
|
@ -97,9 +91,11 @@ namespace TestSite
|
||||||
await context.Response.WriteAsync(Process.GetCurrentProcess().Id.ToString());
|
await context.Response.WriteAsync(Process.GetCurrentProcess().Id.ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task ServerAddresses(HttpContext context)
|
public async Task HTTPS_PORT(HttpContext context)
|
||||||
{
|
{
|
||||||
await context.Response.WriteAsync(string.Join(",", _serverAddresses.Addresses));
|
var httpsPort = context.RequestServices.GetService<IConfiguration>().GetValue<int?>("HTTPS_PORT");
|
||||||
|
|
||||||
|
await context.Response.WriteAsync(httpsPort.HasValue ? httpsPort.Value.ToString() : "NOVALUE");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,8 @@ using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Authentication;
|
using Microsoft.AspNetCore.Authentication;
|
||||||
using Microsoft.AspNetCore.Builder;
|
using Microsoft.AspNetCore.Builder;
|
||||||
using Microsoft.AspNetCore.Hosting;
|
using Microsoft.AspNetCore.Hosting;
|
||||||
|
using Microsoft.AspNetCore.Hosting.Server;
|
||||||
|
using Microsoft.AspNetCore.Hosting.Server.Features;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
|
|
@ -33,6 +35,12 @@ namespace TestSite
|
||||||
|
|
||||||
private async Task ASPNETCORE_IIS_PHYSICAL_PATH(HttpContext ctx) => await ctx.Response.WriteAsync(Environment.GetEnvironmentVariable("ASPNETCORE_IIS_PHYSICAL_PATH"));
|
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)
|
||||||
|
{
|
||||||
|
var serverAddresses = ctx.RequestServices.GetService<IServer>().Features.Get<IServerAddressesFeature>();
|
||||||
|
await ctx.Response.WriteAsync(string.Join(",", serverAddresses.Addresses));
|
||||||
|
}
|
||||||
|
|
||||||
private async Task ConsoleWrite(HttpContext ctx)
|
private async Task ConsoleWrite(HttpContext ctx)
|
||||||
{
|
{
|
||||||
Console.WriteLine("TEST MESSAGE");
|
Console.WriteLine("TEST MESSAGE");
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue