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
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
# Visual Studio 15
|
# Visual Studio 15
|
||||||
VisualStudioVersion = 15.0.27130.2026
|
VisualStudioVersion = 15.0.27130.2036
|
||||||
MinimumVisualStudioVersion = 15.0.26730.03
|
MinimumVisualStudioVersion = 15.0.26730.03
|
||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{04B1EDB6-E967-4D25-89B9-E6F8304038CD}"
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{04B1EDB6-E967-4D25-89B9-E6F8304038CD}"
|
||||||
ProjectSection(SolutionItems) = preProject
|
ProjectSection(SolutionItems) = preProject
|
||||||
|
|
@ -44,8 +44,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NativeIISSample", "samples\
|
||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IISTestSite", "test\IISTestSite\IISTestSite.csproj", "{679FA2A2-898B-4320-884E-C2D294A97CE1}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IISTestSite", "test\IISTestSite\IISTestSite.csproj", "{679FA2A2-898B-4320-884E-C2D294A97CE1}"
|
||||||
EndProject
|
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}"
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AspNetCore", "src\AspNetCore\AspNetCore.vcxproj", "{439824F9-1455-4CC4-BD79-B44FA0A16552}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "IISLib", "src\IISLib\IISLib.vcxproj", "{4787A64F-9A3E-4867-A55A-70CB4B2B2FFE}"
|
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|x64.Build.0 = Release|Any CPU
|
||||||
{679FA2A2-898B-4320-884E-C2D294A97CE1}.Release|x86.ActiveCfg = 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
|
{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|Any CPU.ActiveCfg = Debug|Win32
|
||||||
{439824F9-1455-4CC4-BD79-B44FA0A16552}.Debug|x64.ActiveCfg = Debug|x64
|
{439824F9-1455-4CC4-BD79-B44FA0A16552}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
{439824F9-1455-4CC4-BD79-B44FA0A16552}.Debug|x64.Build.0 = 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}
|
{4E3E1F5C-CD52-4CC0-A35F-D1FA1685D2FA} = {EF30B533-D715-421A-92B7-92FEF460AC9C}
|
||||||
{9BC4AFCB-325D-4C81-8228-8CF301CE2F97} = {C74B8F36-FD2F-45C9-9B8A-00E7CF0126A9}
|
{9BC4AFCB-325D-4C81-8228-8CF301CE2F97} = {C74B8F36-FD2F-45C9-9B8A-00E7CF0126A9}
|
||||||
{679FA2A2-898B-4320-884E-C2D294A97CE1} = {EF30B533-D715-421A-92B7-92FEF460AC9C}
|
{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}
|
{439824F9-1455-4CC4-BD79-B44FA0A16552} = {04B1EDB6-E967-4D25-89B9-E6F8304038CD}
|
||||||
{4787A64F-9A3E-4867-A55A-70CB4B2B2FFE} = {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}
|
{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.Builder;
|
||||||
using Microsoft.AspNetCore.Hosting;
|
using Microsoft.AspNetCore.Hosting;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.AspNetCore.Http.Features;
|
||||||
using Microsoft.AspNetCore.Server.IISIntegration;
|
using Microsoft.AspNetCore.Server.IISIntegration;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
@ -71,7 +72,16 @@ namespace IISSample
|
||||||
var value = vars[key];
|
var value = vars[key];
|
||||||
await context.Response.WriteAsync(key + ": " + value + Environment.NewLine);
|
await context.Response.WriteAsync(key + ": " + value + Environment.NewLine);
|
||||||
}
|
}
|
||||||
|
|
||||||
await context.Response.WriteAsync(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"/>
|
<aspNetCore processPath="dotnet" arguments=".\IISSample.dll" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" forwardWindowsAuthToken="false"/>
|
||||||
-->
|
-->
|
||||||
</system.webServer>
|
</system.webServer>
|
||||||
</configuration>
|
</configuration>
|
||||||
|
|
|
||||||
|
|
@ -70,6 +70,16 @@ namespace NativeIISSample
|
||||||
{
|
{
|
||||||
await context.Response.WriteAsync(varName + ": " + context.GetIISServerVariable(varName) + Environment.NewLine);
|
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_PORT",
|
||||||
"REMOTE_USER",
|
"REMOTE_USER",
|
||||||
"REQUEST_METHOD",
|
"REQUEST_METHOD",
|
||||||
|
"WEBSOCKET_VERSION"
|
||||||
};
|
};
|
||||||
|
|
||||||
public static void Main(string[] args)
|
public static void Main(string[] args)
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@
|
||||||
#define HOSTING_STARTUP_ASSEMBLIES_NAME L"ASPNETCORE_HOSTINGSTARTUPASSEMBLIES="
|
#define HOSTING_STARTUP_ASSEMBLIES_NAME L"ASPNETCORE_HOSTINGSTARTUPASSEMBLIES="
|
||||||
#define HOSTING_STARTUP_ASSEMBLIES_VALUE L"Microsoft.AspNetCore.Server.IISIntegration"
|
#define HOSTING_STARTUP_ASSEMBLIES_VALUE L"Microsoft.AspNetCore.Server.IISIntegration"
|
||||||
#define ASPNETCORE_IIS_AUTH_ENV_STR L"ASPNETCORE_IIS_HTTPAUTH="
|
#define ASPNETCORE_IIS_AUTH_ENV_STR L"ASPNETCORE_IIS_HTTPAUTH="
|
||||||
|
#define ASPNETCORE_IIS_WEBSOCKETS_SUPPORTED_ENV_STR L"ASPNETCORE_IIS_WEBSOCKETS_SUPPORTED="
|
||||||
#define ASPNETCORE_IIS_AUTH_WINDOWS L"windows;"
|
#define ASPNETCORE_IIS_AUTH_WINDOWS L"windows;"
|
||||||
#define ASPNETCORE_IIS_AUTH_BASIC L"basic;"
|
#define ASPNETCORE_IIS_AUTH_BASIC L"basic;"
|
||||||
#define ASPNETCORE_IIS_AUTH_ANONYMOUS L"anonymous;"
|
#define ASPNETCORE_IIS_AUTH_ANONYMOUS L"anonymous;"
|
||||||
|
|
@ -123,349 +124,6 @@ public:
|
||||||
pEntry->Dereference();
|
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:
|
private:
|
||||||
ENVIRONMENT_VAR_HASH(const ENVIRONMENT_VAR_HASH &);
|
ENVIRONMENT_VAR_HASH(const ENVIRONMENT_VAR_HASH &);
|
||||||
|
|
|
||||||
|
|
@ -28,8 +28,26 @@ namespace Microsoft.AspNetCore.Server.IISIntegration
|
||||||
private readonly ILogger _logger;
|
private readonly ILogger _logger;
|
||||||
private readonly string _pairingToken;
|
private readonly string _pairingToken;
|
||||||
private readonly IApplicationLifetime _applicationLifetime;
|
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)
|
if (next == null)
|
||||||
{
|
{
|
||||||
|
|
@ -63,6 +81,7 @@ namespace Microsoft.AspNetCore.Server.IISIntegration
|
||||||
_pairingToken = pairingToken;
|
_pairingToken = pairingToken;
|
||||||
_applicationLifetime = applicationLifetime;
|
_applicationLifetime = applicationLifetime;
|
||||||
_logger = loggerFactory.CreateLogger<IISMiddleware>();
|
_logger = loggerFactory.CreateLogger<IISMiddleware>();
|
||||||
|
_isWebsocketsSupported = isWebsocketsSupported;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Invoke(HttpContext httpContext)
|
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);
|
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.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
|
@ -12,11 +12,13 @@ namespace Microsoft.AspNetCore.Server.IISIntegration
|
||||||
{
|
{
|
||||||
private readonly string _pairingToken;
|
private readonly string _pairingToken;
|
||||||
private readonly PathString _pathBase;
|
private readonly PathString _pathBase;
|
||||||
|
private readonly bool _isWebsocketsSupported;
|
||||||
|
|
||||||
internal IISSetupFilter(string pairingToken, PathString pathBase)
|
internal IISSetupFilter(string pairingToken, PathString pathBase, bool isWebsocketsSupported)
|
||||||
{
|
{
|
||||||
_pairingToken = pairingToken;
|
_pairingToken = pairingToken;
|
||||||
_pathBase = pathBase;
|
_pathBase = pathBase;
|
||||||
|
_isWebsocketsSupported = isWebsocketsSupported;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Action<IApplicationBuilder> Configure(Action<IApplicationBuilder> next)
|
public Action<IApplicationBuilder> Configure(Action<IApplicationBuilder> next)
|
||||||
|
|
@ -25,7 +27,7 @@ namespace Microsoft.AspNetCore.Server.IISIntegration
|
||||||
{
|
{
|
||||||
app.UsePathBase(_pathBase);
|
app.UsePathBase(_pathBase);
|
||||||
app.UseForwardedHeaders();
|
app.UseForwardedHeaders();
|
||||||
app.UseMiddleware<IISMiddleware>(_pairingToken);
|
app.UseMiddleware<IISMiddleware>(_pairingToken, _isWebsocketsSupported);
|
||||||
next(app);
|
next(app);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -183,7 +183,8 @@ namespace Microsoft.AspNetCore.Server.IISIntegration
|
||||||
|
|
||||||
bool IHttpResponseFeature.HasStarted => HasResponseStarted;
|
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;
|
bool IFeatureCollection.IsReadOnly => false;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,8 @@ namespace Microsoft.AspNetCore.Server.IISIntegration
|
||||||
private const int PauseWriterThreshold = 65536;
|
private const int PauseWriterThreshold = 65536;
|
||||||
private const int ResumeWriterTheshold = PauseWriterThreshold / 2;
|
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;
|
protected readonly IntPtr _pInProcessHandler;
|
||||||
|
|
||||||
|
|
@ -59,6 +60,7 @@ namespace Microsoft.AspNetCore.Server.IISIntegration
|
||||||
private const string NtlmString = "NTLM";
|
private const string NtlmString = "NTLM";
|
||||||
private const string NegotiateString = "Negotiate";
|
private const string NegotiateString = "Negotiate";
|
||||||
private const string BasicString = "Basic";
|
private const string BasicString = "Basic";
|
||||||
|
private const string WebSocketVersionString = "WEBSOCKET_VERSION";
|
||||||
|
|
||||||
internal unsafe IISHttpContext(MemoryPool<byte> memoryPool, IntPtr pInProcessHandler, IISOptions options, IISHttpServer server)
|
internal unsafe IISHttpContext(MemoryPool<byte> memoryPool, IntPtr pInProcessHandler, IISOptions options, IISHttpServer server)
|
||||||
: base((HttpApiTypes.HTTP_REQUEST*)NativeMethods.http_get_raw_request(pInProcessHandler))
|
: base((HttpApiTypes.HTTP_REQUEST*)NativeMethods.http_get_raw_request(pInProcessHandler))
|
||||||
|
|
@ -121,7 +123,7 @@ namespace Microsoft.AspNetCore.Server.IISIntegration
|
||||||
StatusCode = 200;
|
StatusCode = 200;
|
||||||
|
|
||||||
RequestHeaders = new RequestHeaders(this);
|
RequestHeaders = new RequestHeaders(this);
|
||||||
HttpResponseHeaders = new HeaderCollection(); // TODO Optimize for known headers
|
HttpResponseHeaders = new HeaderCollection();
|
||||||
ResponseHeaders = HttpResponseHeaders;
|
ResponseHeaders = HttpResponseHeaders;
|
||||||
|
|
||||||
if (options.ForwardWindowsAuthentication)
|
if (options.ForwardWindowsAuthentication)
|
||||||
|
|
@ -134,6 +136,26 @@ namespace Microsoft.AspNetCore.Server.IISIntegration
|
||||||
}
|
}
|
||||||
|
|
||||||
ResetFeatureCollection();
|
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);
|
RequestBody = new IISHttpRequestBody(this);
|
||||||
|
|
@ -534,5 +556,12 @@ namespace Microsoft.AspNetCore.Server.IISIntegration
|
||||||
}
|
}
|
||||||
return null;
|
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 ServerPath = "APPL_PATH";
|
||||||
private static readonly string PairingToken = "TOKEN";
|
private static readonly string PairingToken = "TOKEN";
|
||||||
private static readonly string IISAuth = "IIS_HTTPAUTH";
|
private static readonly string IISAuth = "IIS_HTTPAUTH";
|
||||||
|
private static readonly string IISWebSockets = "IIS_WEBSOCKETS_SUPPORTED";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Configures the port and base path the server should listen on when running behind AspNetCoreModule.
|
/// 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 path = hostBuilder.GetSetting(ServerPath) ?? Environment.GetEnvironmentVariable($"ASPNETCORE_{ServerPath}");
|
||||||
var pairingToken = hostBuilder.GetSetting(PairingToken) ?? Environment.GetEnvironmentVariable($"ASPNETCORE_{PairingToken}");
|
var pairingToken = hostBuilder.GetSetting(PairingToken) ?? Environment.GetEnvironmentVariable($"ASPNETCORE_{PairingToken}");
|
||||||
var iisAuth = hostBuilder.GetSetting(IISAuth) ?? Environment.GetEnvironmentVariable($"ASPNETCORE_{IISAuth}");
|
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))
|
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.
|
// Delay register the url so users don't accidently overwrite it.
|
||||||
hostBuilder.UseSetting(WebHostDefaults.ServerUrlsKey, address);
|
hostBuilder.UseSetting(WebHostDefaults.ServerUrlsKey, address);
|
||||||
hostBuilder.PreferHostingUrls(true);
|
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 =>
|
services.Configure<ForwardedHeadersOptions>(options =>
|
||||||
{
|
{
|
||||||
options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
|
options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
|
||||||
|
|
|
||||||
|
|
@ -208,6 +208,7 @@
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="aspnetcore_event.h" />
|
<ClInclude Include="aspnetcore_event.h" />
|
||||||
<ClInclude Include="disconnectcontext.h" />
|
<ClInclude Include="disconnectcontext.h" />
|
||||||
|
<ClInclude Include="environmentvariablehelpers.h" />
|
||||||
<ClInclude Include="sttimer.h" />
|
<ClInclude Include="sttimer.h" />
|
||||||
<ClInclude Include="outofprocess\forwarderconnection.h" />
|
<ClInclude Include="outofprocess\forwarderconnection.h" />
|
||||||
<ClInclude Include="outofprocess\processmanager.h" />
|
<ClInclude Include="outofprocess\processmanager.h" />
|
||||||
|
|
|
||||||
|
|
@ -80,6 +80,7 @@
|
||||||
<ClInclude Include="aspnetcore_event.h" />
|
<ClInclude Include="aspnetcore_event.h" />
|
||||||
<ClInclude Include="sttimer.h" />
|
<ClInclude Include="sttimer.h" />
|
||||||
<ClInclude Include="disconnectcontext.h" />
|
<ClInclude Include="disconnectcontext.h" />
|
||||||
|
<ClInclude Include="environmentvariablehelpers.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="Source.def" />
|
<None Include="Source.def" />
|
||||||
|
|
|
||||||
|
|
@ -112,8 +112,6 @@ InitializeGlobalConfiguration(
|
||||||
g_fNsiApiNotSupported = TRUE;
|
g_fNsiApiNotSupported = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// WebSocket is supported on Win8 and above only
|
|
||||||
// todo: test on win7
|
|
||||||
g_fWebSocketSupported = IsWindows8OrGreater();
|
g_fWebSocketSupported = IsWindows8OrGreater();
|
||||||
|
|
||||||
g_fGlobalInitialize = TRUE;
|
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;
|
HRESULT hr = S_OK;
|
||||||
ENVIRONMENT_VAR_HASH* pHashTable = NULL;
|
ENVIRONMENT_VAR_HASH* pHashTable = NULL;
|
||||||
if (FAILED(hr = ENVIRONMENT_VAR_HASH::InitEnvironmentVariablesTable(
|
if (FAILED(hr = ENVIRONMENT_VAR_HELPERS::InitEnvironmentVariablesTable(
|
||||||
m_pConfig->QueryEnvironmentVariables(),
|
m_pConfig->QueryEnvironmentVariables(),
|
||||||
m_pConfig->QueryWindowsAuthEnabled(),
|
m_pConfig->QueryWindowsAuthEnabled(),
|
||||||
m_pConfig->QueryBasicAuthEnabled(),
|
m_pConfig->QueryBasicAuthEnabled(),
|
||||||
|
|
@ -736,8 +736,16 @@ IN_PROCESS_APPLICATION::SetEnvironementVariablesOnWorkerProcess(
|
||||||
goto Finished;
|
goto Finished;
|
||||||
}
|
}
|
||||||
|
|
||||||
pHashTable->Apply(ENVIRONMENT_VAR_HASH::AppendEnvironmentVariables, NULL);
|
pHashTable->Apply(ENVIRONMENT_VAR_HELPERS::AppendEnvironmentVariables, &hr);
|
||||||
pHashTable->Apply(ENVIRONMENT_VAR_HASH::SetEnvironmentVariables, NULL);
|
if (FAILED(hr))
|
||||||
|
{
|
||||||
|
goto Finished;
|
||||||
|
}
|
||||||
|
pHashTable->Apply(ENVIRONMENT_VAR_HELPERS::SetEnvironmentVariables, &hr);
|
||||||
|
if (FAILED(hr))
|
||||||
|
{
|
||||||
|
goto Finished;
|
||||||
|
}
|
||||||
Finished:
|
Finished:
|
||||||
return hr;
|
return hr;
|
||||||
}
|
}
|
||||||
|
|
@ -770,15 +778,15 @@ IN_PROCESS_APPLICATION::ExecuteApplication(
|
||||||
goto Finished;
|
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()))
|
if (FAILED(hr = SetEnvironementVariablesOnWorkerProcess()))
|
||||||
{
|
{
|
||||||
goto Finished;
|
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
|
// We set a static so that managed code can call back into this instance and
|
||||||
// set the callbacks
|
// set the callbacks
|
||||||
s_Application = this;
|
s_Application = this;
|
||||||
|
|
|
||||||
|
|
@ -225,6 +225,7 @@ PROCESS_MANAGER::GetProcess(
|
||||||
pConfig->QueryAnonymousAuthEnabled(),
|
pConfig->QueryAnonymousAuthEnabled(),
|
||||||
pConfig->QueryEnvironmentVariables(),
|
pConfig->QueryEnvironmentVariables(),
|
||||||
pConfig->QueryStdoutLogEnabled(),
|
pConfig->QueryStdoutLogEnabled(),
|
||||||
|
pConfig->QueryWebSocketEnabled(),
|
||||||
pConfig->QueryStdoutLogFile(),
|
pConfig->QueryStdoutLogFile(),
|
||||||
pConfig->QueryApplicationPhysicalPath(), // physical path
|
pConfig->QueryApplicationPhysicalPath(), // physical path
|
||||||
pConfig->QueryApplicationPath(), // app path
|
pConfig->QueryApplicationPath(), // app path
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ SERVER_PROCESS::Initialize(
|
||||||
BOOL fAnonymousAuthEnabled,
|
BOOL fAnonymousAuthEnabled,
|
||||||
ENVIRONMENT_VAR_HASH *pEnvironmentVariables,
|
ENVIRONMENT_VAR_HASH *pEnvironmentVariables,
|
||||||
BOOL fStdoutLogEnabled,
|
BOOL fStdoutLogEnabled,
|
||||||
|
BOOL fWebsocketsEnabled,
|
||||||
STRU *pstruStdoutLogFile,
|
STRU *pstruStdoutLogFile,
|
||||||
STRU *pszAppPhysicalPath,
|
STRU *pszAppPhysicalPath,
|
||||||
STRU *pszAppPath,
|
STRU *pszAppPath,
|
||||||
|
|
@ -38,6 +39,7 @@ SERVER_PROCESS::Initialize(
|
||||||
m_fWindowsAuthEnabled = fWindowsAuthEnabled;
|
m_fWindowsAuthEnabled = fWindowsAuthEnabled;
|
||||||
m_fBasicAuthEnabled = fBasicAuthEnabled;
|
m_fBasicAuthEnabled = fBasicAuthEnabled;
|
||||||
m_fAnonymousAuthEnabled = fAnonymousAuthEnabled;
|
m_fAnonymousAuthEnabled = fAnonymousAuthEnabled;
|
||||||
|
m_fWebsocketsEnabled = fWebsocketsEnabled;
|
||||||
m_pProcessManager->ReferenceProcessManager();
|
m_pProcessManager->ReferenceProcessManager();
|
||||||
|
|
||||||
if (FAILED(hr = m_ProcessPath.Copy(*pszProcessExePath)) ||
|
if (FAILED(hr = m_ProcessPath.Copy(*pszProcessExePath)) ||
|
||||||
|
|
@ -402,7 +404,7 @@ SERVER_PROCESS::OutputEnvironmentVariables
|
||||||
pszCurrentVariable = pszNextVariable;
|
pszCurrentVariable = pszNextVariable;
|
||||||
}
|
}
|
||||||
// append the remaining env variable in hash table
|
// append the remaining env variable in hash table
|
||||||
pEnvironmentVarTable->Apply(ENVIRONMENT_VAR_HASH::CopyToMultiSz, pmszOutput);
|
pEnvironmentVarTable->Apply(ENVIRONMENT_VAR_HELPERS::CopyToMultiSz, pmszOutput);
|
||||||
|
|
||||||
Finished:
|
Finished:
|
||||||
if (pszEnvironmentVariables != NULL)
|
if (pszEnvironmentVariables != NULL)
|
||||||
|
|
@ -755,7 +757,7 @@ SERVER_PROCESS::StartProcess(
|
||||||
goto Failure;
|
goto Failure;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (FAILED(hr = ENVIRONMENT_VAR_HASH::InitEnvironmentVariablesTable(
|
if (FAILED(hr = ENVIRONMENT_VAR_HELPERS::InitEnvironmentVariablesTable(
|
||||||
m_pEnvironmentVarTable,
|
m_pEnvironmentVarTable,
|
||||||
m_fWindowsAuthEnabled,
|
m_fWindowsAuthEnabled,
|
||||||
m_fBasicAuthEnabled,
|
m_fBasicAuthEnabled,
|
||||||
|
|
@ -766,6 +768,16 @@ SERVER_PROCESS::StartProcess(
|
||||||
goto Failure;
|
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
|
// setup the the port that the backend process will listen on
|
||||||
//
|
//
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@ public:
|
||||||
_In_ BOOL fAnonymousAuthEnabled,
|
_In_ BOOL fAnonymousAuthEnabled,
|
||||||
_In_ ENVIRONMENT_VAR_HASH* pEnvironmentVariables,
|
_In_ ENVIRONMENT_VAR_HASH* pEnvironmentVariables,
|
||||||
_In_ BOOL fStdoutLogEnabled,
|
_In_ BOOL fStdoutLogEnabled,
|
||||||
|
_In_ BOOL fWebsocketsEnabled,
|
||||||
_In_ STRU *pstruStdoutLogFile,
|
_In_ STRU *pstruStdoutLogFile,
|
||||||
_In_ STRU *pszAppPhysicalPath,
|
_In_ STRU *pszAppPhysicalPath,
|
||||||
_In_ STRU *pszAppPath,
|
_In_ STRU *pszAppPath,
|
||||||
|
|
@ -222,6 +223,7 @@ private:
|
||||||
BOOL m_fWindowsAuthEnabled;
|
BOOL m_fWindowsAuthEnabled;
|
||||||
BOOL m_fBasicAuthEnabled;
|
BOOL m_fBasicAuthEnabled;
|
||||||
BOOL m_fAnonymousAuthEnabled;
|
BOOL m_fAnonymousAuthEnabled;
|
||||||
|
BOOL m_fWebsocketsEnabled;
|
||||||
|
|
||||||
STTIMER m_Timer;
|
STTIMER m_Timer;
|
||||||
SOCKET m_socket;
|
SOCKET m_socket;
|
||||||
|
|
|
||||||
|
|
@ -59,6 +59,7 @@
|
||||||
#include "aspnetcore_event.h"
|
#include "aspnetcore_event.h"
|
||||||
#include "aspnetcore_msg.h"
|
#include "aspnetcore_msg.h"
|
||||||
#include "disconnectcontext.h"
|
#include "disconnectcontext.h"
|
||||||
|
#include "environmentvariablehelpers.h"
|
||||||
#include "sttimer.h"
|
#include "sttimer.h"
|
||||||
#include ".\inprocess\InProcessHandler.h"
|
#include ".\inprocess\InProcessHandler.h"
|
||||||
#include ".\inprocess\inprocessapplication.h"
|
#include ".\inprocess\inprocessapplication.h"
|
||||||
|
|
|
||||||
|
|
@ -212,9 +212,9 @@
|
||||||
-->
|
-->
|
||||||
<globalModules>
|
<globalModules>
|
||||||
<add name="UriCacheModule" image="%IIS_BIN%\cachuri.dll" />
|
<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="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="DynamicCompressionModule" image="%IIS_BIN%\compdyn.dll" />
|
||||||
<add name="StaticCompressionModule" image="%IIS_BIN%\compstat.dll" />
|
<add name="StaticCompressionModule" image="%IIS_BIN%\compstat.dll" />
|
||||||
<add name="DefaultDocumentModule" image="%IIS_BIN%\defdoc.dll" />
|
<add name="DefaultDocumentModule" image="%IIS_BIN%\defdoc.dll" />
|
||||||
|
|
@ -228,7 +228,7 @@
|
||||||
<add name="UrlAuthorizationModule" image="%IIS_BIN%\urlauthz.dll" />
|
<add name="UrlAuthorizationModule" image="%IIS_BIN%\urlauthz.dll" />
|
||||||
<add name="BasicAuthenticationModule" image="%IIS_BIN%\authbas.dll" />
|
<add name="BasicAuthenticationModule" image="%IIS_BIN%\authbas.dll" />
|
||||||
<add name="WindowsAuthenticationModule" image="%IIS_BIN%\authsspi.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="IISCertificateMappingAuthenticationModule" image="%IIS_BIN%\authmap.dll" />
|
||||||
<add name="IpRestrictionModule" image="%IIS_BIN%\iprestr.dll" />
|
<add name="IpRestrictionModule" image="%IIS_BIN%\iprestr.dll" />
|
||||||
<add name="DynamicIpRestrictionModule" image="%IIS_BIN%\diprestr.dll" />
|
<add name="DynamicIpRestrictionModule" image="%IIS_BIN%\diprestr.dll" />
|
||||||
|
|
@ -236,14 +236,14 @@
|
||||||
<add name="CustomLoggingModule" image="%IIS_BIN%\logcust.dll" />
|
<add name="CustomLoggingModule" image="%IIS_BIN%\logcust.dll" />
|
||||||
<add name="CustomErrorModule" image="%IIS_BIN%\custerr.dll" />
|
<add name="CustomErrorModule" image="%IIS_BIN%\custerr.dll" />
|
||||||
<add name="HttpLoggingModule" image="%IIS_BIN%\loghttp.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="FailedRequestsTracingModule" image="%IIS_BIN%\iisfreb.dll" />
|
||||||
<add name="RequestMonitorModule" image="%IIS_BIN%\iisreqs.dll" />
|
<add name="RequestMonitorModule" image="%IIS_BIN%\iisreqs.dll" />
|
||||||
<add name="IsapiModule" image="%IIS_BIN%\isapi.dll" />
|
<add name="IsapiModule" image="%IIS_BIN%\isapi.dll" />
|
||||||
<add name="IsapiFilterModule" image="%IIS_BIN%\filter.dll" />
|
<add name="IsapiFilterModule" image="%IIS_BIN%\filter.dll" />
|
||||||
<add name="CgiModule" image="%IIS_BIN%\cgi.dll" />
|
<add name="CgiModule" image="%IIS_BIN%\cgi.dll" />
|
||||||
<add name="FastCgiModule" image="%IIS_BIN%\iisfcgi.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="RewriteModule" image="%IIS_BIN%\rewrite.dll" />
|
||||||
<add name="ConfigurationValidationModule" image="%IIS_BIN%\validcfg.dll" />
|
<add name="ConfigurationValidationModule" image="%IIS_BIN%\validcfg.dll" />
|
||||||
<add name="ApplicationInitializationModule" image="%IIS_BIN%\warmup.dll" />
|
<add name="ApplicationInitializationModule" image="%IIS_BIN%\warmup.dll" />
|
||||||
|
|
@ -799,7 +799,7 @@
|
||||||
|
|
||||||
<tracing>
|
<tracing>
|
||||||
|
|
||||||
<traceProviderDefinitions>
|
<traceProviderDefinitions>
|
||||||
<add name="WWW Server" guid="{3a2a4e84-4c21-4981-ae10-3fda0d9b0f83}">
|
<add name="WWW Server" guid="{3a2a4e84-4c21-4981-ae10-3fda0d9b0f83}">
|
||||||
<areas>
|
<areas>
|
||||||
<clear />
|
<clear />
|
||||||
|
|
@ -870,7 +870,7 @@
|
||||||
<authoringRules />
|
<authoringRules />
|
||||||
</webdav>
|
</webdav>
|
||||||
<applicationInitialization />
|
<applicationInitialization />
|
||||||
<webSocket />
|
<webSocket enabled="false" />
|
||||||
|
|
||||||
</system.webServer>
|
</system.webServer>
|
||||||
<location path="" overrideMode="Allow">
|
<location path="" overrideMode="Allow">
|
||||||
|
|
@ -5,15 +5,19 @@
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<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>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Server.IntegrationTesting" Version="$(MicrosoftAspNetCoreServerIntegrationTestingPackageVersion)" />
|
<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.Console" Version="$(MicrosoftExtensionsLoggingConsolePackageVersion)" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="$(MicrosoftExtensionsLoggingDebugPackageVersion)" />
|
<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="Microsoft.NET.Test.Sdk" Version="$(MicrosoftNETTestSdkPackageVersion)" />
|
||||||
<PackageReference Include="xunit" Version="$(XunitPackageVersion)" />
|
<PackageReference Include="xunit" Version="$(XunitPackageVersion)" />
|
||||||
<PackageReference Include="xunit.runner.visualstudio" Version="$(XunitRunnerVisualStudioPackageVersion)" />
|
<PackageReference Include="xunit.runner.visualstudio" Version="$(XunitRunnerVisualStudioPackageVersion)" />
|
||||||
|
|
|
||||||
|
|
@ -6,11 +6,10 @@
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Server.IIS.FunctionalTests;
|
|
||||||
using Microsoft.AspNetCore.Testing.xunit;
|
using Microsoft.AspNetCore.Testing.xunit;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace IISIntegration.IISServerFunctionalTests
|
namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
||||||
{
|
{
|
||||||
[Collection(IISTestSiteCollection.Name)]
|
[Collection(IISTestSiteCollection.Name)]
|
||||||
public class AuthenticationTests
|
public class AuthenticationTests
|
||||||
|
|
@ -5,7 +5,7 @@ using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Testing.xunit;
|
using Microsoft.AspNetCore.Testing.xunit;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests
|
namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
||||||
{
|
{
|
||||||
[Collection(IISTestSiteCollection.Name)]
|
[Collection(IISTestSiteCollection.Name)]
|
||||||
public class EnvironmentVariableTests
|
public class EnvironmentVariableTests
|
||||||
|
|
@ -6,7 +6,7 @@ using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Testing.xunit;
|
using Microsoft.AspNetCore.Testing.xunit;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests
|
namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
||||||
{
|
{
|
||||||
[Collection(IISTestSiteCollection.Name)]
|
[Collection(IISTestSiteCollection.Name)]
|
||||||
public class FeatureCollectionTest
|
public class FeatureCollectionTest
|
||||||
|
|
@ -6,14 +6,14 @@ using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Testing.xunit;
|
using Microsoft.AspNetCore.Testing.xunit;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests
|
namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
||||||
{
|
{
|
||||||
[Collection(IISTestSiteCollection.Name)]
|
[Collection(IISTestSiteCollection.Name)]
|
||||||
public class HelloWorldTests
|
public class HelloWorldInProcessTests
|
||||||
{
|
{
|
||||||
private readonly IISTestSiteFixture _fixture;
|
private readonly IISTestSiteFixture _fixture;
|
||||||
|
|
||||||
public HelloWorldTests(IISTestSiteFixture fixture)
|
public HelloWorldInProcessTests(IISTestSiteFixture fixture)
|
||||||
{
|
{
|
||||||
_fixture = fixture;
|
_fixture = fixture;
|
||||||
}
|
}
|
||||||
|
|
@ -5,7 +5,7 @@ using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Testing.xunit;
|
using Microsoft.AspNetCore.Testing.xunit;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests
|
namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
||||||
{
|
{
|
||||||
[Collection(IISTestSiteCollection.Name)]
|
[Collection(IISTestSiteCollection.Name)]
|
||||||
public class LargeResponseBodyTests
|
public class LargeResponseBodyTests
|
||||||
|
|
@ -8,7 +8,7 @@ using Microsoft.AspNetCore.Testing.xunit;
|
||||||
using Microsoft.Net.Http.Headers;
|
using Microsoft.Net.Http.Headers;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests
|
namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
||||||
{
|
{
|
||||||
[Collection(IISTestSiteCollection.Name)]
|
[Collection(IISTestSiteCollection.Name)]
|
||||||
|
|
||||||
|
|
@ -5,7 +5,7 @@ using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Testing.xunit;
|
using Microsoft.AspNetCore.Testing.xunit;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests
|
namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
||||||
{
|
{
|
||||||
[Collection(IISTestSiteCollection.Name)]
|
[Collection(IISTestSiteCollection.Name)]
|
||||||
public class ResponseInvalidOrderingTest
|
public class ResponseInvalidOrderingTest
|
||||||
|
|
@ -5,7 +5,7 @@ using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Testing.xunit;
|
using Microsoft.AspNetCore.Testing.xunit;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests
|
namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
||||||
{
|
{
|
||||||
[Collection(IISTestSiteCollection.Name)]
|
[Collection(IISTestSiteCollection.Name)]
|
||||||
public class ServerVariablesTest
|
public class ServerVariablesTest
|
||||||
|
|
@ -41,10 +41,10 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
||||||
{
|
{
|
||||||
var logger = loggerFactory.CreateLogger("HelloWorldTest");
|
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',
|
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
|
SiteName = "HttpTestSite", // This is configured in the Http.config
|
||||||
TargetFramework = runtimeFlavor == RuntimeFlavor.Clr ? "net461" : "netcoreapp2.0",
|
TargetFramework = runtimeFlavor == RuntimeFlavor.Clr ? "net461" : "netcoreapp2.0",
|
||||||
ApplicationType = applicationType,
|
ApplicationType = applicationType,
|
||||||
|
|
@ -48,11 +48,11 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
||||||
{
|
{
|
||||||
var logger = loggerFactory.CreateLogger("HttpsHelloWorldTest");
|
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,
|
ApplicationBaseUriHint = applicationBaseUrl,
|
||||||
EnvironmentName = "HttpsHelloWorld", // Will pick the Start class named 'StartupHttpsHelloWorld',
|
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
|
SiteName = "HttpsTestSite", // This is configured in the Https.config
|
||||||
TargetFramework = runtimeFlavor == RuntimeFlavor.Clr ? "net461" : "netcoreapp2.0",
|
TargetFramework = runtimeFlavor == RuntimeFlavor.Clr ? "net461" : "netcoreapp2.0",
|
||||||
ApplicationType = applicationType,
|
ApplicationType = applicationType,
|
||||||
|
|
@ -131,7 +131,7 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
||||||
{
|
{
|
||||||
var logger = loggerFactory.CreateLogger("HttpsHelloWorldTest");
|
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,
|
ApplicationBaseUriHint = applicationBaseUrl,
|
||||||
EnvironmentName = "HttpsHelloWorld", // Will pick the Start class named 'StartupHttpsHelloWorld',
|
EnvironmentName = "HttpsHelloWorld", // Will pick the Start class named 'StartupHttpsHelloWorld',
|
||||||
|
|
@ -50,11 +50,11 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
||||||
? "win7-x64"
|
? "win7-x64"
|
||||||
: "win7-x86";
|
: "win7-x86";
|
||||||
|
|
||||||
var deploymentParameters = new DeploymentParameters(Helpers.GetTestSitesPath(), serverType, runtimeFlavor, architecture)
|
var deploymentParameters = new DeploymentParameters(Helpers.GetOutOfProcessTestSitesPath(), serverType, runtimeFlavor, architecture)
|
||||||
{
|
{
|
||||||
ApplicationBaseUriHint = $"http://localhost:{port}",
|
ApplicationBaseUriHint = $"http://localhost:{port}",
|
||||||
EnvironmentName = "NtlmAuthentication", // Will pick the Start class named 'StartupNtlmAuthentication'
|
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
|
SiteName = "NtlmAuthenticationTestSite", // This is configured in the NtlmAuthentication.config
|
||||||
TargetFramework = runtimeFlavor == RuntimeFlavor.Clr ? "net461" : "netcoreapp2.0",
|
TargetFramework = runtimeFlavor == RuntimeFlavor.Clr ? "net461" : "netcoreapp2.0",
|
||||||
ApplicationType = applicationType,
|
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 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(
|
return Path.GetFullPath(
|
||||||
Path.Combine(AppDomain.CurrentDomain.BaseDirectory,
|
Path.Combine(AppDomain.CurrentDomain.BaseDirectory,
|
||||||
|
|
@ -8,7 +8,7 @@ using System.Runtime.InteropServices;
|
||||||
using System.Xml.Linq;
|
using System.Xml.Linq;
|
||||||
using Microsoft.AspNetCore.Testing.xunit;
|
using Microsoft.AspNetCore.Testing.xunit;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests
|
namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
||||||
{
|
{
|
||||||
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Assembly | AttributeTargets.Class)]
|
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Assembly | AttributeTargets.Class)]
|
||||||
public sealed class IISExpressSupportsInProcessHostingAttribute : Attribute, ITestCondition
|
public sealed class IISExpressSupportsInProcessHostingAttribute : Attribute, ITestCondition
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests
|
namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// This type just maps collection names to available fixtures
|
/// This type just maps collection names to available fixtures
|
||||||
|
|
@ -8,7 +8,7 @@ using System.Threading;
|
||||||
using Microsoft.AspNetCore.Server.IntegrationTesting;
|
using Microsoft.AspNetCore.Server.IntegrationTesting;
|
||||||
using Microsoft.Extensions.Logging.Abstractions;
|
using Microsoft.Extensions.Logging.Abstractions;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests
|
namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
||||||
{
|
{
|
||||||
public class IISTestSiteFixture : IDisposable
|
public class IISTestSiteFixture : IDisposable
|
||||||
{
|
{
|
||||||
|
|
@ -16,12 +16,12 @@ namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests
|
||||||
|
|
||||||
public IISTestSiteFixture()
|
public IISTestSiteFixture()
|
||||||
{
|
{
|
||||||
var deploymentParameters = new DeploymentParameters(Helpers.GetTestSitesPath(),
|
var deploymentParameters = new DeploymentParameters(Helpers.GetInProcessTestSitesPath(),
|
||||||
ServerType.IISExpress,
|
ServerType.IISExpress,
|
||||||
RuntimeFlavor.CoreClr,
|
RuntimeFlavor.CoreClr,
|
||||||
RuntimeArchitecture.x64)
|
RuntimeArchitecture.x64)
|
||||||
{
|
{
|
||||||
ServerConfigTemplateContent = File.ReadAllText("Http.config"),
|
ServerConfigTemplateContent = File.ReadAllText("AppHostConfig/Http.config"),
|
||||||
SiteName = "HttpTestSite",
|
SiteName = "HttpTestSite",
|
||||||
TargetFramework = "netcoreapp2.0",
|
TargetFramework = "netcoreapp2.0",
|
||||||
ApplicationType = ApplicationType.Portable,
|
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("/ReadAndWriteEchoTwice", ReadAndWriteEchoTwice);
|
||||||
app.Map("/ReadAndWriteSlowConnection", ReadAndWriteSlowConnection);
|
app.Map("/ReadAndWriteSlowConnection", ReadAndWriteSlowConnection);
|
||||||
app.Map("/WebsocketRequest", WebsocketRequest);
|
app.Map("/WebsocketRequest", WebsocketRequest);
|
||||||
|
app.Map("/UpgradeFeatureDetection", UpgradeFeatureDetection);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ServerVariable(IApplicationBuilder app)
|
private void ServerVariable(IApplicationBuilder app)
|
||||||
|
|
@ -425,5 +426,20 @@ namespace IISTestSite
|
||||||
await context.Request.Body.CopyToAsync(context.Response.Body);
|
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