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
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NativeIISSample", "samples\NativeIISSample\NativeIISSample.csproj", "{9BC4AFCB-325D-4C81-8228-8CF301CE2F97}"
|
||||
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
|
||||
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
|
||||
|
|
@ -63,7 +63,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Server
|
|||
{D57EA297-6DC2-4BC0-8C91-334863327863} = {D57EA297-6DC2-4BC0-8C91-334863327863}
|
||||
EndProjectSection
|
||||
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
|
||||
{46A8612B-418B-4D70-B3A7-A21DD0627473} = {46A8612B-418B-4D70-B3A7-A21DD0627473}
|
||||
EndProjectSection
|
||||
|
|
@ -82,7 +82,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CommonLib", "src\AspNetCore
|
|||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "IISLib", "src\AspNetCoreModuleV2\IISLib\IISLib.vcxproj", "{09D9D1D6-2951-4E14-BC35-76A23CF9391A}"
|
||||
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
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "benchmarks", "benchmarks", "{622D35C9-627B-466E-8D15-752968CC79AF}"
|
||||
EndProject
|
||||
|
|
@ -114,7 +114,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IIS.BackwardsCompatibility.
|
|||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IIS.ForwardsCompatibility.FunctionalTests", "test\IIS.ForwardsCompatibility.FunctionalTests\IIS.ForwardsCompatibility.FunctionalTests.csproj", "{D1EA5D99-28FD-4197-81DE-17098846B38B}"
|
||||
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
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@
|
|||
"IIS_SITE_PATH": "$(MSBuildThisFileDirectory)",
|
||||
"ANCM_PATH": "$(AspNetCoreModuleV1ShimDll)",
|
||||
"ANCMV2_PATH": "$(AspNetCoreModuleV2ShimDll)",
|
||||
"ANCM_OUTOFPROCESS_HANDLER": "$(AspNetCoreModuleV2OutOfProcessHandlerDll)",
|
||||
"ASPNETCORE_MODULE_OUTOFPROCESS_HANDLER": "$(AspNetCoreModuleV2OutOfProcessHandlerDll)",
|
||||
"LAUNCHER_ARGS": "$(TargetPath)",
|
||||
"ASPNETCORE_ENVIRONMENT": "Development",
|
||||
"LAUNCHER_PATH": "$(DotNetPath)",
|
||||
|
|
|
|||
|
|
@ -6,9 +6,12 @@ using System.Linq;
|
|||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Hosting.Server;
|
||||
using Microsoft.AspNetCore.Hosting.Server.Features;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Http.Features;
|
||||
using Microsoft.AspNetCore.Server.IIS;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace NativeIISSample
|
||||
{
|
||||
|
|
@ -89,6 +92,13 @@ namespace NativeIISSample
|
|||
{
|
||||
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
|
||||
auto location = m_location;
|
||||
std::array<APPLICATION_PARAMETER, 2> parameters {
|
||||
std::array<APPLICATION_PARAMETER, 3> parameters {
|
||||
{
|
||||
{"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>
|
||||
<ClInclude Include="application.h" />
|
||||
<ClInclude Include="baseoutputmanager.h" />
|
||||
<ClInclude Include="BindingInformation.h" />
|
||||
<ClInclude Include="ConfigurationSection.h" />
|
||||
<ClInclude Include="ConfigurationSource.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()));
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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> 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;
|
||||
bool GetRequiredBool(const std::wstring& name) const;
|
||||
DWORD GetRequiredLong(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:
|
||||
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));
|
||||
}
|
||||
|
||||
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;
|
||||
CComPtr<IAppHostElement> element = nullptr;
|
||||
CComPtr<IAppHostElementCollection> elementCollection = nullptr;
|
||||
CComPtr<IAppHostElement> collectionEntry = nullptr;
|
||||
ENUM_INDEX index{};
|
||||
|
||||
if (FAILED_LOG(GetElementChildByName(m_element, name.c_str(), &element)))
|
||||
{
|
||||
return pairs;
|
||||
}
|
||||
|
||||
THROW_IF_FAILED(element->get_Collection(&elementCollection));
|
||||
THROW_IF_FAILED(m_element->get_Collection(&elementCollection));
|
||||
THROW_IF_FAILED(findElementResult = FindFirstElement(elementCollection, &index, &collectionEntry));
|
||||
|
||||
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;
|
||||
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);
|
||||
elements.emplace_back(std::make_shared<WebConfigConfigurationSection>(collectionEntry.Detach()));
|
||||
|
||||
collectionEntry.Release();
|
||||
|
||||
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<DWORD> GetLong(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:
|
||||
CComPtr<IAppHostElement> m_element;
|
||||
|
|
|
|||
|
|
@ -7,13 +7,14 @@
|
|||
|
||||
HRESULT InProcessOptions::Create(
|
||||
IHttpServer& pServer,
|
||||
IHttpSite* site,
|
||||
IHttpApplication& pHttpApplication,
|
||||
std::unique_ptr<InProcessOptions>& options)
|
||||
{
|
||||
try
|
||||
{
|
||||
const WebConfigConfigurationSource configurationSource(pServer.GetAdminManager(), pHttpApplication);
|
||||
options = std::make_unique<InProcessOptions>(configurationSource);
|
||||
options = std::make_unique<InProcessOptions>(configurationSource, site);
|
||||
}
|
||||
catch (InvalidOperationException& ex)
|
||||
{
|
||||
|
|
@ -38,7 +39,7 @@ HRESULT InProcessOptions::Create(
|
|||
return S_OK;
|
||||
}
|
||||
|
||||
InProcessOptions::InProcessOptions(const ConfigurationSource &configurationSource) :
|
||||
InProcessOptions::InProcessOptions(const ConfigurationSource &configurationSource, IHttpSite* pSite) :
|
||||
m_fStdoutLogEnabled(false),
|
||||
m_fWindowsAuthEnabled(false),
|
||||
m_fBasicAuthEnabled(false),
|
||||
|
|
@ -68,4 +69,9 @@ InProcessOptions::InProcessOptions(const ConfigurationSource &configurationSourc
|
|||
|
||||
const auto anonAuthSection = configurationSource.GetSection(CS_ANONYMOUS_AUTHENTICATION_SECTION);
|
||||
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
|
||||
|
||||
#include <string>
|
||||
#include "BindingInformation.h"
|
||||
#include "ConfigurationSource.h"
|
||||
#include "WebConfigConfigurationSource.h"
|
||||
|
||||
|
|
@ -92,11 +93,18 @@ public:
|
|||
return m_environmentVariables;
|
||||
}
|
||||
|
||||
InProcessOptions(const ConfigurationSource &configurationSource);
|
||||
const std::vector<BindingInformation>&
|
||||
QueryBindings() const
|
||||
{
|
||||
return m_bindingInformation;
|
||||
}
|
||||
|
||||
InProcessOptions(const ConfigurationSource &configurationSource, IHttpSite* pSite);
|
||||
|
||||
static
|
||||
HRESULT InProcessOptions::Create(
|
||||
IHttpServer& pServer,
|
||||
IHttpSite* site,
|
||||
IHttpApplication& pHttpApplication,
|
||||
std::unique_ptr<InProcessOptions>& options);
|
||||
|
||||
|
|
@ -113,6 +121,7 @@ private:
|
|||
DWORD m_dwStartupTimeLimitInMS;
|
||||
DWORD m_dwShutdownTimeLimitInMS;
|
||||
std::vector<std::pair<std::wstring, std::wstring>> m_environmentVariables;
|
||||
std::vector<BindingInformation> m_bindingInformation;
|
||||
|
||||
protected:
|
||||
InProcessOptions() = default;
|
||||
|
|
|
|||
|
|
@ -100,6 +100,8 @@ CreateApplication(
|
|||
)
|
||||
{
|
||||
TraceContextScope traceScope(FindParameter<IHttpTraceContext*>("TraceContext", pParameters, nParameters));
|
||||
const auto pSite = FindParameter<IHttpSite*>("Site", pParameters, nParameters);
|
||||
|
||||
try
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
|
|
@ -117,14 +119,14 @@ CreateApplication(
|
|||
g_fInProcessApplicationCreated = true;
|
||||
|
||||
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();
|
||||
}
|
||||
else
|
||||
{
|
||||
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.
|
||||
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(
|
||||
IHttpServer& pServer,
|
||||
IHttpSite* pSite,
|
||||
IHttpApplication& pHttpApplication,
|
||||
APPLICATION_PARAMETER* pParameters,
|
||||
DWORD nParameters,
|
||||
|
|
@ -352,7 +353,7 @@ HRESULT IN_PROCESS_APPLICATION::Start(
|
|||
try
|
||||
{
|
||||
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>(
|
||||
new IN_PROCESS_APPLICATION(pServer, pHttpApplication, std::move(options), pParameters, nParameters));
|
||||
THROW_IF_FAILED(application->LoadManagedApplication());
|
||||
|
|
@ -444,6 +445,7 @@ IN_PROCESS_APPLICATION::SetEnvironmentVariablesOnWorkerProcess()
|
|||
m_pConfig->QueryBasicAuthEnabled(),
|
||||
m_pConfig->QueryAnonymousAuthEnabled(),
|
||||
QueryApplicationPhysicalPath().c_str(),
|
||||
nullptr, /* pHttpsPort */
|
||||
&pHashTable));
|
||||
|
||||
table.reset(pHashTable);
|
||||
|
|
|
|||
|
|
@ -104,6 +104,7 @@ public:
|
|||
static
|
||||
HRESULT Start(
|
||||
IHttpServer& pServer,
|
||||
IHttpSite* pSite,
|
||||
IHttpApplication& pHttpApplication,
|
||||
APPLICATION_PARAMETER* pParameters,
|
||||
DWORD nParameters,
|
||||
|
|
|
|||
|
|
@ -185,6 +185,7 @@ struct IISConfigurationData
|
|||
BOOL fWindowsAuthEnabled;
|
||||
BOOL fBasicAuthEnabled;
|
||||
BOOL fAnonymousAuthEnable;
|
||||
BSTR pwzBindings;
|
||||
};
|
||||
|
||||
EXTERN_C __MIDL_DECLSPEC_DLLEXPORT
|
||||
|
|
@ -208,6 +209,8 @@ http_get_application_properties(
|
|||
pIISCofigurationData->fBasicAuthEnabled = pConfiguration.QueryBasicAuthEnabled();
|
||||
pIISCofigurationData->fAnonymousAuthEnable = pConfiguration.QueryAnonymousAuthEnabled();
|
||||
|
||||
auto const serverAddresses = BindingInformation::Format(pConfiguration.QueryBindings(), pInProcessApplication->QueryApplicationVirtualPath());
|
||||
pIISCofigurationData->pwzBindings = SysAllocString(serverAddresses.c_str());
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -251,11 +251,12 @@ CreateApplication(
|
|||
)
|
||||
{
|
||||
TraceContextScope traceScope(FindParameter<IHttpTraceContext*>("TraceContext", pParameters, nParameters));
|
||||
auto pSite = FindParameter<IHttpSite*>("Site", pParameters, nParameters);
|
||||
|
||||
InitializeGlobalConfiguration(pServer);
|
||||
|
||||
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);
|
||||
|
||||
RETURN_IF_FAILED(EnsureOutOfProcessInitializtion(pHttpApplication));
|
||||
|
|
|
|||
|
|
@ -162,7 +162,8 @@ PROCESS_MANAGER::GetProcess(
|
|||
pConfig->QueryStdoutLogFile(),
|
||||
pConfig->QueryApplicationPhysicalPath(), // physical path
|
||||
pConfig->QueryApplicationPath(), // app path
|
||||
pConfig->QueryApplicationVirtualPath() // App relative virtual path
|
||||
pConfig->QueryApplicationVirtualPath(), // App relative virtual path,
|
||||
pConfig->QueryBindings()
|
||||
));
|
||||
RETURN_IF_FAILED(pSelectedServerProcess->StartProcess());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,7 +30,8 @@ SERVER_PROCESS::Initialize(
|
|||
STRU *pstruStdoutLogFile,
|
||||
STRU *pszAppPhysicalPath,
|
||||
STRU *pszAppPath,
|
||||
STRU *pszAppVirtualPath
|
||||
STRU *pszAppVirtualPath,
|
||||
STRU *pszHttpsPort
|
||||
)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
|
|
@ -52,6 +53,7 @@ SERVER_PROCESS::Initialize(
|
|||
FAILED_LOG(hr = m_struAppFullPath.Copy(*pszAppPath))||
|
||||
FAILED_LOG(hr = m_struAppVirtualPath.Copy(*pszAppVirtualPath))||
|
||||
FAILED_LOG(hr = m_Arguments.Copy(*pszArguments)) ||
|
||||
FAILED_LOG(hr = m_struHttpsPort.Copy(*pszHttpsPort)) ||
|
||||
FAILED_LOG(hr = SetupJobObject()))
|
||||
{
|
||||
goto Finished;
|
||||
|
|
@ -786,6 +788,7 @@ SERVER_PROCESS::StartProcess(
|
|||
m_fBasicAuthEnabled,
|
||||
m_fAnonymousAuthEnabled,
|
||||
m_struAppFullPath.QueryStr(),
|
||||
m_struHttpsPort.QueryStr(),
|
||||
&pHashTable)))
|
||||
{
|
||||
pStrStage = L"InitEnvironmentVariablesTable";
|
||||
|
|
|
|||
|
|
@ -39,7 +39,8 @@ public:
|
|||
_In_ STRU *pstruStdoutLogFile,
|
||||
_In_ STRU *pszAppPhysicalPath,
|
||||
_In_ STRU *pszAppPath,
|
||||
_In_ STRU *pszAppVirtualPath
|
||||
_In_ STRU *pszAppVirtualPath,
|
||||
_In_ STRU *pszHttpsPort
|
||||
);
|
||||
|
||||
HRESULT
|
||||
|
|
@ -98,7 +99,7 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
virtual
|
||||
virtual
|
||||
~SERVER_PROCESS();
|
||||
|
||||
static
|
||||
|
|
@ -129,7 +130,7 @@ public:
|
|||
};
|
||||
|
||||
VOID
|
||||
SendSignal(
|
||||
SendSignal(
|
||||
VOID
|
||||
);
|
||||
|
||||
|
|
@ -142,7 +143,7 @@ private:
|
|||
VOID
|
||||
);
|
||||
|
||||
BOOL
|
||||
BOOL
|
||||
IsDebuggerIsAttached(
|
||||
VOID
|
||||
);
|
||||
|
|
@ -164,13 +165,13 @@ private:
|
|||
_Out_ BOOL * pfReady
|
||||
);
|
||||
|
||||
HRESULT
|
||||
HRESULT
|
||||
RegisterProcessWait(
|
||||
_In_ PHANDLE phWaitHandle,
|
||||
_In_ HANDLE hProcessToWaitOn
|
||||
);
|
||||
|
||||
HRESULT
|
||||
HRESULT
|
||||
GetChildProcessHandles(
|
||||
VOID
|
||||
);
|
||||
|
|
@ -252,6 +253,7 @@ private:
|
|||
STRU m_struAppVirtualPath; // e.g., '/' for site
|
||||
STRU m_struAppFullPath; // e.g., /LM/W3SVC/4/ROOT/Inproc
|
||||
STRU m_struPhysicalPath; // e.g., c:/test/mysite
|
||||
STRU m_struHttpsPort; // e.g., /LM/W3SVC/4/ROOT/Inproc
|
||||
STRU m_struPort;
|
||||
STRU m_struCommandLine;
|
||||
|
||||
|
|
@ -281,7 +283,7 @@ private:
|
|||
HANDLE m_hProcessWaitHandle;
|
||||
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.
|
||||
//
|
||||
HANDLE m_hChildProcessHandles[MAX_ACTIVE_CHILD_PROCESSES];
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
#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_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_BASIC L"basic;"
|
||||
#define ASPNETCORE_IIS_AUTH_ANONYMOUS L"anonymous;"
|
||||
|
|
|
|||
|
|
@ -192,6 +192,7 @@ public:
|
|||
_In_ BOOL fBasicAuthEnabled,
|
||||
_In_ BOOL fAnonymousAuthEnabled,
|
||||
_In_ PCWSTR pApplicationPhysicalPath,
|
||||
_In_ PCWSTR pHttpsPort,
|
||||
_Out_ ENVIRONMENT_VAR_HASH** ppEnvironmentVarTable
|
||||
)
|
||||
{
|
||||
|
|
@ -203,6 +204,7 @@ public:
|
|||
ENVIRONMENT_VAR_ENTRY* pHostingEntry = NULL;
|
||||
ENVIRONMENT_VAR_ENTRY* pIISAuthEntry = NULL;
|
||||
ENVIRONMENT_VAR_ENTRY* pIISPathEntry = NULL;
|
||||
ENVIRONMENT_VAR_ENTRY* pIISHttpsPort = NULL;
|
||||
ENVIRONMENT_VAR_HASH* pEnvironmentVarTable = NULL;
|
||||
|
||||
pEnvironmentVarTable = new ENVIRONMENT_VAR_HASH();
|
||||
|
|
@ -240,6 +242,26 @@ public:
|
|||
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);
|
||||
if (pIISAuthEntry != NULL)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@
|
|||
#include "exceptions.h"
|
||||
#include "config_utility.h"
|
||||
|
||||
|
||||
REQUESTHANDLER_CONFIG::~REQUESTHANDLER_CONFIG()
|
||||
{
|
||||
if (m_ppStrArguments != NULL)
|
||||
|
|
@ -28,6 +27,7 @@ REQUESTHANDLER_CONFIG::~REQUESTHANDLER_CONFIG()
|
|||
HRESULT
|
||||
REQUESTHANDLER_CONFIG::CreateRequestHandlerConfig(
|
||||
_In_ IHttpServer *pHttpServer,
|
||||
_In_ IHttpSite *pSite,
|
||||
_In_ IHttpApplication *pHttpApplication,
|
||||
_Out_ REQUESTHANDLER_CONFIG **ppAspNetCoreConfig
|
||||
)
|
||||
|
|
@ -49,7 +49,7 @@ REQUESTHANDLER_CONFIG::CreateRequestHandlerConfig(
|
|||
|
||||
pRequestHandlerConfig = new REQUESTHANDLER_CONFIG;
|
||||
|
||||
hr = pRequestHandlerConfig->Populate(pHttpServer, pHttpApplication);
|
||||
hr = pRequestHandlerConfig->Populate(pHttpServer, pSite, pHttpApplication);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
goto Finished;
|
||||
|
|
@ -85,6 +85,7 @@ Finished:
|
|||
HRESULT
|
||||
REQUESTHANDLER_CONFIG::Populate(
|
||||
IHttpServer *pHttpServer,
|
||||
IHttpSite *pSite,
|
||||
IHttpApplication *pHttpApplication
|
||||
)
|
||||
{
|
||||
|
|
@ -122,6 +123,19 @@ REQUESTHANDLER_CONFIG::Populate(
|
|||
}
|
||||
|
||||
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());
|
||||
if (FAILED(hr))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@
|
|||
|
||||
#include "stdafx.h"
|
||||
#include "environmentvariablehash.h"
|
||||
#include "BindingInformation.h"
|
||||
|
||||
enum APP_HOSTING_MODEL
|
||||
{
|
||||
|
|
@ -62,6 +63,7 @@ public:
|
|||
HRESULT
|
||||
CreateRequestHandlerConfig(
|
||||
_In_ IHttpServer *pHttpServer,
|
||||
_In_ IHttpSite *pSite,
|
||||
_In_ IHttpApplication *pHttpApplication,
|
||||
_Out_ REQUESTHANDLER_CONFIG **ppAspNetCoreConfig
|
||||
);
|
||||
|
|
@ -114,6 +116,12 @@ public:
|
|||
return m_dwRequestTimeoutInMS;
|
||||
}
|
||||
|
||||
STRU*
|
||||
QueryBindings()
|
||||
{
|
||||
return &m_struHttpsPort;
|
||||
}
|
||||
|
||||
STRU*
|
||||
QueryArguments(
|
||||
VOID
|
||||
|
|
@ -226,6 +234,7 @@ protected:
|
|||
HRESULT
|
||||
Populate(
|
||||
IHttpServer *pHttpServer,
|
||||
IHttpSite *pSite,
|
||||
IHttpApplication *pHttpApplication
|
||||
);
|
||||
|
||||
|
|
@ -252,5 +261,5 @@ protected:
|
|||
STRU m_struHostFxrLocation;
|
||||
PWSTR* m_ppStrArguments;
|
||||
DWORD m_dwArgc;
|
||||
|
||||
STRU m_struHttpsPort;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -17,5 +17,7 @@ namespace Microsoft.AspNetCore.Server.IIS.Core
|
|||
public bool fWindowsAuthEnabled;
|
||||
public bool fBasicAuthEnabled;
|
||||
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.Buffers;
|
||||
|
|
@ -10,6 +8,7 @@ using Microsoft.AspNetCore.Authentication;
|
|||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Hosting.Server;
|
||||
using Microsoft.AspNetCore.Hosting.Server.Features;
|
||||
using Microsoft.AspNetCore.Http.Features;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
|
@ -32,6 +31,7 @@ namespace Microsoft.AspNetCore.Server.IIS.Core
|
|||
private readonly ILogger<IISHttpServer> _logger;
|
||||
private readonly IISServerOptions _options;
|
||||
private readonly IISNativeApplication _nativeApplication;
|
||||
private readonly ServerAddressesFeature _serverAddressesFeature;
|
||||
|
||||
private volatile int _stopping;
|
||||
private bool Stopping => _stopping == 1;
|
||||
|
|
@ -71,11 +71,14 @@ namespace Microsoft.AspNetCore.Server.IIS.Core
|
|||
_applicationLifetime = applicationLifetime;
|
||||
_logger = logger;
|
||||
_options = options.Value;
|
||||
_serverAddressesFeature = new ServerAddressesFeature();
|
||||
|
||||
if (_options.ForwardWindowsAuthentication)
|
||||
{
|
||||
authentication.AddScheme(new AuthenticationScheme(IISServerDefaults.AuthenticationScheme, _options.AuthenticationDisplayName, typeof(IISServerAuthenticationHandler)));
|
||||
}
|
||||
|
||||
Features.Set<IServerAddressesFeature>(_serverAddressesFeature);
|
||||
}
|
||||
|
||||
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);
|
||||
_nativeApplication.RegisterCallbacks(_requestHandler, _shutdownHandler, _onDisconnect, _onAsyncCompletion, (IntPtr)_httpServerHandle, (IntPtr)_httpServerHandle);
|
||||
|
||||
_serverAddressesFeature.Addresses = _options.ServerAddresses;
|
||||
|
||||
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.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Hosting.Server;
|
||||
using Microsoft.AspNetCore.Hosting.Server.Features;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.IIS.Core
|
||||
{
|
||||
internal class IISServerSetupFilter : IStartupFilter
|
||||
{
|
||||
private string _virtualPath;
|
||||
private readonly 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.
|
||||
/// </summary>
|
||||
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.AddAuthenticationCore();
|
||||
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.
|
||||
// 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 Microsoft.AspNetCore.Testing.xunit;
|
||||
using Xunit;
|
||||
|
|
@ -25,5 +26,13 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
|||
{
|
||||
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);
|
||||
|
||||
// IIS Express requires root application to exist
|
||||
var rootApplicationDirectory = new DirectoryInfo(contentRoot + "rootApp");
|
||||
rootApplicationDirectory.Create();
|
||||
|
||||
_rootApplication = new PublishedApplication(rootApplicationDirectory.FullName, 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);
|
||||
_rootApplication = new PublishedApplication(Helpers.CreateEmptyApplication(config, contentRoot), Logger);
|
||||
}
|
||||
|
||||
private static string GetWebConfigLocation(string siteRoot)
|
||||
|
|
|
|||
|
|
@ -237,5 +237,30 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
|||
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">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
|
|
@ -58,6 +57,7 @@
|
|||
<ClCompile Include="inprocess_application_tests.cpp" />
|
||||
<ClCompile Include="main.cpp" />
|
||||
<ClCompile Include="PipeOutputManagerTests.cpp" />
|
||||
<ClCompile Include="BindingInformationTest.cpp" />
|
||||
<ClCompile Include="utility_tests.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
|
@ -195,4 +195,4 @@
|
|||
</Lib>
|
||||
</ItemDefinitionGroup>
|
||||
<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.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Security.Principal;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting.Server.Features;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Http.Features;
|
||||
using Microsoft.AspNetCore.IISIntegration.FunctionalTests;
|
||||
using Microsoft.AspNetCore.Server.IISIntegration;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Xunit;
|
||||
|
||||
|
|
@ -21,13 +20,9 @@ namespace TestSite
|
|||
{
|
||||
public partial class Startup
|
||||
{
|
||||
private IServerAddressesFeature _serverAddresses;
|
||||
|
||||
public void Configure(IApplicationBuilder app)
|
||||
{
|
||||
TestStartup.Register(app, this);
|
||||
|
||||
_serverAddresses = app.ServerFeatures.Get<IServerAddressesFeature>();
|
||||
}
|
||||
|
||||
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 HelloWorld(HttpContext ctx) => ctx.Response.WriteAsync("Hello World");
|
||||
|
||||
public Task HttpsHelloWorld(HttpContext ctx) =>
|
||||
|
|
@ -97,9 +91,11 @@ namespace TestSite
|
|||
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.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Hosting.Server;
|
||||
using Microsoft.AspNetCore.Hosting.Server.Features;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
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 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)
|
||||
{
|
||||
Console.WriteLine("TEST MESSAGE");
|
||||
|
|
|
|||
Loading…
Reference in New Issue