Adds websocket feature detection, test cleanup. (#624)
This commit is contained in:
parent
ad4b172660
commit
00b1948937
|
|
@ -1,7 +1,7 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 15
|
||||
VisualStudioVersion = 15.0.27130.2026
|
||||
VisualStudioVersion = 15.0.27130.2036
|
||||
MinimumVisualStudioVersion = 15.0.26730.03
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{04B1EDB6-E967-4D25-89B9-E6F8304038CD}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
|
|
@ -44,8 +44,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NativeIISSample", "samples\
|
|||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IISTestSite", "test\IISTestSite\IISTestSite.csproj", "{679FA2A2-898B-4320-884E-C2D294A97CE1}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IISIntegration.IISServerFunctionalTests", "test\IISIntegration.IISServerFunctionalTests\IISIntegration.IISServerFunctionalTests.csproj", "{C745BBFD-7888-4038-B41B-6D1832D13878}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AspNetCore", "src\AspNetCore\AspNetCore.vcxproj", "{439824F9-1455-4CC4-BD79-B44FA0A16552}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "IISLib", "src\IISLib\IISLib.vcxproj", "{4787A64F-9A3E-4867-A55A-70CB4B2B2FFE}"
|
||||
|
|
@ -150,17 +148,6 @@ Global
|
|||
{679FA2A2-898B-4320-884E-C2D294A97CE1}.Release|x64.Build.0 = Release|Any CPU
|
||||
{679FA2A2-898B-4320-884E-C2D294A97CE1}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{679FA2A2-898B-4320-884E-C2D294A97CE1}.Release|x86.Build.0 = Release|Any CPU
|
||||
{C745BBFD-7888-4038-B41B-6D1832D13878}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{C745BBFD-7888-4038-B41B-6D1832D13878}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{C745BBFD-7888-4038-B41B-6D1832D13878}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{C745BBFD-7888-4038-B41B-6D1832D13878}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{C745BBFD-7888-4038-B41B-6D1832D13878}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{C745BBFD-7888-4038-B41B-6D1832D13878}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{C745BBFD-7888-4038-B41B-6D1832D13878}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{C745BBFD-7888-4038-B41B-6D1832D13878}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{C745BBFD-7888-4038-B41B-6D1832D13878}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{C745BBFD-7888-4038-B41B-6D1832D13878}.Release|x64.Build.0 = Release|Any CPU
|
||||
{C745BBFD-7888-4038-B41B-6D1832D13878}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{439824F9-1455-4CC4-BD79-B44FA0A16552}.Debug|Any CPU.ActiveCfg = Debug|Win32
|
||||
{439824F9-1455-4CC4-BD79-B44FA0A16552}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{439824F9-1455-4CC4-BD79-B44FA0A16552}.Debug|x64.Build.0 = Debug|x64
|
||||
|
|
@ -225,7 +212,6 @@ Global
|
|||
{4E3E1F5C-CD52-4CC0-A35F-D1FA1685D2FA} = {EF30B533-D715-421A-92B7-92FEF460AC9C}
|
||||
{9BC4AFCB-325D-4C81-8228-8CF301CE2F97} = {C74B8F36-FD2F-45C9-9B8A-00E7CF0126A9}
|
||||
{679FA2A2-898B-4320-884E-C2D294A97CE1} = {EF30B533-D715-421A-92B7-92FEF460AC9C}
|
||||
{C745BBFD-7888-4038-B41B-6D1832D13878} = {EF30B533-D715-421A-92B7-92FEF460AC9C}
|
||||
{439824F9-1455-4CC4-BD79-B44FA0A16552} = {04B1EDB6-E967-4D25-89B9-E6F8304038CD}
|
||||
{4787A64F-9A3E-4867-A55A-70CB4B2B2FFE} = {04B1EDB6-E967-4D25-89B9-E6F8304038CD}
|
||||
{55494E58-E061-4C4C-A0A8-837008E72F85} = {04B1EDB6-E967-4D25-89B9-E6F8304038CD}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ using Microsoft.AspNetCore.Authentication;
|
|||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Http.Features;
|
||||
using Microsoft.AspNetCore.Server.IISIntegration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
|
@ -71,7 +72,16 @@ namespace IISSample
|
|||
var value = vars[key];
|
||||
await context.Response.WriteAsync(key + ": " + value + Environment.NewLine);
|
||||
}
|
||||
|
||||
await context.Response.WriteAsync(Environment.NewLine);
|
||||
if (context.Features.Get<IHttpUpgradeFeature>() != null)
|
||||
{
|
||||
await context.Response.WriteAsync("Websocket feature is enabled.");
|
||||
}
|
||||
else
|
||||
{
|
||||
await context.Response.WriteAsync("Websocket feature is disabled.");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -18,4 +18,4 @@
|
|||
<aspNetCore processPath="dotnet" arguments=".\IISSample.dll" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" forwardWindowsAuthToken="false"/>
|
||||
-->
|
||||
</system.webServer>
|
||||
</configuration>
|
||||
</configuration>
|
||||
|
|
|
|||
|
|
@ -70,6 +70,16 @@ namespace NativeIISSample
|
|||
{
|
||||
await context.Response.WriteAsync(varName + ": " + context.GetIISServerVariable(varName) + Environment.NewLine);
|
||||
}
|
||||
|
||||
await context.Response.WriteAsync(Environment.NewLine);
|
||||
if (context.Features.Get<IHttpUpgradeFeature>() != null)
|
||||
{
|
||||
await context.Response.WriteAsync("Websocket feature is enabled.");
|
||||
}
|
||||
else
|
||||
{
|
||||
await context.Response.WriteAsync("Websocket feature is disabled.");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -83,6 +93,7 @@ namespace NativeIISSample
|
|||
"REMOTE_PORT",
|
||||
"REMOTE_USER",
|
||||
"REQUEST_METHOD",
|
||||
"WEBSOCKET_VERSION"
|
||||
};
|
||||
|
||||
public static void Main(string[] args)
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
#define HOSTING_STARTUP_ASSEMBLIES_NAME L"ASPNETCORE_HOSTINGSTARTUPASSEMBLIES="
|
||||
#define HOSTING_STARTUP_ASSEMBLIES_VALUE L"Microsoft.AspNetCore.Server.IISIntegration"
|
||||
#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_AUTH_WINDOWS L"windows;"
|
||||
#define ASPNETCORE_IIS_AUTH_BASIC L"basic;"
|
||||
#define ASPNETCORE_IIS_AUTH_ANONYMOUS L"anonymous;"
|
||||
|
|
@ -123,349 +124,6 @@ public:
|
|||
pEntry->Dereference();
|
||||
}
|
||||
|
||||
static
|
||||
VOID
|
||||
CopyToMultiSz(
|
||||
ENVIRONMENT_VAR_ENTRY * pEntry,
|
||||
PVOID pvData
|
||||
)
|
||||
{
|
||||
STRU strTemp;
|
||||
MULTISZ *pMultiSz = static_cast<MULTISZ *>(pvData);
|
||||
DBG_ASSERT(pMultiSz);
|
||||
DBG_ASSERT(pEntry);
|
||||
strTemp.Copy(pEntry->QueryName());
|
||||
strTemp.Append(pEntry->QueryValue());
|
||||
pMultiSz->Append(strTemp.QueryStr());
|
||||
}
|
||||
|
||||
static
|
||||
VOID
|
||||
CopyToTable(
|
||||
ENVIRONMENT_VAR_ENTRY * pEntry,
|
||||
PVOID pvData
|
||||
)
|
||||
{
|
||||
// best effort copy, ignore the failure
|
||||
ENVIRONMENT_VAR_ENTRY * pNewEntry = new ENVIRONMENT_VAR_ENTRY();
|
||||
if (pNewEntry != NULL)
|
||||
{
|
||||
pNewEntry->Initialize(pEntry->QueryName(), pEntry->QueryValue());
|
||||
ENVIRONMENT_VAR_HASH *pHash = static_cast<ENVIRONMENT_VAR_HASH *>(pvData);
|
||||
DBG_ASSERT(pHash);
|
||||
pHash->InsertRecord(pNewEntry);
|
||||
// Need to dereference as InsertRecord references it now
|
||||
pNewEntry->Dereference();
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
VOID
|
||||
AppendEnvironmentVariables
|
||||
(
|
||||
ENVIRONMENT_VAR_ENTRY * pEntry,
|
||||
PVOID pvData
|
||||
)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(pvData);
|
||||
|
||||
HRESULT hr = S_OK;
|
||||
DWORD dwResult = 0;
|
||||
DWORD dwError = 0;
|
||||
STRU struNameBuffer;
|
||||
STACK_STRU(struValueBuffer, 300);
|
||||
BOOL fFound = FALSE;
|
||||
|
||||
// pEntry->QueryName includes the trailing =, remove it before calling stru
|
||||
if (FAILED(hr = struNameBuffer.Copy(pEntry->QueryName())))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
dwResult = struNameBuffer.LastIndexOf(L'=');
|
||||
if (dwResult != -1)
|
||||
{
|
||||
struNameBuffer.QueryStr()[dwResult] = L'\0';
|
||||
if (FAILED(hr = struNameBuffer.SyncWithBuffer()))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
}
|
||||
|
||||
dwResult = GetEnvironmentVariable(struNameBuffer.QueryStr(), struValueBuffer.QueryStr(), struValueBuffer.QuerySizeCCH());
|
||||
if (dwResult == 0)
|
||||
{
|
||||
dwError = GetLastError();
|
||||
// Windows API (e.g., CreateProcess) allows variable with empty string value
|
||||
// in such case dwResult will be 0 and dwError will also be 0
|
||||
// As UI and CMD does not allow empty value, ignore this environment var
|
||||
if (dwError != ERROR_ENVVAR_NOT_FOUND && dwError != ERROR_SUCCESS)
|
||||
{
|
||||
hr = HRESULT_FROM_WIN32(dwError);
|
||||
goto Finished;
|
||||
}
|
||||
}
|
||||
else if (dwResult > struValueBuffer.QuerySizeCCH())
|
||||
{
|
||||
// have to increase the buffer and try get environment var again
|
||||
struValueBuffer.Reset();
|
||||
struValueBuffer.Resize(dwResult + (DWORD)wcslen(pEntry->QueryValue()) + 2); // for null char and semicolon
|
||||
dwResult = GetEnvironmentVariable(struNameBuffer.QueryStr(),
|
||||
struValueBuffer.QueryStr(),
|
||||
struValueBuffer.QuerySizeCCH());
|
||||
if (struValueBuffer.IsEmpty())
|
||||
{
|
||||
hr = E_UNEXPECTED;
|
||||
goto Finished;
|
||||
}
|
||||
fFound = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
fFound = TRUE;
|
||||
}
|
||||
|
||||
if (FAILED(hr = struValueBuffer.SyncWithBuffer()))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
if (fFound)
|
||||
{
|
||||
if (FAILED(hr = struValueBuffer.Append(L";")))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
}
|
||||
if (FAILED(hr = struValueBuffer.Append(pEntry->QueryValue())))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
if (FAILED(hr = pEntry->Initialize(pEntry->QueryName(), struValueBuffer.QueryStr())))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
Finished:
|
||||
// TODO besides calling SetLastError, is there anyway to propagate failures to set the environment variable?
|
||||
return;
|
||||
}
|
||||
|
||||
static
|
||||
VOID
|
||||
SetEnvironmentVariables
|
||||
(
|
||||
ENVIRONMENT_VAR_ENTRY * pEntry,
|
||||
PVOID pvData
|
||||
)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(pvData);
|
||||
HRESULT hr = S_OK;
|
||||
DWORD dwResult = 0;
|
||||
STRU struNameBuffer;
|
||||
|
||||
// pEntry->QueryName includes the trailing =, remove it before calling SetEnvironmentVariable.
|
||||
if (FAILED(hr = struNameBuffer.Copy(pEntry->QueryName())))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
dwResult = struNameBuffer.LastIndexOf(L'=');
|
||||
if (dwResult != -1)
|
||||
{
|
||||
struNameBuffer.QueryStr()[dwResult] = L'\0';
|
||||
if (FAILED(hr = struNameBuffer.SyncWithBuffer()))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
}
|
||||
|
||||
dwResult = SetEnvironmentVariable(struNameBuffer.QueryStr(), pEntry->QueryValue());
|
||||
if (dwResult == 0)
|
||||
{
|
||||
hr = HRESULT_FROM_WIN32(GetLastError());
|
||||
}
|
||||
|
||||
Finished:
|
||||
return;
|
||||
}
|
||||
|
||||
static
|
||||
HRESULT
|
||||
InitEnvironmentVariablesTable
|
||||
(
|
||||
_In_ ENVIRONMENT_VAR_HASH* pInEnvironmentVarTable,
|
||||
BOOL fWindowsAuthEnabled,
|
||||
BOOL fBasicAuthEnabled,
|
||||
BOOL fAnonymousAuthEnabled,
|
||||
ENVIRONMENT_VAR_HASH** ppEnvironmentVarTable
|
||||
)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
BOOL fFound = FALSE;
|
||||
DWORD dwResult, dwError;
|
||||
STRU strIisAuthEnvValue;
|
||||
STACK_STRU(strStartupAssemblyEnv, 1024);
|
||||
ENVIRONMENT_VAR_ENTRY* pHostingEntry = NULL;
|
||||
ENVIRONMENT_VAR_ENTRY* pIISAuthEntry = NULL;
|
||||
ENVIRONMENT_VAR_HASH* pEnvironmentVarTable = NULL;
|
||||
|
||||
pEnvironmentVarTable = new ENVIRONMENT_VAR_HASH();
|
||||
if (pEnvironmentVarTable == NULL)
|
||||
{
|
||||
hr = E_OUTOFMEMORY;
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
//
|
||||
// few environment variables expected, small bucket size for hash table
|
||||
//
|
||||
if (FAILED(hr = pEnvironmentVarTable->Initialize(37 /*prime*/)))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
// copy the envirable hash table (from configuration) to a temp one as we may need to remove elements
|
||||
pInEnvironmentVarTable->Apply(ENVIRONMENT_VAR_HASH::CopyToTable, pEnvironmentVarTable);
|
||||
if (pEnvironmentVarTable->Count() != pInEnvironmentVarTable->Count())
|
||||
{
|
||||
// hash table copy failed
|
||||
hr = E_UNEXPECTED;
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
pEnvironmentVarTable->FindKey((PWSTR)ASPNETCORE_IIS_AUTH_ENV_STR, &pIISAuthEntry);
|
||||
if (pIISAuthEntry != NULL)
|
||||
{
|
||||
// user defined ASPNETCORE_IIS_HTTPAUTH in configuration, wipe it off
|
||||
pIISAuthEntry->Dereference();
|
||||
pEnvironmentVarTable->DeleteKey((PWSTR)ASPNETCORE_IIS_AUTH_ENV_STR);
|
||||
}
|
||||
|
||||
if (fWindowsAuthEnabled)
|
||||
{
|
||||
strIisAuthEnvValue.Copy(ASPNETCORE_IIS_AUTH_WINDOWS);
|
||||
}
|
||||
|
||||
if (fBasicAuthEnabled)
|
||||
{
|
||||
strIisAuthEnvValue.Append(ASPNETCORE_IIS_AUTH_BASIC);
|
||||
}
|
||||
|
||||
if (fAnonymousAuthEnabled)
|
||||
{
|
||||
strIisAuthEnvValue.Append(ASPNETCORE_IIS_AUTH_ANONYMOUS);
|
||||
}
|
||||
|
||||
if (strIisAuthEnvValue.IsEmpty())
|
||||
{
|
||||
strIisAuthEnvValue.Copy(ASPNETCORE_IIS_AUTH_NONE);
|
||||
}
|
||||
|
||||
pIISAuthEntry = new ENVIRONMENT_VAR_ENTRY();
|
||||
if (pIISAuthEntry == NULL)
|
||||
{
|
||||
hr = E_OUTOFMEMORY;
|
||||
goto Finished;
|
||||
}
|
||||
if (FAILED(hr = pIISAuthEntry->Initialize(ASPNETCORE_IIS_AUTH_ENV_STR, strIisAuthEnvValue.QueryStr())) ||
|
||||
FAILED(hr = pEnvironmentVarTable->InsertRecord(pIISAuthEntry)))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
// Compiler is complaining about conversion between PCWSTR and PWSTR here.
|
||||
// Explictly casting.
|
||||
pEnvironmentVarTable->FindKey((PWSTR)HOSTING_STARTUP_ASSEMBLIES_NAME, &pHostingEntry);
|
||||
if (pHostingEntry != NULL)
|
||||
{
|
||||
// user defined ASPNETCORE_HOSTINGSTARTUPASSEMBLIES in configuration
|
||||
// the value will be used in OutputEnvironmentVariables. Do nothing here
|
||||
pHostingEntry->Dereference();
|
||||
pHostingEntry = NULL;
|
||||
goto Skipped;
|
||||
}
|
||||
|
||||
//check whether ASPNETCORE_HOSTINGSTARTUPASSEMBLIES is defined in system
|
||||
dwResult = GetEnvironmentVariable(HOSTING_STARTUP_ASSEMBLIES_ENV_STR,
|
||||
strStartupAssemblyEnv.QueryStr(),
|
||||
strStartupAssemblyEnv.QuerySizeCCH());
|
||||
if (dwResult == 0)
|
||||
{
|
||||
dwError = GetLastError();
|
||||
// Windows API (e.g., CreateProcess) allows variable with empty string value
|
||||
// in such case dwResult will be 0 and dwError will also be 0
|
||||
// As UI and CMD does not allow empty value, ignore this environment var
|
||||
if (dwError != ERROR_ENVVAR_NOT_FOUND && dwError != ERROR_SUCCESS)
|
||||
{
|
||||
hr = HRESULT_FROM_WIN32(dwError);
|
||||
goto Finished;
|
||||
}
|
||||
}
|
||||
else if (dwResult > strStartupAssemblyEnv.QuerySizeCCH())
|
||||
{
|
||||
// have to increase the buffer and try get environment var again
|
||||
strStartupAssemblyEnv.Reset();
|
||||
strStartupAssemblyEnv.Resize(dwResult + (DWORD)wcslen(HOSTING_STARTUP_ASSEMBLIES_VALUE) + 1);
|
||||
dwResult = GetEnvironmentVariable(HOSTING_STARTUP_ASSEMBLIES_ENV_STR,
|
||||
strStartupAssemblyEnv.QueryStr(),
|
||||
strStartupAssemblyEnv.QuerySizeCCH());
|
||||
if (strStartupAssemblyEnv.IsEmpty())
|
||||
{
|
||||
hr = E_UNEXPECTED;
|
||||
goto Finished;
|
||||
}
|
||||
fFound = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
fFound = TRUE;
|
||||
}
|
||||
|
||||
strStartupAssemblyEnv.SyncWithBuffer();
|
||||
if (fFound)
|
||||
{
|
||||
strStartupAssemblyEnv.Append(L";");
|
||||
}
|
||||
strStartupAssemblyEnv.Append(HOSTING_STARTUP_ASSEMBLIES_VALUE);
|
||||
|
||||
// the environment variable was not defined, create it and add to hashtable
|
||||
pHostingEntry = new ENVIRONMENT_VAR_ENTRY();
|
||||
if (pHostingEntry == NULL)
|
||||
{
|
||||
hr = E_OUTOFMEMORY;
|
||||
goto Finished;
|
||||
}
|
||||
if (FAILED(hr = pHostingEntry->Initialize(HOSTING_STARTUP_ASSEMBLIES_NAME, strStartupAssemblyEnv.QueryStr())) ||
|
||||
FAILED(hr = pEnvironmentVarTable->InsertRecord(pHostingEntry)))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
Skipped:
|
||||
*ppEnvironmentVarTable = pEnvironmentVarTable;
|
||||
pEnvironmentVarTable = NULL;
|
||||
|
||||
Finished:
|
||||
if (pHostingEntry != NULL)
|
||||
{
|
||||
pHostingEntry->Dereference();
|
||||
pHostingEntry = NULL;
|
||||
}
|
||||
|
||||
if (pIISAuthEntry != NULL)
|
||||
{
|
||||
pIISAuthEntry->Dereference();
|
||||
pIISAuthEntry = NULL;
|
||||
}
|
||||
|
||||
if (pEnvironmentVarTable != NULL)
|
||||
{
|
||||
pEnvironmentVarTable->Clear();
|
||||
delete pEnvironmentVarTable;
|
||||
pEnvironmentVarTable = NULL;
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
private:
|
||||
ENVIRONMENT_VAR_HASH(const ENVIRONMENT_VAR_HASH &);
|
||||
|
|
|
|||
|
|
@ -28,8 +28,26 @@ namespace Microsoft.AspNetCore.Server.IISIntegration
|
|||
private readonly ILogger _logger;
|
||||
private readonly string _pairingToken;
|
||||
private readonly IApplicationLifetime _applicationLifetime;
|
||||
private readonly bool _isWebsocketsSupported;
|
||||
|
||||
public IISMiddleware(RequestDelegate next, ILoggerFactory loggerFactory, IOptions<IISOptions> options, string pairingToken, IAuthenticationSchemeProvider authentication, IApplicationLifetime applicationLifetime)
|
||||
// Can't break public API, so creating a second constructor to propagate the isWebsocketsSupported flag.
|
||||
public IISMiddleware(RequestDelegate next,
|
||||
ILoggerFactory loggerFactory,
|
||||
IOptions<IISOptions> options,
|
||||
string pairingToken,
|
||||
IAuthenticationSchemeProvider authentication,
|
||||
IApplicationLifetime applicationLifetime)
|
||||
: this(next, loggerFactory, options, pairingToken, isWebsocketsSupported: true, authentication, applicationLifetime)
|
||||
{
|
||||
}
|
||||
|
||||
public IISMiddleware(RequestDelegate next,
|
||||
ILoggerFactory loggerFactory,
|
||||
IOptions<IISOptions> options,
|
||||
string pairingToken,
|
||||
bool isWebsocketsSupported,
|
||||
IAuthenticationSchemeProvider authentication,
|
||||
IApplicationLifetime applicationLifetime)
|
||||
{
|
||||
if (next == null)
|
||||
{
|
||||
|
|
@ -63,6 +81,7 @@ namespace Microsoft.AspNetCore.Server.IISIntegration
|
|||
_pairingToken = pairingToken;
|
||||
_applicationLifetime = applicationLifetime;
|
||||
_logger = loggerFactory.CreateLogger<IISMiddleware>();
|
||||
_isWebsocketsSupported = isWebsocketsSupported;
|
||||
}
|
||||
|
||||
public async Task Invoke(HttpContext httpContext)
|
||||
|
|
@ -118,6 +137,13 @@ namespace Microsoft.AspNetCore.Server.IISIntegration
|
|||
}
|
||||
}
|
||||
|
||||
// Remove the upgrade feature if websockets are not supported by ANCM.
|
||||
// The feature must be removed on a per request basis as the Upgrade feature exists per request.
|
||||
if (!_isWebsocketsSupported)
|
||||
{
|
||||
httpContext.Features.Set<IHttpUpgradeFeature>(null);
|
||||
}
|
||||
|
||||
await _next(httpContext);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// 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.
|
||||
|
||||
using System;
|
||||
|
|
@ -12,11 +12,13 @@ namespace Microsoft.AspNetCore.Server.IISIntegration
|
|||
{
|
||||
private readonly string _pairingToken;
|
||||
private readonly PathString _pathBase;
|
||||
private readonly bool _isWebsocketsSupported;
|
||||
|
||||
internal IISSetupFilter(string pairingToken, PathString pathBase)
|
||||
internal IISSetupFilter(string pairingToken, PathString pathBase, bool isWebsocketsSupported)
|
||||
{
|
||||
_pairingToken = pairingToken;
|
||||
_pathBase = pathBase;
|
||||
_isWebsocketsSupported = isWebsocketsSupported;
|
||||
}
|
||||
|
||||
public Action<IApplicationBuilder> Configure(Action<IApplicationBuilder> next)
|
||||
|
|
@ -25,7 +27,7 @@ namespace Microsoft.AspNetCore.Server.IISIntegration
|
|||
{
|
||||
app.UsePathBase(_pathBase);
|
||||
app.UseForwardedHeaders();
|
||||
app.UseMiddleware<IISMiddleware>(_pairingToken);
|
||||
app.UseMiddleware<IISMiddleware>(_pairingToken, _isWebsocketsSupported);
|
||||
next(app);
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -183,7 +183,8 @@ namespace Microsoft.AspNetCore.Server.IISIntegration
|
|||
|
||||
bool IHttpResponseFeature.HasStarted => HasResponseStarted;
|
||||
|
||||
bool IHttpUpgradeFeature.IsUpgradableRequest => UpgradeAvailable;
|
||||
// The UpgradeAvailable Feature is set on the first request to the server.
|
||||
bool IHttpUpgradeFeature.IsUpgradableRequest => _websocketAvailability == WebsocketAvailabilityStatus.Available;
|
||||
|
||||
bool IFeatureCollection.IsReadOnly => false;
|
||||
|
||||
|
|
|
|||
|
|
@ -28,7 +28,8 @@ namespace Microsoft.AspNetCore.Server.IISIntegration
|
|||
private const int PauseWriterThreshold = 65536;
|
||||
private const int ResumeWriterTheshold = PauseWriterThreshold / 2;
|
||||
|
||||
private static bool UpgradeAvailable = (Environment.OSVersion.Version >= new Version(6, 2));
|
||||
// TODO make this static again.
|
||||
private static WebsocketAvailabilityStatus _websocketAvailability = WebsocketAvailabilityStatus.Uninitialized;
|
||||
|
||||
protected readonly IntPtr _pInProcessHandler;
|
||||
|
||||
|
|
@ -59,6 +60,7 @@ namespace Microsoft.AspNetCore.Server.IISIntegration
|
|||
private const string NtlmString = "NTLM";
|
||||
private const string NegotiateString = "Negotiate";
|
||||
private const string BasicString = "Basic";
|
||||
private const string WebSocketVersionString = "WEBSOCKET_VERSION";
|
||||
|
||||
internal unsafe IISHttpContext(MemoryPool<byte> memoryPool, IntPtr pInProcessHandler, IISOptions options, IISHttpServer server)
|
||||
: base((HttpApiTypes.HTTP_REQUEST*)NativeMethods.http_get_raw_request(pInProcessHandler))
|
||||
|
|
@ -121,7 +123,7 @@ namespace Microsoft.AspNetCore.Server.IISIntegration
|
|||
StatusCode = 200;
|
||||
|
||||
RequestHeaders = new RequestHeaders(this);
|
||||
HttpResponseHeaders = new HeaderCollection(); // TODO Optimize for known headers
|
||||
HttpResponseHeaders = new HeaderCollection();
|
||||
ResponseHeaders = HttpResponseHeaders;
|
||||
|
||||
if (options.ForwardWindowsAuthentication)
|
||||
|
|
@ -134,6 +136,26 @@ namespace Microsoft.AspNetCore.Server.IISIntegration
|
|||
}
|
||||
|
||||
ResetFeatureCollection();
|
||||
|
||||
// Check if the Http upgrade feature is available in IIS.
|
||||
// To check this, we can look at the server variable WEBSOCKET_VERSION
|
||||
// And see if there is a version. Same check that Katana did:
|
||||
// https://github.com/aspnet/AspNetKatana/blob/9f6e09af6bf203744feb5347121fe25f6eec06d8/src/Microsoft.Owin.Host.SystemWeb/OwinAppContext.cs#L125
|
||||
// Actively not locking here as acquiring a lock on every request will hurt perf more than checking the
|
||||
// server variables a few extra times if a bunch of requests hit the server at the same time.
|
||||
if (_websocketAvailability == WebsocketAvailabilityStatus.Uninitialized)
|
||||
{
|
||||
NativeMethods.http_get_server_variable(pInProcessHandler, WebSocketVersionString, out var webSocketsSupported);
|
||||
var webSocketsAvailable = !string.IsNullOrEmpty(webSocketsSupported);
|
||||
_websocketAvailability = webSocketsAvailable ?
|
||||
WebsocketAvailabilityStatus.Available :
|
||||
WebsocketAvailabilityStatus.NotAvailable;
|
||||
}
|
||||
|
||||
if (_websocketAvailability == WebsocketAvailabilityStatus.NotAvailable)
|
||||
{
|
||||
_currentIHttpUpgradeFeature = null;
|
||||
}
|
||||
}
|
||||
|
||||
RequestBody = new IISHttpRequestBody(this);
|
||||
|
|
@ -534,5 +556,12 @@ namespace Microsoft.AspNetCore.Server.IISIntegration
|
|||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private enum WebsocketAvailabilityStatus
|
||||
{
|
||||
Uninitialized = 1,
|
||||
Available,
|
||||
NotAvailable
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ namespace Microsoft.AspNetCore.Hosting
|
|||
private static readonly string ServerPath = "APPL_PATH";
|
||||
private static readonly string PairingToken = "TOKEN";
|
||||
private static readonly string IISAuth = "IIS_HTTPAUTH";
|
||||
private static readonly string IISWebSockets = "IIS_WEBSOCKETS_SUPPORTED";
|
||||
|
||||
/// <summary>
|
||||
/// Configures the port and base path the server should listen on when running behind AspNetCoreModule.
|
||||
|
|
@ -74,6 +75,14 @@ namespace Microsoft.AspNetCore.Hosting
|
|||
var path = hostBuilder.GetSetting(ServerPath) ?? Environment.GetEnvironmentVariable($"ASPNETCORE_{ServerPath}");
|
||||
var pairingToken = hostBuilder.GetSetting(PairingToken) ?? Environment.GetEnvironmentVariable($"ASPNETCORE_{PairingToken}");
|
||||
var iisAuth = hostBuilder.GetSetting(IISAuth) ?? Environment.GetEnvironmentVariable($"ASPNETCORE_{IISAuth}");
|
||||
var websocketsSupported = hostBuilder.GetSetting(IISWebSockets) ?? Environment.GetEnvironmentVariable($"ASPNETCORE_{IISWebSockets}");
|
||||
|
||||
bool isWebSocketsSupported;
|
||||
if (!bool.TryParse(websocketsSupported, out isWebSocketsSupported))
|
||||
{
|
||||
// If the websocket support variable is not set, we will always fallback to assuming websockets are enabled.
|
||||
isWebSocketsSupported = (Environment.OSVersion.Version >= new Version(6, 2));
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(port) && !string.IsNullOrEmpty(path) && !string.IsNullOrEmpty(pairingToken))
|
||||
{
|
||||
|
|
@ -107,7 +116,7 @@ namespace Microsoft.AspNetCore.Hosting
|
|||
// Delay register the url so users don't accidently overwrite it.
|
||||
hostBuilder.UseSetting(WebHostDefaults.ServerUrlsKey, address);
|
||||
hostBuilder.PreferHostingUrls(true);
|
||||
services.AddSingleton<IStartupFilter>(new IISSetupFilter(pairingToken, new PathString(path)));
|
||||
services.AddSingleton<IStartupFilter>(new IISSetupFilter(pairingToken, new PathString(path), isWebSocketsSupported));
|
||||
services.Configure<ForwardedHeadersOptions>(options =>
|
||||
{
|
||||
options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
|
||||
|
|
|
|||
|
|
@ -208,6 +208,7 @@
|
|||
<ItemGroup>
|
||||
<ClInclude Include="aspnetcore_event.h" />
|
||||
<ClInclude Include="disconnectcontext.h" />
|
||||
<ClInclude Include="environmentvariablehelpers.h" />
|
||||
<ClInclude Include="sttimer.h" />
|
||||
<ClInclude Include="outofprocess\forwarderconnection.h" />
|
||||
<ClInclude Include="outofprocess\processmanager.h" />
|
||||
|
|
|
|||
|
|
@ -80,6 +80,7 @@
|
|||
<ClInclude Include="aspnetcore_event.h" />
|
||||
<ClInclude Include="sttimer.h" />
|
||||
<ClInclude Include="disconnectcontext.h" />
|
||||
<ClInclude Include="environmentvariablehelpers.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="Source.def" />
|
||||
|
|
|
|||
|
|
@ -112,8 +112,6 @@ InitializeGlobalConfiguration(
|
|||
g_fNsiApiNotSupported = TRUE;
|
||||
}
|
||||
|
||||
// WebSocket is supported on Win8 and above only
|
||||
// todo: test on win7
|
||||
g_fWebSocketSupported = IsWindows8OrGreater();
|
||||
|
||||
g_fGlobalInitialize = TRUE;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,421 @@
|
|||
// 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 "precomp.hxx"
|
||||
|
||||
class ENVIRONMENT_VAR_HELPERS
|
||||
{
|
||||
|
||||
public:
|
||||
static
|
||||
VOID
|
||||
CopyToMultiSz(
|
||||
ENVIRONMENT_VAR_ENTRY * pEntry,
|
||||
PVOID pvData
|
||||
)
|
||||
{
|
||||
STRU strTemp;
|
||||
MULTISZ *pMultiSz = static_cast<MULTISZ *>(pvData);
|
||||
DBG_ASSERT(pMultiSz);
|
||||
DBG_ASSERT(pEntry);
|
||||
strTemp.Copy(pEntry->QueryName());
|
||||
strTemp.Append(pEntry->QueryValue());
|
||||
pMultiSz->Append(strTemp.QueryStr());
|
||||
}
|
||||
|
||||
static
|
||||
VOID
|
||||
CopyToTable(
|
||||
ENVIRONMENT_VAR_ENTRY * pEntry,
|
||||
PVOID pvData
|
||||
)
|
||||
{
|
||||
// best effort copy, ignore the failure
|
||||
ENVIRONMENT_VAR_ENTRY * pNewEntry = new ENVIRONMENT_VAR_ENTRY();
|
||||
if (pNewEntry != NULL)
|
||||
{
|
||||
pNewEntry->Initialize(pEntry->QueryName(), pEntry->QueryValue());
|
||||
ENVIRONMENT_VAR_HASH *pHash = static_cast<ENVIRONMENT_VAR_HASH *>(pvData);
|
||||
DBG_ASSERT(pHash);
|
||||
pHash->InsertRecord(pNewEntry);
|
||||
// Need to dereference as InsertRecord references it now
|
||||
pNewEntry->Dereference();
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
VOID
|
||||
AppendEnvironmentVariables
|
||||
(
|
||||
ENVIRONMENT_VAR_ENTRY * pEntry,
|
||||
PVOID pvData
|
||||
)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
DWORD dwResult = 0;
|
||||
DWORD dwError = 0;
|
||||
STRU struNameBuffer;
|
||||
STACK_STRU(struValueBuffer, 300);
|
||||
BOOL fFound = FALSE;
|
||||
|
||||
HRESULT* pHr = static_cast<HRESULT*>(pvData);
|
||||
|
||||
// pEntry->QueryName includes the trailing =, remove it before calling stru
|
||||
if (FAILED(hr = struNameBuffer.Copy(pEntry->QueryName())))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
dwResult = struNameBuffer.LastIndexOf(L'=');
|
||||
if (dwResult != -1)
|
||||
{
|
||||
struNameBuffer.QueryStr()[dwResult] = L'\0';
|
||||
if (FAILED(hr = struNameBuffer.SyncWithBuffer()))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
}
|
||||
|
||||
dwResult = GetEnvironmentVariable(struNameBuffer.QueryStr(), struValueBuffer.QueryStr(), struValueBuffer.QuerySizeCCH());
|
||||
if (dwResult == 0)
|
||||
{
|
||||
dwError = GetLastError();
|
||||
// Windows API (e.g., CreateProcess) allows variable with empty string value
|
||||
// in such case dwResult will be 0 and dwError will also be 0
|
||||
// As UI and CMD does not allow empty value, ignore this environment var
|
||||
if (dwError != ERROR_ENVVAR_NOT_FOUND && dwError != ERROR_SUCCESS)
|
||||
{
|
||||
hr = HRESULT_FROM_WIN32(dwError);
|
||||
goto Finished;
|
||||
}
|
||||
}
|
||||
else if (dwResult > struValueBuffer.QuerySizeCCH())
|
||||
{
|
||||
// have to increase the buffer and try get environment var again
|
||||
struValueBuffer.Reset();
|
||||
struValueBuffer.Resize(dwResult + (DWORD)wcslen(pEntry->QueryValue()) + 2); // for null char and semicolon
|
||||
dwResult = GetEnvironmentVariable(struNameBuffer.QueryStr(),
|
||||
struValueBuffer.QueryStr(),
|
||||
struValueBuffer.QuerySizeCCH());
|
||||
if (struValueBuffer.IsEmpty())
|
||||
{
|
||||
hr = E_UNEXPECTED;
|
||||
goto Finished;
|
||||
}
|
||||
fFound = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
fFound = TRUE;
|
||||
}
|
||||
|
||||
if (FAILED(hr = struValueBuffer.SyncWithBuffer()))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
if (fFound)
|
||||
{
|
||||
if (FAILED(hr = struValueBuffer.Append(L";")))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
}
|
||||
if (FAILED(hr = struValueBuffer.Append(pEntry->QueryValue())))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
if (FAILED(hr = pEntry->Initialize(pEntry->QueryName(), struValueBuffer.QueryStr())))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
Finished:
|
||||
if (FAILED(hr))
|
||||
{
|
||||
*pHr = hr;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
static
|
||||
VOID
|
||||
SetEnvironmentVariables
|
||||
(
|
||||
ENVIRONMENT_VAR_ENTRY * pEntry,
|
||||
PVOID pvData
|
||||
)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(pvData);
|
||||
HRESULT hr = S_OK;
|
||||
DWORD dwResult = 0;
|
||||
STRU struNameBuffer;
|
||||
|
||||
HRESULT* pHr = static_cast<HRESULT*>(pvData);
|
||||
|
||||
// pEntry->QueryName includes the trailing =, remove it before calling SetEnvironmentVariable.
|
||||
if (FAILED(hr = struNameBuffer.Copy(pEntry->QueryName())))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
dwResult = struNameBuffer.LastIndexOf(L'=');
|
||||
if (dwResult != -1)
|
||||
{
|
||||
struNameBuffer.QueryStr()[dwResult] = L'\0';
|
||||
if (FAILED(hr = struNameBuffer.SyncWithBuffer()))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
}
|
||||
|
||||
dwResult = SetEnvironmentVariable(struNameBuffer.QueryStr(), pEntry->QueryValue());
|
||||
if (dwResult == 0)
|
||||
{
|
||||
hr = HRESULT_FROM_WIN32(GetLastError());
|
||||
}
|
||||
|
||||
Finished:
|
||||
if (FAILED(hr))
|
||||
{
|
||||
*pHr = hr;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
static
|
||||
HRESULT
|
||||
InitEnvironmentVariablesTable
|
||||
(
|
||||
_In_ ENVIRONMENT_VAR_HASH* pInEnvironmentVarTable,
|
||||
_In_ BOOL fWindowsAuthEnabled,
|
||||
_In_ BOOL fBasicAuthEnabled,
|
||||
_In_ BOOL fAnonymousAuthEnabled,
|
||||
_Out_ ENVIRONMENT_VAR_HASH** ppEnvironmentVarTable
|
||||
)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
BOOL fFound = FALSE;
|
||||
DWORD dwResult, dwError;
|
||||
STRU strIisAuthEnvValue;
|
||||
STACK_STRU(strStartupAssemblyEnv, 1024);
|
||||
ENVIRONMENT_VAR_ENTRY* pHostingEntry = NULL;
|
||||
ENVIRONMENT_VAR_ENTRY* pIISAuthEntry = NULL;
|
||||
ENVIRONMENT_VAR_HASH* pEnvironmentVarTable = NULL;
|
||||
|
||||
pEnvironmentVarTable = new ENVIRONMENT_VAR_HASH();
|
||||
if (pEnvironmentVarTable == NULL)
|
||||
{
|
||||
hr = E_OUTOFMEMORY;
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
//
|
||||
// few environment variables expected, small bucket size for hash table
|
||||
//
|
||||
if (FAILED(hr = pEnvironmentVarTable->Initialize(37 /*prime*/)))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
// copy the envirable hash table (from configuration) to a temp one as we may need to remove elements
|
||||
pInEnvironmentVarTable->Apply(ENVIRONMENT_VAR_HELPERS::CopyToTable, pEnvironmentVarTable);
|
||||
if (pEnvironmentVarTable->Count() != pInEnvironmentVarTable->Count())
|
||||
{
|
||||
// hash table copy failed
|
||||
hr = E_UNEXPECTED;
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
pEnvironmentVarTable->FindKey((PWSTR)ASPNETCORE_IIS_AUTH_ENV_STR, &pIISAuthEntry);
|
||||
if (pIISAuthEntry != NULL)
|
||||
{
|
||||
// user defined ASPNETCORE_IIS_HTTPAUTH in configuration, wipe it off
|
||||
pIISAuthEntry->Dereference();
|
||||
pEnvironmentVarTable->DeleteKey((PWSTR)ASPNETCORE_IIS_AUTH_ENV_STR);
|
||||
}
|
||||
|
||||
if (fWindowsAuthEnabled)
|
||||
{
|
||||
strIisAuthEnvValue.Copy(ASPNETCORE_IIS_AUTH_WINDOWS);
|
||||
}
|
||||
|
||||
if (fBasicAuthEnabled)
|
||||
{
|
||||
strIisAuthEnvValue.Append(ASPNETCORE_IIS_AUTH_BASIC);
|
||||
}
|
||||
|
||||
if (fAnonymousAuthEnabled)
|
||||
{
|
||||
strIisAuthEnvValue.Append(ASPNETCORE_IIS_AUTH_ANONYMOUS);
|
||||
}
|
||||
|
||||
if (strIisAuthEnvValue.IsEmpty())
|
||||
{
|
||||
strIisAuthEnvValue.Copy(ASPNETCORE_IIS_AUTH_NONE);
|
||||
}
|
||||
|
||||
pIISAuthEntry = new ENVIRONMENT_VAR_ENTRY();
|
||||
if (pIISAuthEntry == NULL)
|
||||
{
|
||||
hr = E_OUTOFMEMORY;
|
||||
goto Finished;
|
||||
}
|
||||
if (FAILED(hr = pIISAuthEntry->Initialize(ASPNETCORE_IIS_AUTH_ENV_STR, strIisAuthEnvValue.QueryStr())) ||
|
||||
FAILED(hr = pEnvironmentVarTable->InsertRecord(pIISAuthEntry)))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
// Compiler is complaining about conversion between PCWSTR and PWSTR here.
|
||||
// Explictly casting.
|
||||
pEnvironmentVarTable->FindKey((PWSTR)HOSTING_STARTUP_ASSEMBLIES_NAME, &pHostingEntry);
|
||||
if (pHostingEntry != NULL)
|
||||
{
|
||||
// user defined ASPNETCORE_HOSTINGSTARTUPASSEMBLIES in configuration
|
||||
// the value will be used in OutputEnvironmentVariables. Do nothing here
|
||||
pHostingEntry->Dereference();
|
||||
pHostingEntry = NULL;
|
||||
goto Skipped;
|
||||
}
|
||||
|
||||
//check whether ASPNETCORE_HOSTINGSTARTUPASSEMBLIES is defined in system
|
||||
dwResult = GetEnvironmentVariable(HOSTING_STARTUP_ASSEMBLIES_ENV_STR,
|
||||
strStartupAssemblyEnv.QueryStr(),
|
||||
strStartupAssemblyEnv.QuerySizeCCH());
|
||||
if (dwResult == 0)
|
||||
{
|
||||
dwError = GetLastError();
|
||||
// Windows API (e.g., CreateProcess) allows variable with empty string value
|
||||
// in such case dwResult will be 0 and dwError will also be 0
|
||||
// As UI and CMD does not allow empty value, ignore this environment var
|
||||
if (dwError != ERROR_ENVVAR_NOT_FOUND && dwError != ERROR_SUCCESS)
|
||||
{
|
||||
hr = HRESULT_FROM_WIN32(dwError);
|
||||
goto Finished;
|
||||
}
|
||||
}
|
||||
else if (dwResult > strStartupAssemblyEnv.QuerySizeCCH())
|
||||
{
|
||||
// have to increase the buffer and try get environment var again
|
||||
strStartupAssemblyEnv.Reset();
|
||||
strStartupAssemblyEnv.Resize(dwResult + (DWORD)wcslen(HOSTING_STARTUP_ASSEMBLIES_VALUE) + 1);
|
||||
dwResult = GetEnvironmentVariable(HOSTING_STARTUP_ASSEMBLIES_ENV_STR,
|
||||
strStartupAssemblyEnv.QueryStr(),
|
||||
strStartupAssemblyEnv.QuerySizeCCH());
|
||||
if (strStartupAssemblyEnv.IsEmpty())
|
||||
{
|
||||
hr = E_UNEXPECTED;
|
||||
goto Finished;
|
||||
}
|
||||
fFound = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
fFound = TRUE;
|
||||
}
|
||||
|
||||
strStartupAssemblyEnv.SyncWithBuffer();
|
||||
if (fFound)
|
||||
{
|
||||
strStartupAssemblyEnv.Append(L";");
|
||||
}
|
||||
strStartupAssemblyEnv.Append(HOSTING_STARTUP_ASSEMBLIES_VALUE);
|
||||
|
||||
// the environment variable was not defined, create it and add to hashtable
|
||||
pHostingEntry = new ENVIRONMENT_VAR_ENTRY();
|
||||
if (pHostingEntry == NULL)
|
||||
{
|
||||
hr = E_OUTOFMEMORY;
|
||||
goto Finished;
|
||||
}
|
||||
if (FAILED(hr = pHostingEntry->Initialize(HOSTING_STARTUP_ASSEMBLIES_NAME, strStartupAssemblyEnv.QueryStr())) ||
|
||||
FAILED(hr = pEnvironmentVarTable->InsertRecord(pHostingEntry)))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
Skipped:
|
||||
*ppEnvironmentVarTable = pEnvironmentVarTable;
|
||||
pEnvironmentVarTable = NULL;
|
||||
|
||||
Finished:
|
||||
if (pHostingEntry != NULL)
|
||||
{
|
||||
pHostingEntry->Dereference();
|
||||
pHostingEntry = NULL;
|
||||
}
|
||||
|
||||
if (pIISAuthEntry != NULL)
|
||||
{
|
||||
pIISAuthEntry->Dereference();
|
||||
pIISAuthEntry = NULL;
|
||||
}
|
||||
|
||||
if (pEnvironmentVarTable != NULL)
|
||||
{
|
||||
pEnvironmentVarTable->Clear();
|
||||
delete pEnvironmentVarTable;
|
||||
pEnvironmentVarTable = NULL;
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
HRESULT
|
||||
AddWebsocketEnabledToEnvironmentVariables
|
||||
(
|
||||
_Inout_ ENVIRONMENT_VAR_HASH* pInEnvironmentVarTable,
|
||||
_In_ BOOL fWebsocketsEnabled
|
||||
)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
ENVIRONMENT_VAR_ENTRY* pIISWebsocketEntry = NULL;
|
||||
STACK_STRU(strIISWebsocketEnvValue, 40);
|
||||
|
||||
// We only need to set the WEBSOCKET_SUPPORTED environment variable for out of process
|
||||
pInEnvironmentVarTable->FindKey((PWSTR)ASPNETCORE_IIS_WEBSOCKETS_SUPPORTED_ENV_STR, &pIISWebsocketEntry);
|
||||
if (pIISWebsocketEntry != NULL)
|
||||
{
|
||||
// user defined ASPNETCORE_IIS_WEBSOCKETS in configuration, wipe it off
|
||||
pIISWebsocketEntry->Dereference();
|
||||
pInEnvironmentVarTable->DeleteKey((PWSTR)ASPNETCORE_IIS_WEBSOCKETS_SUPPORTED_ENV_STR);
|
||||
}
|
||||
// Set either true or false for the WebsocketEnvValue.
|
||||
if (fWebsocketsEnabled)
|
||||
{
|
||||
if (FAILED(hr = strIISWebsocketEnvValue.Copy(L"true")))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (FAILED(hr = strIISWebsocketEnvValue.Copy(L"false")))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
}
|
||||
|
||||
pIISWebsocketEntry = new ENVIRONMENT_VAR_ENTRY();
|
||||
if (pIISWebsocketEntry == NULL)
|
||||
{
|
||||
hr = E_OUTOFMEMORY;
|
||||
goto Finished;
|
||||
}
|
||||
if (FAILED(hr = pIISWebsocketEntry->Initialize(ASPNETCORE_IIS_WEBSOCKETS_SUPPORTED_ENV_STR, strIISWebsocketEnvValue.QueryStr())) ||
|
||||
FAILED(hr = pInEnvironmentVarTable->InsertRecord(pIISWebsocketEntry)))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
Finished:
|
||||
return hr;
|
||||
}
|
||||
public:
|
||||
ENVIRONMENT_VAR_HELPERS();
|
||||
~ENVIRONMENT_VAR_HELPERS();
|
||||
};
|
||||
|
||||
|
|
@ -726,7 +726,7 @@ IN_PROCESS_APPLICATION::SetEnvironementVariablesOnWorkerProcess(
|
|||
{
|
||||
HRESULT hr = S_OK;
|
||||
ENVIRONMENT_VAR_HASH* pHashTable = NULL;
|
||||
if (FAILED(hr = ENVIRONMENT_VAR_HASH::InitEnvironmentVariablesTable(
|
||||
if (FAILED(hr = ENVIRONMENT_VAR_HELPERS::InitEnvironmentVariablesTable(
|
||||
m_pConfig->QueryEnvironmentVariables(),
|
||||
m_pConfig->QueryWindowsAuthEnabled(),
|
||||
m_pConfig->QueryBasicAuthEnabled(),
|
||||
|
|
@ -736,8 +736,16 @@ IN_PROCESS_APPLICATION::SetEnvironementVariablesOnWorkerProcess(
|
|||
goto Finished;
|
||||
}
|
||||
|
||||
pHashTable->Apply(ENVIRONMENT_VAR_HASH::AppendEnvironmentVariables, NULL);
|
||||
pHashTable->Apply(ENVIRONMENT_VAR_HASH::SetEnvironmentVariables, NULL);
|
||||
pHashTable->Apply(ENVIRONMENT_VAR_HELPERS::AppendEnvironmentVariables, &hr);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
pHashTable->Apply(ENVIRONMENT_VAR_HELPERS::SetEnvironmentVariables, &hr);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
Finished:
|
||||
return hr;
|
||||
}
|
||||
|
|
@ -770,15 +778,15 @@ IN_PROCESS_APPLICATION::ExecuteApplication(
|
|||
goto Finished;
|
||||
}
|
||||
|
||||
// There can only ever be a single instance of .NET Core
|
||||
// loaded in the process but we need to get config information to boot it up in the
|
||||
// first place. This is happening in an execute request handler and everyone waits
|
||||
// until this initialization is done.
|
||||
if (FAILED(hr = SetEnvironementVariablesOnWorkerProcess()))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
// There can only ever be a single instance of .NET Core
|
||||
// loaded in the process but we need to get config information to boot it up in the
|
||||
// first place. This is happening in an execute request handler and everyone waits
|
||||
// until this initialization is done.
|
||||
// We set a static so that managed code can call back into this instance and
|
||||
// set the callbacks
|
||||
s_Application = this;
|
||||
|
|
|
|||
|
|
@ -225,6 +225,7 @@ PROCESS_MANAGER::GetProcess(
|
|||
pConfig->QueryAnonymousAuthEnabled(),
|
||||
pConfig->QueryEnvironmentVariables(),
|
||||
pConfig->QueryStdoutLogEnabled(),
|
||||
pConfig->QueryWebSocketEnabled(),
|
||||
pConfig->QueryStdoutLogFile(),
|
||||
pConfig->QueryApplicationPhysicalPath(), // physical path
|
||||
pConfig->QueryApplicationPath(), // app path
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ SERVER_PROCESS::Initialize(
|
|||
BOOL fAnonymousAuthEnabled,
|
||||
ENVIRONMENT_VAR_HASH *pEnvironmentVariables,
|
||||
BOOL fStdoutLogEnabled,
|
||||
BOOL fWebsocketsEnabled,
|
||||
STRU *pstruStdoutLogFile,
|
||||
STRU *pszAppPhysicalPath,
|
||||
STRU *pszAppPath,
|
||||
|
|
@ -38,6 +39,7 @@ SERVER_PROCESS::Initialize(
|
|||
m_fWindowsAuthEnabled = fWindowsAuthEnabled;
|
||||
m_fBasicAuthEnabled = fBasicAuthEnabled;
|
||||
m_fAnonymousAuthEnabled = fAnonymousAuthEnabled;
|
||||
m_fWebsocketsEnabled = fWebsocketsEnabled;
|
||||
m_pProcessManager->ReferenceProcessManager();
|
||||
|
||||
if (FAILED(hr = m_ProcessPath.Copy(*pszProcessExePath)) ||
|
||||
|
|
@ -402,7 +404,7 @@ SERVER_PROCESS::OutputEnvironmentVariables
|
|||
pszCurrentVariable = pszNextVariable;
|
||||
}
|
||||
// append the remaining env variable in hash table
|
||||
pEnvironmentVarTable->Apply(ENVIRONMENT_VAR_HASH::CopyToMultiSz, pmszOutput);
|
||||
pEnvironmentVarTable->Apply(ENVIRONMENT_VAR_HELPERS::CopyToMultiSz, pmszOutput);
|
||||
|
||||
Finished:
|
||||
if (pszEnvironmentVariables != NULL)
|
||||
|
|
@ -755,7 +757,7 @@ SERVER_PROCESS::StartProcess(
|
|||
goto Failure;
|
||||
}
|
||||
|
||||
if (FAILED(hr = ENVIRONMENT_VAR_HASH::InitEnvironmentVariablesTable(
|
||||
if (FAILED(hr = ENVIRONMENT_VAR_HELPERS::InitEnvironmentVariablesTable(
|
||||
m_pEnvironmentVarTable,
|
||||
m_fWindowsAuthEnabled,
|
||||
m_fBasicAuthEnabled,
|
||||
|
|
@ -766,6 +768,16 @@ SERVER_PROCESS::StartProcess(
|
|||
goto Failure;
|
||||
}
|
||||
|
||||
if (FAILED(hr = ENVIRONMENT_VAR_HELPERS::AddWebsocketEnabledToEnvironmentVariables(
|
||||
pHashTable,
|
||||
m_fWebsocketsEnabled
|
||||
)))
|
||||
{
|
||||
pStrStage = L"AddWebsocketEnabledToEnvironmentVariables";
|
||||
goto Failure;
|
||||
|
||||
}
|
||||
|
||||
//
|
||||
// setup the the port that the backend process will listen on
|
||||
//
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ public:
|
|||
_In_ BOOL fAnonymousAuthEnabled,
|
||||
_In_ ENVIRONMENT_VAR_HASH* pEnvironmentVariables,
|
||||
_In_ BOOL fStdoutLogEnabled,
|
||||
_In_ BOOL fWebsocketsEnabled,
|
||||
_In_ STRU *pstruStdoutLogFile,
|
||||
_In_ STRU *pszAppPhysicalPath,
|
||||
_In_ STRU *pszAppPath,
|
||||
|
|
@ -222,6 +223,7 @@ private:
|
|||
BOOL m_fWindowsAuthEnabled;
|
||||
BOOL m_fBasicAuthEnabled;
|
||||
BOOL m_fAnonymousAuthEnabled;
|
||||
BOOL m_fWebsocketsEnabled;
|
||||
|
||||
STTIMER m_Timer;
|
||||
SOCKET m_socket;
|
||||
|
|
|
|||
|
|
@ -59,6 +59,7 @@
|
|||
#include "aspnetcore_event.h"
|
||||
#include "aspnetcore_msg.h"
|
||||
#include "disconnectcontext.h"
|
||||
#include "environmentvariablehelpers.h"
|
||||
#include "sttimer.h"
|
||||
#include ".\inprocess\InProcessHandler.h"
|
||||
#include ".\inprocess\inprocessapplication.h"
|
||||
|
|
|
|||
|
|
@ -212,9 +212,9 @@
|
|||
-->
|
||||
<globalModules>
|
||||
<add name="UriCacheModule" image="%IIS_BIN%\cachuri.dll" />
|
||||
<!-- <add name="FileCacheModule" image="%IIS_BIN%\cachfile.dll" /> -->
|
||||
<!-- <add name="FileCacheModule" image="%IIS_BIN%\cachfile.dll" /> -->
|
||||
<add name="TokenCacheModule" image="%IIS_BIN%\cachtokn.dll" />
|
||||
<!-- <add name="HttpCacheModule" image="%IIS_BIN%\cachhttp.dll" /> -->
|
||||
<!-- <add name="HttpCacheModule" image="%IIS_BIN%\cachhttp.dll" /> -->
|
||||
<add name="DynamicCompressionModule" image="%IIS_BIN%\compdyn.dll" />
|
||||
<add name="StaticCompressionModule" image="%IIS_BIN%\compstat.dll" />
|
||||
<add name="DefaultDocumentModule" image="%IIS_BIN%\defdoc.dll" />
|
||||
|
|
@ -228,7 +228,7 @@
|
|||
<add name="UrlAuthorizationModule" image="%IIS_BIN%\urlauthz.dll" />
|
||||
<add name="BasicAuthenticationModule" image="%IIS_BIN%\authbas.dll" />
|
||||
<add name="WindowsAuthenticationModule" image="%IIS_BIN%\authsspi.dll" />
|
||||
<!-- <add name="DigestAuthenticationModule" image="%IIS_BIN%\authmd5.dll" /> -->
|
||||
<!-- <add name="DigestAuthenticationModule" image="%IIS_BIN%\authmd5.dll" /> -->
|
||||
<add name="IISCertificateMappingAuthenticationModule" image="%IIS_BIN%\authmap.dll" />
|
||||
<add name="IpRestrictionModule" image="%IIS_BIN%\iprestr.dll" />
|
||||
<add name="DynamicIpRestrictionModule" image="%IIS_BIN%\diprestr.dll" />
|
||||
|
|
@ -236,14 +236,14 @@
|
|||
<add name="CustomLoggingModule" image="%IIS_BIN%\logcust.dll" />
|
||||
<add name="CustomErrorModule" image="%IIS_BIN%\custerr.dll" />
|
||||
<add name="HttpLoggingModule" image="%IIS_BIN%\loghttp.dll" />
|
||||
<!-- <add name="TracingModule" image="%IIS_BIN%\iisetw.dll" /> -->
|
||||
<!-- <add name="TracingModule" image="%IIS_BIN%\iisetw.dll" /> -->
|
||||
<add name="FailedRequestsTracingModule" image="%IIS_BIN%\iisfreb.dll" />
|
||||
<add name="RequestMonitorModule" image="%IIS_BIN%\iisreqs.dll" />
|
||||
<add name="IsapiModule" image="%IIS_BIN%\isapi.dll" />
|
||||
<add name="IsapiFilterModule" image="%IIS_BIN%\filter.dll" />
|
||||
<add name="CgiModule" image="%IIS_BIN%\cgi.dll" />
|
||||
<add name="FastCgiModule" image="%IIS_BIN%\iisfcgi.dll" />
|
||||
<!-- <add name="WebDAVModule" image="%IIS_BIN%\webdav.dll" /> -->
|
||||
<!-- <add name="WebDAVModule" image="%IIS_BIN%\webdav.dll" /> -->
|
||||
<add name="RewriteModule" image="%IIS_BIN%\rewrite.dll" />
|
||||
<add name="ConfigurationValidationModule" image="%IIS_BIN%\validcfg.dll" />
|
||||
<add name="ApplicationInitializationModule" image="%IIS_BIN%\warmup.dll" />
|
||||
|
|
@ -799,7 +799,7 @@
|
|||
|
||||
<tracing>
|
||||
|
||||
<traceProviderDefinitions>
|
||||
<traceProviderDefinitions>
|
||||
<add name="WWW Server" guid="{3a2a4e84-4c21-4981-ae10-3fda0d9b0f83}">
|
||||
<areas>
|
||||
<clear />
|
||||
|
|
@ -870,7 +870,7 @@
|
|||
<authoringRules />
|
||||
</webdav>
|
||||
<applicationInitialization />
|
||||
<webSocket />
|
||||
<webSocket enabled="false" />
|
||||
|
||||
</system.webServer>
|
||||
<location path="" overrideMode="Allow">
|
||||
|
|
@ -5,15 +5,19 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Include="*.config" CopyToOutputDirectory="PreserveNewest" />
|
||||
<Content Include="AppHostConfig\*.config" CopyToOutputDirectory="PreserveNewest" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.Server.IISIntegration\Microsoft.AspNetCore.Server.IISIntegration.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Server.IntegrationTesting" Version="$(MicrosoftAspNetCoreServerIntegrationTestingPackageVersion)" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Testing" Version="$(MicrosoftExtensionsLoggingTestingPackageVersion)" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging" Version="$(MicrosoftExtensionsLoggingPackageVersion)" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="$(MicrosoftExtensionsLoggingConsolePackageVersion)" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="$(MicrosoftExtensionsLoggingDebugPackageVersion)" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging" Version="$(MicrosoftExtensionsLoggingPackageVersion)" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Testing" Version="$(MicrosoftExtensionsLoggingTestingPackageVersion)" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="$(MicrosoftNETTestSdkPackageVersion)" />
|
||||
<PackageReference Include="xunit" Version="$(XunitPackageVersion)" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="$(XunitRunnerVisualStudioPackageVersion)" />
|
||||
|
|
|
|||
|
|
@ -6,11 +6,10 @@
|
|||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Server.IIS.FunctionalTests;
|
||||
using Microsoft.AspNetCore.Testing.xunit;
|
||||
using Xunit;
|
||||
|
||||
namespace IISIntegration.IISServerFunctionalTests
|
||||
namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
||||
{
|
||||
[Collection(IISTestSiteCollection.Name)]
|
||||
public class AuthenticationTests
|
||||
|
|
@ -5,7 +5,7 @@ using System.Threading.Tasks;
|
|||
using Microsoft.AspNetCore.Testing.xunit;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests
|
||||
namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
||||
{
|
||||
[Collection(IISTestSiteCollection.Name)]
|
||||
public class EnvironmentVariableTests
|
||||
|
|
@ -6,7 +6,7 @@ using System.Threading.Tasks;
|
|||
using Microsoft.AspNetCore.Testing.xunit;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests
|
||||
namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
||||
{
|
||||
[Collection(IISTestSiteCollection.Name)]
|
||||
public class FeatureCollectionTest
|
||||
|
|
@ -6,14 +6,14 @@ using System.Threading.Tasks;
|
|||
using Microsoft.AspNetCore.Testing.xunit;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests
|
||||
namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
||||
{
|
||||
[Collection(IISTestSiteCollection.Name)]
|
||||
public class HelloWorldTests
|
||||
public class HelloWorldInProcessTests
|
||||
{
|
||||
private readonly IISTestSiteFixture _fixture;
|
||||
|
||||
public HelloWorldTests(IISTestSiteFixture fixture)
|
||||
public HelloWorldInProcessTests(IISTestSiteFixture fixture)
|
||||
{
|
||||
_fixture = fixture;
|
||||
}
|
||||
|
|
@ -5,7 +5,7 @@ using System.Threading.Tasks;
|
|||
using Microsoft.AspNetCore.Testing.xunit;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests
|
||||
namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
||||
{
|
||||
[Collection(IISTestSiteCollection.Name)]
|
||||
public class LargeResponseBodyTests
|
||||
|
|
@ -8,7 +8,7 @@ using Microsoft.AspNetCore.Testing.xunit;
|
|||
using Microsoft.Net.Http.Headers;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests
|
||||
namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
||||
{
|
||||
[Collection(IISTestSiteCollection.Name)]
|
||||
|
||||
|
|
@ -5,7 +5,7 @@ using System.Threading.Tasks;
|
|||
using Microsoft.AspNetCore.Testing.xunit;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests
|
||||
namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
||||
{
|
||||
[Collection(IISTestSiteCollection.Name)]
|
||||
public class ResponseInvalidOrderingTest
|
||||
|
|
@ -5,7 +5,7 @@ using System.Threading.Tasks;
|
|||
using Microsoft.AspNetCore.Testing.xunit;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests
|
||||
namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
||||
{
|
||||
[Collection(IISTestSiteCollection.Name)]
|
||||
public class ServerVariablesTest
|
||||
|
|
@ -41,10 +41,10 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
|||
{
|
||||
var logger = loggerFactory.CreateLogger("HelloWorldTest");
|
||||
|
||||
var deploymentParameters = new DeploymentParameters(Helpers.GetTestSitesPath(), serverType, runtimeFlavor, architecture)
|
||||
var deploymentParameters = new DeploymentParameters(Helpers.GetOutOfProcessTestSitesPath(), serverType, runtimeFlavor, architecture)
|
||||
{
|
||||
EnvironmentName = "HelloWorld", // Will pick the Start class named 'StartupHelloWorld',
|
||||
ServerConfigTemplateContent = (serverType == ServerType.IISExpress) ? File.ReadAllText("Http.config") : null,
|
||||
ServerConfigTemplateContent = (serverType == ServerType.IISExpress) ? File.ReadAllText("AppHostConfig/Http.config") : null,
|
||||
SiteName = "HttpTestSite", // This is configured in the Http.config
|
||||
TargetFramework = runtimeFlavor == RuntimeFlavor.Clr ? "net461" : "netcoreapp2.0",
|
||||
ApplicationType = applicationType,
|
||||
|
|
@ -48,11 +48,11 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
|||
{
|
||||
var logger = loggerFactory.CreateLogger("HttpsHelloWorldTest");
|
||||
|
||||
var deploymentParameters = new DeploymentParameters(Helpers.GetTestSitesPath(), serverType, runtimeFlavor, architecture)
|
||||
var deploymentParameters = new DeploymentParameters(Helpers.GetOutOfProcessTestSitesPath(), serverType, runtimeFlavor, architecture)
|
||||
{
|
||||
ApplicationBaseUriHint = applicationBaseUrl,
|
||||
EnvironmentName = "HttpsHelloWorld", // Will pick the Start class named 'StartupHttpsHelloWorld',
|
||||
ServerConfigTemplateContent = (serverType == ServerType.IISExpress) ? File.ReadAllText("Https.config") : null,
|
||||
ServerConfigTemplateContent = (serverType == ServerType.IISExpress) ? File.ReadAllText("AppHostConfig/Https.config") : null,
|
||||
SiteName = "HttpsTestSite", // This is configured in the Https.config
|
||||
TargetFramework = runtimeFlavor == RuntimeFlavor.Clr ? "net461" : "netcoreapp2.0",
|
||||
ApplicationType = applicationType,
|
||||
|
|
@ -131,7 +131,7 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
|||
{
|
||||
var logger = loggerFactory.CreateLogger("HttpsHelloWorldTest");
|
||||
|
||||
var deploymentParameters = new DeploymentParameters(Helpers.GetTestSitesPath(), serverType, runtimeFlavor, architecture)
|
||||
var deploymentParameters = new DeploymentParameters(Helpers.GetOutOfProcessTestSitesPath(), serverType, runtimeFlavor, architecture)
|
||||
{
|
||||
ApplicationBaseUriHint = applicationBaseUrl,
|
||||
EnvironmentName = "HttpsHelloWorld", // Will pick the Start class named 'StartupHttpsHelloWorld',
|
||||
|
|
@ -50,11 +50,11 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
|||
? "win7-x64"
|
||||
: "win7-x86";
|
||||
|
||||
var deploymentParameters = new DeploymentParameters(Helpers.GetTestSitesPath(), serverType, runtimeFlavor, architecture)
|
||||
var deploymentParameters = new DeploymentParameters(Helpers.GetOutOfProcessTestSitesPath(), serverType, runtimeFlavor, architecture)
|
||||
{
|
||||
ApplicationBaseUriHint = $"http://localhost:{port}",
|
||||
EnvironmentName = "NtlmAuthentication", // Will pick the Start class named 'StartupNtlmAuthentication'
|
||||
ServerConfigTemplateContent = (serverType == ServerType.IISExpress) ? File.ReadAllText("NtlmAuthentation.config") : null,
|
||||
ServerConfigTemplateContent = (serverType == ServerType.IISExpress) ? File.ReadAllText("AppHostConfig/NtlmAuthentation.config") : null,
|
||||
SiteName = "NtlmAuthenticationTestSite", // This is configured in the NtlmAuthentication.config
|
||||
TargetFramework = runtimeFlavor == RuntimeFlavor.Clr ? "net461" : "netcoreapp2.0",
|
||||
ApplicationType = applicationType,
|
||||
|
|
@ -1,3 +1,5 @@
|
|||
using Xunit;
|
||||
// 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.
|
||||
|
||||
[assembly: CollectionBehavior(CollectionBehavior.CollectionPerAssembly)]
|
||||
// All functional tests in this project require a version of IIS express with an updated schema
|
||||
[assembly: Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests.IISExpressSupportsInProcessHosting]
|
||||
|
|
|
|||
|
|
@ -0,0 +1,117 @@
|
|||
// 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.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Server.IntegrationTesting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Logging.Testing;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
using Xunit.Sdk;
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
||||
{
|
||||
public class UpgradeFeatureDetectionTests : LoggedTest
|
||||
{
|
||||
public UpgradeFeatureDetectionTests(ITestOutputHelper output) : base(output)
|
||||
{
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public Task UpgradeFeatureDetectionEnabled_InProcess_IISExpress_CoreClr_x64_Portable()
|
||||
{
|
||||
return UpgradeFeatureDetectionDeployer(RuntimeFlavor.CoreClr,
|
||||
ApplicationType.Portable,
|
||||
"AppHostConfig/WebsocketsNotSupported.config",
|
||||
Helpers.GetInProcessTestSitesPath(),
|
||||
"Disabled");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public Task UpgradeFeatureDetectionDisabled_InProcess_IISExpress_CoreClr_x64_Portable()
|
||||
{
|
||||
return UpgradeFeatureDetectionDeployer(RuntimeFlavor.CoreClr,
|
||||
ApplicationType.Portable,
|
||||
"AppHostConfig/Http.config",
|
||||
Helpers.GetInProcessTestSitesPath(),
|
||||
"Enabled");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public Task UpgradeFeatureDetectionEnabled_OutOfProcess_IISExpress_CoreClr_x64_Portable()
|
||||
{
|
||||
return UpgradeFeatureDetectionDeployer(RuntimeFlavor.CoreClr,
|
||||
ApplicationType.Portable,
|
||||
"AppHostConfig/WebsocketsNotSupported.config",
|
||||
Helpers.GetOutOfProcessTestSitesPath(),
|
||||
"Disabled");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public Task UpgradeFeatureDetectionDisabled_OutOfProcess_IISExpress_CoreClr_x64_Portable()
|
||||
{
|
||||
return UpgradeFeatureDetectionDeployer(RuntimeFlavor.CoreClr,
|
||||
ApplicationType.Portable,
|
||||
"AppHostConfig/Http.config",
|
||||
Helpers.GetOutOfProcessTestSitesPath(),
|
||||
"Enabled");
|
||||
}
|
||||
|
||||
private async Task UpgradeFeatureDetectionDeployer(RuntimeFlavor runtimeFlavor,
|
||||
ApplicationType applicationType,
|
||||
string configPath,
|
||||
string sitePath,
|
||||
string expected)
|
||||
{
|
||||
var serverType = ServerType.IISExpress;
|
||||
var architecture = RuntimeArchitecture.x64;
|
||||
var testName = $"HelloWorld_{runtimeFlavor}";
|
||||
using (StartLog(out var loggerFactory, testName))
|
||||
{
|
||||
var logger = loggerFactory.CreateLogger("HelloWorldTest");
|
||||
|
||||
var deploymentParameters = new DeploymentParameters(Helpers.GetInProcessTestSitesPath(), serverType, runtimeFlavor, architecture)
|
||||
{
|
||||
EnvironmentName = "UpgradeFeatureDetection", // Will pick the Start class named 'StartupHelloWorld',
|
||||
ServerConfigTemplateContent = (serverType == ServerType.IISExpress) ? File.ReadAllText(configPath) : null,
|
||||
SiteName = "HttpTestSite", // This is configured in the Http.config
|
||||
TargetFramework = "netcoreapp2.0",
|
||||
ApplicationType = applicationType,
|
||||
Configuration =
|
||||
#if DEBUG
|
||||
"Debug"
|
||||
#else
|
||||
"Release"
|
||||
#endif
|
||||
};
|
||||
|
||||
using (var deployer = ApplicationDeployerFactory.Create(deploymentParameters, loggerFactory))
|
||||
{
|
||||
var deploymentResult = await deployer.DeployAsync();
|
||||
deploymentResult.HttpClient.Timeout = TimeSpan.FromSeconds(5);
|
||||
|
||||
// Request to base address and check if various parts of the body are rendered & measure the cold startup time.
|
||||
var response = await RetryHelper.RetryRequest(() =>
|
||||
{
|
||||
return deploymentResult.HttpClient.GetAsync("UpgradeFeatureDetection");
|
||||
}, logger, deploymentResult.HostShutdownToken, retryCount: 30);
|
||||
|
||||
var responseText = await response.Content.ReadAsStringAsync();
|
||||
try
|
||||
{
|
||||
Assert.Equal(expected, responseText);
|
||||
}
|
||||
catch (XunitException)
|
||||
{
|
||||
logger.LogWarning(response.ToString());
|
||||
logger.LogWarning(responseText);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -8,7 +8,18 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
|||
{
|
||||
public class Helpers
|
||||
{
|
||||
public static string GetTestSitesPath()
|
||||
public static string GetInProcessTestSitesPath()
|
||||
{
|
||||
return Path.GetFullPath(
|
||||
Path.Combine(AppDomain.CurrentDomain.BaseDirectory,
|
||||
"..", // tfm
|
||||
"..", // debug
|
||||
"..", // obj
|
||||
"..", // projectfolder
|
||||
"IISTestSite"));
|
||||
}
|
||||
|
||||
public static string GetOutOfProcessTestSitesPath()
|
||||
{
|
||||
return Path.GetFullPath(
|
||||
Path.Combine(AppDomain.CurrentDomain.BaseDirectory,
|
||||
|
|
@ -8,7 +8,7 @@ using System.Runtime.InteropServices;
|
|||
using System.Xml.Linq;
|
||||
using Microsoft.AspNetCore.Testing.xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests
|
||||
namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Assembly | AttributeTargets.Class)]
|
||||
public sealed class IISExpressSupportsInProcessHostingAttribute : Attribute, ITestCondition
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests
|
||||
namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
||||
{
|
||||
/// <summary>
|
||||
/// This type just maps collection names to available fixtures
|
||||
|
|
@ -8,7 +8,7 @@ using System.Threading;
|
|||
using Microsoft.AspNetCore.Server.IntegrationTesting;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests
|
||||
namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
||||
{
|
||||
public class IISTestSiteFixture : IDisposable
|
||||
{
|
||||
|
|
@ -16,12 +16,12 @@ namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests
|
|||
|
||||
public IISTestSiteFixture()
|
||||
{
|
||||
var deploymentParameters = new DeploymentParameters(Helpers.GetTestSitesPath(),
|
||||
var deploymentParameters = new DeploymentParameters(Helpers.GetInProcessTestSitesPath(),
|
||||
ServerType.IISExpress,
|
||||
RuntimeFlavor.CoreClr,
|
||||
RuntimeArchitecture.x64)
|
||||
{
|
||||
ServerConfigTemplateContent = File.ReadAllText("Http.config"),
|
||||
ServerConfigTemplateContent = File.ReadAllText("AppHostConfig/Http.config"),
|
||||
SiteName = "HttpTestSite",
|
||||
TargetFramework = "netcoreapp2.0",
|
||||
ApplicationType = ApplicationType.Portable,
|
||||
|
|
@ -1,26 +0,0 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>$(StandardTestTfms)</TargetFrameworks>
|
||||
<RootNamespace>Microsoft.AspNetCore.Server.IIS.FunctionalTests</RootNamespace>
|
||||
<AssemblyName>Microsoft.AspNetCore.Server.IIS.FunctionalTests</AssemblyName>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.Server.IISIntegration\Microsoft.AspNetCore.Server.IISIntegration.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Include="*.config" CopyToOutputDirectory="PreserveNewest" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Server.IntegrationTesting" Version="$(MicrosoftAspNetCoreServerIntegrationTestingPackageVersion)" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging" Version="$(MicrosoftExtensionsLoggingPackageVersion)" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="$(MicrosoftExtensionsLoggingConsolePackageVersion)" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="$(MicrosoftExtensionsLoggingDebugPackageVersion)" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Testing" Version="$(MicrosoftExtensionsLoggingTestingPackageVersion)" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="$(MicrosoftNETTestSdkPackageVersion)" />
|
||||
<PackageReference Include="xunit" Version="$(XunitPackageVersion)" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="$(XunitRunnerVisualStudioPackageVersion)" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
|
@ -1,5 +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.
|
||||
|
||||
// All functional tests in this project require a version of IIS express with an updated schema
|
||||
[assembly: Microsoft.AspNetCore.Server.IIS.FunctionalTests.IISExpressSupportsInProcessHosting]
|
||||
|
|
@ -1,22 +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;
|
||||
using System.IO;
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests
|
||||
{
|
||||
public class Helpers
|
||||
{
|
||||
public static string GetTestSitesPath()
|
||||
{
|
||||
return Path.GetFullPath(
|
||||
Path.Combine(AppDomain.CurrentDomain.BaseDirectory,
|
||||
"..", // tfm
|
||||
"..", // debug
|
||||
"..", // obj
|
||||
"..", // projectfolder
|
||||
"IISTestSite"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -43,6 +43,7 @@ namespace IISTestSite
|
|||
app.Map("/ReadAndWriteEchoTwice", ReadAndWriteEchoTwice);
|
||||
app.Map("/ReadAndWriteSlowConnection", ReadAndWriteSlowConnection);
|
||||
app.Map("/WebsocketRequest", WebsocketRequest);
|
||||
app.Map("/UpgradeFeatureDetection", UpgradeFeatureDetection);
|
||||
}
|
||||
|
||||
private void ServerVariable(IApplicationBuilder app)
|
||||
|
|
@ -425,5 +426,20 @@ namespace IISTestSite
|
|||
await context.Request.Body.CopyToAsync(context.Response.Body);
|
||||
});
|
||||
}
|
||||
|
||||
private void UpgradeFeatureDetection(IApplicationBuilder app)
|
||||
{
|
||||
app.Run(async ctx =>
|
||||
{
|
||||
if (ctx.Features.Get<IHttpUpgradeFeature>() != null)
|
||||
{
|
||||
await ctx.Response.WriteAsync("Enabled");
|
||||
}
|
||||
else
|
||||
{
|
||||
await ctx.Response.WriteAsync("Disabled");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,32 @@
|
|||
// 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.Linq;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Http.Features;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace TestSites
|
||||
{
|
||||
public class StartupUpgradeFeatureDetection
|
||||
{
|
||||
public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory)
|
||||
{
|
||||
app.Run(async ctx =>
|
||||
{
|
||||
if (ctx.Features.Get<IHttpUpgradeFeature>() != null)
|
||||
{
|
||||
await ctx.Response.WriteAsync("Enabled");
|
||||
}
|
||||
else
|
||||
{
|
||||
await ctx.Response.WriteAsync("Disabled");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue