Skip to content

Add IServerAddressesFeature support #4685

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 15 commits into from
Dec 20, 2018
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/IISIntegration/build/launchSettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -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)",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)",
Expand Down
10 changes: 10 additions & 0 deletions src/IISIntegration/samples/NativeIISSample/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,12 @@
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
{
Expand Down Expand Up @@ -89,6 +92,13 @@ public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
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);
}
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,11 @@ class ApplicationFactory
{
// 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()}
}
};

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
// 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"

class BindingInformation
{
public:
BindingInformation(std::wstring protocol, std::wstring host, std::wstring port)
{
m_protocol = protocol;
m_host = host;
m_port = port;
}

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(L"name");
if (equals_ignore_case(runningSiteName, siteName))
{
auto bindings = site->GetRequiredSection(L"bindings")->GetCollection();
for (const auto& binding : bindings)
{
const auto information = binding->GetRequiredString(L"bindingInformation");
const auto firstColon = information.find(L':') + 1;
const auto lastColon = information.find_last_of(L':');

std::wstring host;
// Check that : is not the last character
if (lastColon != information.length() + 1)
{
auto const afterLastColon = lastColon + 1;
host = information.substr(afterLastColon, information.length() - afterLastColon);
}
if (host.length() == 0)
{
host = L"*";
}

items.emplace_back(
binding->GetRequiredString(L"protocol"),
host,
information.substr(firstColon, lastColon - firstColon)
);
}
}
}

return items;
}

static
std::wstring Format(const std::vector<BindingInformation> bindings)
{
std::wstring result;

for (auto binding : bindings)
{
result += binding.QueryProtocol() + L"://" + binding.QueryHost() + L":" + binding.QueryPort() + L";";
}

return result;
}

private:
std::wstring m_protocol;
std::wstring m_port;
std::wstring m_host;
};
Original file line number Diff line number Diff line change
Expand Up @@ -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" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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->GetRequiredString(CS_ASPNETCORE_COLLECTION_ITEM_VALUE));
}
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(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,17 @@ class ConfigurationSection: NonCopyable
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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "ConfigurationSection.h"

#define CS_ASPNETCORE_SECTION L"system.webServer/aspNetCore"
#define CS_SITE_SECTION L"system.applicationHost/sites"
#define CS_WINDOWS_AUTHENTICATION_SECTION L"system.webServer/security/authentication/windowsAuthentication"
#define CS_BASIC_AUTHENTICATION_SECTION L"system.webServer/security/authentication/basicAuthentication"
#define CS_ANONYMOUS_AUTHENTICATION_SECTION L"system.webServer/security/authentication/anonymousAuthentication"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
HRESULT findElementResult;
CComPtr<IAppHostElement> element = nullptr;
CComPtr<IAppHostElementCollection> elementCollection = nullptr;
CComPtr<IAppHostElement> collectionEntry = nullptr;
ENUM_INDEX index{};
CComPtr<IAppHostElement> element = nullptr;

if (FAILED_LOG(GetElementChildByName(m_element, name.c_str(), &element)))
{
return pairs;
return std::nullopt;
}

THROW_IF_FAILED(element->get_Collection(&elementCollection));
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<IAppHostElementCollection> elementCollection = nullptr;
CComPtr<IAppHostElement> collectionEntry = nullptr;
ENUM_INDEX index{};

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;
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ class WebConfigConfigurationSection: public ConfigurationSection
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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand All @@ -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),
Expand Down Expand Up @@ -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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#pragma once

#include <string>
#include "BindingInformation.h"
#include "ConfigurationSource.h"
#include "WebConfigConfigurationSource.h"

Expand Down Expand Up @@ -92,11 +93,18 @@ class InProcessOptions: NonCopyable
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);

Expand All @@ -113,6 +121,7 @@ class InProcessOptions: NonCopyable
DWORD m_dwStartupTimeLimitInMS;
DWORD m_dwShutdownTimeLimitInMS;
std::vector<std::pair<std::wstring, std::wstring>> m_environmentVariables;
std::vector<BindingInformation> m_bindingInformation;

protected:
InProcessOptions() = default;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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);

Expand Down
Loading