diff --git a/src/IISIntegration/.gitignore b/src/IISIntegration/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..f86f68b74880dc2c873aeb1843a06ffe60ba882a
--- /dev/null
+++ b/src/IISIntegration/.gitignore
@@ -0,0 +1,67 @@
+[Oo]bj/
+[Bb]in/
+TestResults/
+.nuget/
+*.sln.ide/
+_ReSharper.*/
+packages/
+artifacts/
+PublishProfiles/
+*.user
+*.suo
+*.cache
+*.docstates
+_ReSharper.*
+nuget.exe
+project.lock.json
+*net45.csproj
+*net451.csproj
+*k10.csproj
+*.psess
+*.vsp
+*.pidb
+*.userprefs
+*DS_Store
+*.ncrunchsolution
+*.*sdf
+*.ipch
+.vscode/
+*.nuget.props
+*.nuget.targets
+*.bin
+*.vs/
+.testPublish/
+
+*.obj
+*.tlog
+*.CppClean.log
+*msbuild.log
+
+src/*/*/Debug/
+src/*/*/x64/Debug/
+src/*/*/Release/
+src/*/*/x64/Release/
+x64/
+
+*vcxproj.filters
+*.aps
+*.pdb
+*.lib
+*.idb
+
+src/*/AspNetCore/aspnetcoremodule.h
+src/*/AspNetCore/aspnetcore_msg.h
+src/*/AspNetCore/aspnetcore_msg.rc
+src/*/*/version.h
+src/*/RequestHandler/version.h
+src/*/CommonLib/aspnetcore_msg.h
+src/*/CommonLib/aspnetcore_msg.rc
+test/*/Debug
+test/*/Release
+test/gtest-1.8.0/msvc/Debug
+test/gtest-1.8.0/msvc/Release
+.build
+
+*.VC.*db
+global.json
+msbuild.binlog
diff --git a/src/IISIntegration/Directory.Build.props b/src/IISIntegration/Directory.Build.props
new file mode 100644
index 0000000000000000000000000000000000000000..3bb2bcbca807fa9acd9fec8f0f6771b21667c611
--- /dev/null
+++ b/src/IISIntegration/Directory.Build.props
@@ -0,0 +1,23 @@
+<Project>
+  <Import
+    Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), AspNetCoreSettings.props))\AspNetCoreSettings.props"
+    Condition=" '$(CI)' != 'true' AND '$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), AspNetCoreSettings.props))' != '' " />
+
+  <Import Project="version.props" />
+  <Import Project="build\dependencies.props" />
+  <Import Project="build\sources.props" />
+
+  <PropertyGroup>
+    <Product>Microsoft ASP.NET Core</Product>
+    <RepositoryUrl>https://github.com/aspnet/IISIntegration</RepositoryUrl>
+    <RepositoryType>git</RepositoryType>
+    <RepositoryRoot>$(MSBuildThisFileDirectory)</RepositoryRoot>
+    <AssemblyOriginatorKeyFile>$(MSBuildThisFileDirectory)build\Key.snk</AssemblyOriginatorKeyFile>
+    <SignAssembly>true</SignAssembly>
+    <PublicSign Condition="'$(OS)' != 'Windows_NT'">true</PublicSign>
+    <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
+    <!-- https://github.com/aspnet/IISIntegration/issues/617 -->
+    <EnableApiCheck>false</EnableApiCheck>
+  </PropertyGroup>
+
+</Project>
diff --git a/src/IISIntegration/Directory.Build.targets b/src/IISIntegration/Directory.Build.targets
new file mode 100644
index 0000000000000000000000000000000000000000..53b3f6e1dabae0bb4e5f8a2cdf3ce1cea06375c1
--- /dev/null
+++ b/src/IISIntegration/Directory.Build.targets
@@ -0,0 +1,7 @@
+<Project>
+  <PropertyGroup>
+    <RuntimeFrameworkVersion Condition=" '$(TargetFramework)' == 'netcoreapp2.0' ">$(MicrosoftNETCoreApp20PackageVersion)</RuntimeFrameworkVersion>
+    <RuntimeFrameworkVersion Condition=" '$(TargetFramework)' == 'netcoreapp2.1' ">$(MicrosoftNETCoreApp21PackageVersion)</RuntimeFrameworkVersion>
+    <NETStandardImplicitPackageVersion Condition=" '$(TargetFramework)' == 'netstandard2.0' ">$(NETStandardLibrary20PackageVersion)</NETStandardImplicitPackageVersion>
+  </PropertyGroup>
+</Project>
diff --git a/src/IISIntegration/IISIntegration.sln b/src/IISIntegration/IISIntegration.sln
new file mode 100644
index 0000000000000000000000000000000000000000..50d11124bcad10224fb58e7469e0090baf253349
--- /dev/null
+++ b/src/IISIntegration/IISIntegration.sln
@@ -0,0 +1,316 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 15
+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
+		src\Directory.Build.props = src\Directory.Build.props
+	EndProjectSection
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{0EF45656-B25D-40D8-959C-726EAF185E60}"
+	ProjectSection(SolutionItems) = preProject
+		.editorconfig = .editorconfig
+		Directory.Build.props = Directory.Build.props
+		Directory.Build.targets = Directory.Build.targets
+		NuGet.Config = NuGet.Config
+	EndProjectSection
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{EF30B533-D715-421A-92B7-92FEF460AC9C}"
+	ProjectSection(SolutionItems) = preProject
+		test\Directory.Build.props = test\Directory.Build.props
+	EndProjectSection
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{C74B8F36-FD2F-45C9-9B8A-00E7CF0126A9}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IISSample", "samples\IISSample\IISSample.csproj", "{E4E2BDC4-A9C6-4AE9-B429-032EC83EDE64}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Server.IISIntegration", "src\Microsoft.AspNetCore.Server.IISIntegration\Microsoft.AspNetCore.Server.IISIntegration.csproj", "{8B3446E8-E6A8-4591-AA63-A95837C6E97C}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Server.IISIntegration.Tests", "test\Microsoft.AspNetCore.Server.IISIntegration.Tests\Microsoft.AspNetCore.Server.IISIntegration.Tests.csproj", "{4106DB10-E09F-480E-9CE6-B39235512EE6}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OutOfProcessWebSite", "test\WebSites\OutOfProcessWebSite\OutOfProcessWebSite.csproj", "{F54715C3-88D8-49E3-A291-C13570FE81FC}"
+	ProjectSection(ProjectDependencies) = postProject
+		{D57EA297-6DC2-4BC0-8C91-334863327863} = {D57EA297-6DC2-4BC0-8C91-334863327863}
+		{439824F9-1455-4CC4-BD79-B44FA0A16552} = {439824F9-1455-4CC4-BD79-B44FA0A16552}
+	EndProjectSection
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{7E80C58E-9CC8-450C-8A8D-94FC76428150}"
+	ProjectSection(SolutionItems) = preProject
+		build\applicationhost.config = build\applicationhost.config
+		build\applicationhost.iis.config = build\applicationhost.iis.config
+		build\dependencies.props = build\dependencies.props
+		build\Key.snk = build\Key.snk
+		build\native.targets = build\native.targets
+		build\repo.props = build\repo.props
+		build\testsite.props = build\testsite.props
+	EndProjectSection
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IISIntegration.FunctionalTests", "test\IISIntegration.FunctionalTests\IISIntegration.FunctionalTests.csproj", "{4E3E1F5C-CD52-4CC0-A35F-D1FA1685D2FA}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NativeIISSample", "samples\NativeIISSample\NativeIISSample.csproj", "{9BC4AFCB-325D-4C81-8228-8CF301CE2F97}"
+	ProjectSection(ProjectDependencies) = postProject
+		{D57EA297-6DC2-4BC0-8C91-334863327863} = {D57EA297-6DC2-4BC0-8C91-334863327863}
+		{439824F9-1455-4CC4-BD79-B44FA0A16552} = {439824F9-1455-4CC4-BD79-B44FA0A16552}
+	EndProjectSection
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "InProcessWebSite", "test\WebSites\InProcessWebSite\InProcessWebSite.csproj", "{679FA2A2-898B-4320-884E-C2D294A97CE1}"
+	ProjectSection(ProjectDependencies) = postProject
+		{D57EA297-6DC2-4BC0-8C91-334863327863} = {D57EA297-6DC2-4BC0-8C91-334863327863}
+		{439824F9-1455-4CC4-BD79-B44FA0A16552} = {439824F9-1455-4CC4-BD79-B44FA0A16552}
+	EndProjectSection
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Server.IIS", "src\Microsoft.AspNetCore.Server.IIS\Microsoft.AspNetCore.Server.IIS.csproj", "{46A8612B-418B-4D70-B3A7-A21DD0627473}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StressTestWebSite", "test\WebSites\StressTestWebSite\StressTestWebSite.csproj", "{13FD8F12-FFBE-4D01-B4AC-444F2994B04F}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestTasks", "test\TestTasks\TestTasks.csproj", "{064D860B-4D7C-4B1D-918F-E020F1B99E2A}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "WebSites", "WebSites", "{744ACDC6-F6A0-4FF9-9421-F25C5F2DC520}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OverriddenServerWebSite", "test\WebSites\OverriddenServerWebSite\OverriddenServerWebSite.csproj", "{FC2A97F8-A749-4C04-97D1-97500066A820}"
+	ProjectSection(ProjectDependencies) = postProject
+		{D57EA297-6DC2-4BC0-8C91-334863327863} = {D57EA297-6DC2-4BC0-8C91-334863327863}
+		{439824F9-1455-4CC4-BD79-B44FA0A16552} = {439824F9-1455-4CC4-BD79-B44FA0A16552}
+	EndProjectSection
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "AspNetCoreModuleV1", "AspNetCoreModuleV1", "{16E521CE-77F1-4B1C-A183-520A41C4F372}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "AspNetCoreModuleV2", "AspNetCoreModuleV2", "{06CA2C2B-83B0-4D83-905A-E0C74790009E}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "IISLib", "src\AspNetCoreModuleV1\IISLib\IISLib.vcxproj", "{4787A64F-9A3E-4867-A55A-70CB4B2B2FFE}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AspNetCore", "src\AspNetCoreModuleV1\AspNetCore\AspNetCore.vcxproj", "{439824F9-1455-4CC4-BD79-B44FA0A16552}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AspNetCore", "src\AspNetCoreModuleV2\AspNetCore\AspNetCore.vcxproj", "{EC82302F-D2F0-4727-99D1-EABC0DD9DC3B}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CommonLib", "src\AspNetCoreModuleV2\CommonLib\CommonLib.vcxproj", "{55494E58-E061-4C4C-A0A8-837008E72F85}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "IISLib", "src\AspNetCoreModuleV2\IISLib\IISLib.vcxproj", "{09D9D1D6-2951-4E14-BC35-76A23CF9391A}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RequestHandler", "src\AspNetCoreModuleV2\RequestHandler\RequestHandler.vcxproj", "{D57EA297-6DC2-4BC0-8C91-334863327863}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Debug|x64 = Debug|x64
+		Debug|x86 = Debug|x86
+		Release|Any CPU = Release|Any CPU
+		Release|x64 = Release|x64
+		Release|x86 = Release|x86
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{E4E2BDC4-A9C6-4AE9-B429-032EC83EDE64}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{E4E2BDC4-A9C6-4AE9-B429-032EC83EDE64}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{E4E2BDC4-A9C6-4AE9-B429-032EC83EDE64}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{E4E2BDC4-A9C6-4AE9-B429-032EC83EDE64}.Debug|x64.Build.0 = Debug|Any CPU
+		{E4E2BDC4-A9C6-4AE9-B429-032EC83EDE64}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{E4E2BDC4-A9C6-4AE9-B429-032EC83EDE64}.Debug|x86.Build.0 = Debug|Any CPU
+		{E4E2BDC4-A9C6-4AE9-B429-032EC83EDE64}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{E4E2BDC4-A9C6-4AE9-B429-032EC83EDE64}.Release|Any CPU.Build.0 = Release|Any CPU
+		{E4E2BDC4-A9C6-4AE9-B429-032EC83EDE64}.Release|x64.ActiveCfg = Release|Any CPU
+		{E4E2BDC4-A9C6-4AE9-B429-032EC83EDE64}.Release|x64.Build.0 = Release|Any CPU
+		{E4E2BDC4-A9C6-4AE9-B429-032EC83EDE64}.Release|x86.ActiveCfg = Release|Any CPU
+		{E4E2BDC4-A9C6-4AE9-B429-032EC83EDE64}.Release|x86.Build.0 = Release|Any CPU
+		{8B3446E8-E6A8-4591-AA63-A95837C6E97C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{8B3446E8-E6A8-4591-AA63-A95837C6E97C}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{8B3446E8-E6A8-4591-AA63-A95837C6E97C}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{8B3446E8-E6A8-4591-AA63-A95837C6E97C}.Debug|x64.Build.0 = Debug|Any CPU
+		{8B3446E8-E6A8-4591-AA63-A95837C6E97C}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{8B3446E8-E6A8-4591-AA63-A95837C6E97C}.Debug|x86.Build.0 = Debug|Any CPU
+		{8B3446E8-E6A8-4591-AA63-A95837C6E97C}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{8B3446E8-E6A8-4591-AA63-A95837C6E97C}.Release|Any CPU.Build.0 = Release|Any CPU
+		{8B3446E8-E6A8-4591-AA63-A95837C6E97C}.Release|x64.ActiveCfg = Release|Any CPU
+		{8B3446E8-E6A8-4591-AA63-A95837C6E97C}.Release|x64.Build.0 = Release|Any CPU
+		{8B3446E8-E6A8-4591-AA63-A95837C6E97C}.Release|x86.ActiveCfg = Release|Any CPU
+		{8B3446E8-E6A8-4591-AA63-A95837C6E97C}.Release|x86.Build.0 = Release|Any CPU
+		{4106DB10-E09F-480E-9CE6-B39235512EE6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{4106DB10-E09F-480E-9CE6-B39235512EE6}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{4106DB10-E09F-480E-9CE6-B39235512EE6}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{4106DB10-E09F-480E-9CE6-B39235512EE6}.Debug|x64.Build.0 = Debug|Any CPU
+		{4106DB10-E09F-480E-9CE6-B39235512EE6}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{4106DB10-E09F-480E-9CE6-B39235512EE6}.Debug|x86.Build.0 = Debug|Any CPU
+		{4106DB10-E09F-480E-9CE6-B39235512EE6}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{4106DB10-E09F-480E-9CE6-B39235512EE6}.Release|Any CPU.Build.0 = Release|Any CPU
+		{4106DB10-E09F-480E-9CE6-B39235512EE6}.Release|x64.ActiveCfg = Release|Any CPU
+		{4106DB10-E09F-480E-9CE6-B39235512EE6}.Release|x64.Build.0 = Release|Any CPU
+		{4106DB10-E09F-480E-9CE6-B39235512EE6}.Release|x86.ActiveCfg = Release|Any CPU
+		{4106DB10-E09F-480E-9CE6-B39235512EE6}.Release|x86.Build.0 = Release|Any CPU
+		{F54715C3-88D8-49E3-A291-C13570FE81FC}.Debug|Any CPU.ActiveCfg = Debug|x86
+		{F54715C3-88D8-49E3-A291-C13570FE81FC}.Debug|x64.ActiveCfg = Debug|x64
+		{F54715C3-88D8-49E3-A291-C13570FE81FC}.Debug|x64.Build.0 = Debug|x64
+		{F54715C3-88D8-49E3-A291-C13570FE81FC}.Debug|x86.ActiveCfg = Debug|x86
+		{F54715C3-88D8-49E3-A291-C13570FE81FC}.Debug|x86.Build.0 = Debug|x86
+		{F54715C3-88D8-49E3-A291-C13570FE81FC}.Release|Any CPU.ActiveCfg = Release|x86
+		{F54715C3-88D8-49E3-A291-C13570FE81FC}.Release|x64.ActiveCfg = Release|x64
+		{F54715C3-88D8-49E3-A291-C13570FE81FC}.Release|x64.Build.0 = Release|x64
+		{F54715C3-88D8-49E3-A291-C13570FE81FC}.Release|x86.ActiveCfg = Release|x86
+		{F54715C3-88D8-49E3-A291-C13570FE81FC}.Release|x86.Build.0 = Release|x86
+		{4E3E1F5C-CD52-4CC0-A35F-D1FA1685D2FA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{4E3E1F5C-CD52-4CC0-A35F-D1FA1685D2FA}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{4E3E1F5C-CD52-4CC0-A35F-D1FA1685D2FA}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{4E3E1F5C-CD52-4CC0-A35F-D1FA1685D2FA}.Debug|x64.Build.0 = Debug|Any CPU
+		{4E3E1F5C-CD52-4CC0-A35F-D1FA1685D2FA}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{4E3E1F5C-CD52-4CC0-A35F-D1FA1685D2FA}.Debug|x86.Build.0 = Debug|Any CPU
+		{4E3E1F5C-CD52-4CC0-A35F-D1FA1685D2FA}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{4E3E1F5C-CD52-4CC0-A35F-D1FA1685D2FA}.Release|Any CPU.Build.0 = Release|Any CPU
+		{4E3E1F5C-CD52-4CC0-A35F-D1FA1685D2FA}.Release|x64.ActiveCfg = Release|Any CPU
+		{4E3E1F5C-CD52-4CC0-A35F-D1FA1685D2FA}.Release|x64.Build.0 = Release|Any CPU
+		{4E3E1F5C-CD52-4CC0-A35F-D1FA1685D2FA}.Release|x86.ActiveCfg = Release|Any CPU
+		{4E3E1F5C-CD52-4CC0-A35F-D1FA1685D2FA}.Release|x86.Build.0 = Release|Any CPU
+		{9BC4AFCB-325D-4C81-8228-8CF301CE2F97}.Debug|Any CPU.ActiveCfg = Debug|x64
+		{9BC4AFCB-325D-4C81-8228-8CF301CE2F97}.Debug|Any CPU.Build.0 = Debug|x64
+		{9BC4AFCB-325D-4C81-8228-8CF301CE2F97}.Debug|x64.ActiveCfg = Debug|x64
+		{9BC4AFCB-325D-4C81-8228-8CF301CE2F97}.Debug|x64.Build.0 = Debug|x64
+		{9BC4AFCB-325D-4C81-8228-8CF301CE2F97}.Debug|x86.ActiveCfg = Debug|x86
+		{9BC4AFCB-325D-4C81-8228-8CF301CE2F97}.Debug|x86.Build.0 = Debug|x86
+		{9BC4AFCB-325D-4C81-8228-8CF301CE2F97}.Release|Any CPU.ActiveCfg = Release|x64
+		{9BC4AFCB-325D-4C81-8228-8CF301CE2F97}.Release|Any CPU.Build.0 = Release|x64
+		{9BC4AFCB-325D-4C81-8228-8CF301CE2F97}.Release|x64.ActiveCfg = Release|x64
+		{9BC4AFCB-325D-4C81-8228-8CF301CE2F97}.Release|x64.Build.0 = Release|x64
+		{9BC4AFCB-325D-4C81-8228-8CF301CE2F97}.Release|x86.ActiveCfg = Release|x86
+		{9BC4AFCB-325D-4C81-8228-8CF301CE2F97}.Release|x86.Build.0 = Release|x86
+		{679FA2A2-898B-4320-884E-C2D294A97CE1}.Debug|Any CPU.ActiveCfg = Debug|x86
+		{679FA2A2-898B-4320-884E-C2D294A97CE1}.Debug|x64.ActiveCfg = Debug|x64
+		{679FA2A2-898B-4320-884E-C2D294A97CE1}.Debug|x64.Build.0 = Debug|x64
+		{679FA2A2-898B-4320-884E-C2D294A97CE1}.Debug|x86.ActiveCfg = Debug|x86
+		{679FA2A2-898B-4320-884E-C2D294A97CE1}.Debug|x86.Build.0 = Debug|x86
+		{679FA2A2-898B-4320-884E-C2D294A97CE1}.Release|Any CPU.ActiveCfg = Release|x86
+		{679FA2A2-898B-4320-884E-C2D294A97CE1}.Release|x64.ActiveCfg = Release|x64
+		{679FA2A2-898B-4320-884E-C2D294A97CE1}.Release|x64.Build.0 = Release|x64
+		{679FA2A2-898B-4320-884E-C2D294A97CE1}.Release|x86.ActiveCfg = Release|x86
+		{679FA2A2-898B-4320-884E-C2D294A97CE1}.Release|x86.Build.0 = Release|x86
+		{46A8612B-418B-4D70-B3A7-A21DD0627473}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{46A8612B-418B-4D70-B3A7-A21DD0627473}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{46A8612B-418B-4D70-B3A7-A21DD0627473}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{46A8612B-418B-4D70-B3A7-A21DD0627473}.Debug|x64.Build.0 = Debug|Any CPU
+		{46A8612B-418B-4D70-B3A7-A21DD0627473}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{46A8612B-418B-4D70-B3A7-A21DD0627473}.Debug|x86.Build.0 = Debug|Any CPU
+		{46A8612B-418B-4D70-B3A7-A21DD0627473}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{46A8612B-418B-4D70-B3A7-A21DD0627473}.Release|Any CPU.Build.0 = Release|Any CPU
+		{46A8612B-418B-4D70-B3A7-A21DD0627473}.Release|x64.ActiveCfg = Release|Any CPU
+		{46A8612B-418B-4D70-B3A7-A21DD0627473}.Release|x64.Build.0 = Release|Any CPU
+		{46A8612B-418B-4D70-B3A7-A21DD0627473}.Release|x86.ActiveCfg = Release|Any CPU
+		{46A8612B-418B-4D70-B3A7-A21DD0627473}.Release|x86.Build.0 = Release|Any CPU
+		{13FD8F12-FFBE-4D01-B4AC-444F2994B04F}.Debug|Any CPU.ActiveCfg = Debug|x86
+		{13FD8F12-FFBE-4D01-B4AC-444F2994B04F}.Debug|x64.ActiveCfg = Debug|x64
+		{13FD8F12-FFBE-4D01-B4AC-444F2994B04F}.Debug|x64.Build.0 = Debug|x64
+		{13FD8F12-FFBE-4D01-B4AC-444F2994B04F}.Debug|x86.ActiveCfg = Debug|x86
+		{13FD8F12-FFBE-4D01-B4AC-444F2994B04F}.Debug|x86.Build.0 = Debug|x86
+		{13FD8F12-FFBE-4D01-B4AC-444F2994B04F}.Release|Any CPU.ActiveCfg = Release|x86
+		{13FD8F12-FFBE-4D01-B4AC-444F2994B04F}.Release|x64.ActiveCfg = Release|x64
+		{13FD8F12-FFBE-4D01-B4AC-444F2994B04F}.Release|x64.Build.0 = Release|x64
+		{13FD8F12-FFBE-4D01-B4AC-444F2994B04F}.Release|x86.ActiveCfg = Release|x86
+		{13FD8F12-FFBE-4D01-B4AC-444F2994B04F}.Release|x86.Build.0 = Release|x86
+		{064D860B-4D7C-4B1D-918F-E020F1B99E2A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{064D860B-4D7C-4B1D-918F-E020F1B99E2A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{064D860B-4D7C-4B1D-918F-E020F1B99E2A}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{064D860B-4D7C-4B1D-918F-E020F1B99E2A}.Debug|x64.Build.0 = Debug|Any CPU
+		{064D860B-4D7C-4B1D-918F-E020F1B99E2A}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{064D860B-4D7C-4B1D-918F-E020F1B99E2A}.Debug|x86.Build.0 = Debug|Any CPU
+		{064D860B-4D7C-4B1D-918F-E020F1B99E2A}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{064D860B-4D7C-4B1D-918F-E020F1B99E2A}.Release|Any CPU.Build.0 = Release|Any CPU
+		{064D860B-4D7C-4B1D-918F-E020F1B99E2A}.Release|x64.ActiveCfg = Release|Any CPU
+		{064D860B-4D7C-4B1D-918F-E020F1B99E2A}.Release|x64.Build.0 = Release|Any CPU
+		{064D860B-4D7C-4B1D-918F-E020F1B99E2A}.Release|x86.ActiveCfg = Release|Any CPU
+		{064D860B-4D7C-4B1D-918F-E020F1B99E2A}.Release|x86.Build.0 = Release|Any CPU
+		{FC2A97F8-A749-4C04-97D1-97500066A820}.Debug|Any CPU.ActiveCfg = Debug|x86
+		{FC2A97F8-A749-4C04-97D1-97500066A820}.Debug|x64.ActiveCfg = Debug|x64
+		{FC2A97F8-A749-4C04-97D1-97500066A820}.Debug|x64.Build.0 = Debug|x64
+		{FC2A97F8-A749-4C04-97D1-97500066A820}.Debug|x86.ActiveCfg = Debug|x86
+		{FC2A97F8-A749-4C04-97D1-97500066A820}.Debug|x86.Build.0 = Debug|x86
+		{FC2A97F8-A749-4C04-97D1-97500066A820}.Release|Any CPU.ActiveCfg = Release|x86
+		{FC2A97F8-A749-4C04-97D1-97500066A820}.Release|x64.ActiveCfg = Release|x64
+		{FC2A97F8-A749-4C04-97D1-97500066A820}.Release|x64.Build.0 = Release|x64
+		{FC2A97F8-A749-4C04-97D1-97500066A820}.Release|x86.ActiveCfg = Release|x86
+		{FC2A97F8-A749-4C04-97D1-97500066A820}.Release|x86.Build.0 = Release|x86
+		{4787A64F-9A3E-4867-A55A-70CB4B2B2FFE}.Debug|Any CPU.ActiveCfg = Debug|Win32
+		{4787A64F-9A3E-4867-A55A-70CB4B2B2FFE}.Debug|x64.ActiveCfg = Debug|x64
+		{4787A64F-9A3E-4867-A55A-70CB4B2B2FFE}.Debug|x64.Build.0 = Debug|x64
+		{4787A64F-9A3E-4867-A55A-70CB4B2B2FFE}.Debug|x86.ActiveCfg = Debug|Win32
+		{4787A64F-9A3E-4867-A55A-70CB4B2B2FFE}.Debug|x86.Build.0 = Debug|Win32
+		{4787A64F-9A3E-4867-A55A-70CB4B2B2FFE}.Release|Any CPU.ActiveCfg = Release|Win32
+		{4787A64F-9A3E-4867-A55A-70CB4B2B2FFE}.Release|x64.ActiveCfg = Release|x64
+		{4787A64F-9A3E-4867-A55A-70CB4B2B2FFE}.Release|x64.Build.0 = Release|x64
+		{4787A64F-9A3E-4867-A55A-70CB4B2B2FFE}.Release|x86.ActiveCfg = Release|Win32
+		{4787A64F-9A3E-4867-A55A-70CB4B2B2FFE}.Release|x86.Build.0 = Release|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.Build.0 = Debug|x64
+		{439824F9-1455-4CC4-BD79-B44FA0A16552}.Debug|x86.ActiveCfg = Debug|Win32
+		{439824F9-1455-4CC4-BD79-B44FA0A16552}.Debug|x86.Build.0 = Debug|Win32
+		{439824F9-1455-4CC4-BD79-B44FA0A16552}.Release|Any CPU.ActiveCfg = Release|Win32
+		{439824F9-1455-4CC4-BD79-B44FA0A16552}.Release|x64.ActiveCfg = Release|x64
+		{439824F9-1455-4CC4-BD79-B44FA0A16552}.Release|x64.Build.0 = Release|x64
+		{439824F9-1455-4CC4-BD79-B44FA0A16552}.Release|x86.ActiveCfg = Release|Win32
+		{439824F9-1455-4CC4-BD79-B44FA0A16552}.Release|x86.Build.0 = Release|Win32
+		{EC82302F-D2F0-4727-99D1-EABC0DD9DC3B}.Debug|Any CPU.ActiveCfg = Debug|Win32
+		{EC82302F-D2F0-4727-99D1-EABC0DD9DC3B}.Debug|x64.ActiveCfg = Debug|x64
+		{EC82302F-D2F0-4727-99D1-EABC0DD9DC3B}.Debug|x64.Build.0 = Debug|x64
+		{EC82302F-D2F0-4727-99D1-EABC0DD9DC3B}.Debug|x86.ActiveCfg = Debug|Win32
+		{EC82302F-D2F0-4727-99D1-EABC0DD9DC3B}.Debug|x86.Build.0 = Debug|Win32
+		{EC82302F-D2F0-4727-99D1-EABC0DD9DC3B}.Release|Any CPU.ActiveCfg = Release|Win32
+		{EC82302F-D2F0-4727-99D1-EABC0DD9DC3B}.Release|x64.ActiveCfg = Release|x64
+		{EC82302F-D2F0-4727-99D1-EABC0DD9DC3B}.Release|x64.Build.0 = Release|x64
+		{EC82302F-D2F0-4727-99D1-EABC0DD9DC3B}.Release|x86.ActiveCfg = Release|Win32
+		{EC82302F-D2F0-4727-99D1-EABC0DD9DC3B}.Release|x86.Build.0 = Release|Win32
+		{55494E58-E061-4C4C-A0A8-837008E72F85}.Debug|Any CPU.ActiveCfg = Debug|Win32
+		{55494E58-E061-4C4C-A0A8-837008E72F85}.Debug|x64.ActiveCfg = Debug|x64
+		{55494E58-E061-4C4C-A0A8-837008E72F85}.Debug|x64.Build.0 = Debug|x64
+		{55494E58-E061-4C4C-A0A8-837008E72F85}.Debug|x86.ActiveCfg = Debug|Win32
+		{55494E58-E061-4C4C-A0A8-837008E72F85}.Debug|x86.Build.0 = Debug|Win32
+		{55494E58-E061-4C4C-A0A8-837008E72F85}.Release|Any CPU.ActiveCfg = Release|Win32
+		{55494E58-E061-4C4C-A0A8-837008E72F85}.Release|x64.ActiveCfg = Release|x64
+		{55494E58-E061-4C4C-A0A8-837008E72F85}.Release|x64.Build.0 = Release|x64
+		{55494E58-E061-4C4C-A0A8-837008E72F85}.Release|x86.ActiveCfg = Release|Win32
+		{55494E58-E061-4C4C-A0A8-837008E72F85}.Release|x86.Build.0 = Release|Win32
+		{09D9D1D6-2951-4E14-BC35-76A23CF9391A}.Debug|Any CPU.ActiveCfg = Debug|Win32
+		{09D9D1D6-2951-4E14-BC35-76A23CF9391A}.Debug|x64.ActiveCfg = Debug|x64
+		{09D9D1D6-2951-4E14-BC35-76A23CF9391A}.Debug|x64.Build.0 = Debug|x64
+		{09D9D1D6-2951-4E14-BC35-76A23CF9391A}.Debug|x86.ActiveCfg = Debug|Win32
+		{09D9D1D6-2951-4E14-BC35-76A23CF9391A}.Debug|x86.Build.0 = Debug|Win32
+		{09D9D1D6-2951-4E14-BC35-76A23CF9391A}.Release|Any CPU.ActiveCfg = Release|Win32
+		{09D9D1D6-2951-4E14-BC35-76A23CF9391A}.Release|x64.ActiveCfg = Release|x64
+		{09D9D1D6-2951-4E14-BC35-76A23CF9391A}.Release|x64.Build.0 = Release|x64
+		{09D9D1D6-2951-4E14-BC35-76A23CF9391A}.Release|x86.ActiveCfg = Release|Win32
+		{09D9D1D6-2951-4E14-BC35-76A23CF9391A}.Release|x86.Build.0 = Release|Win32
+		{D57EA297-6DC2-4BC0-8C91-334863327863}.Debug|Any CPU.ActiveCfg = Debug|Win32
+		{D57EA297-6DC2-4BC0-8C91-334863327863}.Debug|x64.ActiveCfg = Debug|x64
+		{D57EA297-6DC2-4BC0-8C91-334863327863}.Debug|x64.Build.0 = Debug|x64
+		{D57EA297-6DC2-4BC0-8C91-334863327863}.Debug|x86.ActiveCfg = Debug|Win32
+		{D57EA297-6DC2-4BC0-8C91-334863327863}.Debug|x86.Build.0 = Debug|Win32
+		{D57EA297-6DC2-4BC0-8C91-334863327863}.Release|Any CPU.ActiveCfg = Release|Win32
+		{D57EA297-6DC2-4BC0-8C91-334863327863}.Release|x64.ActiveCfg = Release|x64
+		{D57EA297-6DC2-4BC0-8C91-334863327863}.Release|x64.Build.0 = Release|x64
+		{D57EA297-6DC2-4BC0-8C91-334863327863}.Release|x86.ActiveCfg = Release|Win32
+		{D57EA297-6DC2-4BC0-8C91-334863327863}.Release|x86.Build.0 = Release|Win32
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(NestedProjects) = preSolution
+		{E4E2BDC4-A9C6-4AE9-B429-032EC83EDE64} = {C74B8F36-FD2F-45C9-9B8A-00E7CF0126A9}
+		{8B3446E8-E6A8-4591-AA63-A95837C6E97C} = {04B1EDB6-E967-4D25-89B9-E6F8304038CD}
+		{4106DB10-E09F-480E-9CE6-B39235512EE6} = {EF30B533-D715-421A-92B7-92FEF460AC9C}
+		{F54715C3-88D8-49E3-A291-C13570FE81FC} = {744ACDC6-F6A0-4FF9-9421-F25C5F2DC520}
+		{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} = {744ACDC6-F6A0-4FF9-9421-F25C5F2DC520}
+		{46A8612B-418B-4D70-B3A7-A21DD0627473} = {04B1EDB6-E967-4D25-89B9-E6F8304038CD}
+		{13FD8F12-FFBE-4D01-B4AC-444F2994B04F} = {744ACDC6-F6A0-4FF9-9421-F25C5F2DC520}
+		{064D860B-4D7C-4B1D-918F-E020F1B99E2A} = {EF30B533-D715-421A-92B7-92FEF460AC9C}
+		{744ACDC6-F6A0-4FF9-9421-F25C5F2DC520} = {EF30B533-D715-421A-92B7-92FEF460AC9C}
+		{FC2A97F8-A749-4C04-97D1-97500066A820} = {744ACDC6-F6A0-4FF9-9421-F25C5F2DC520}
+		{16E521CE-77F1-4B1C-A183-520A41C4F372} = {04B1EDB6-E967-4D25-89B9-E6F8304038CD}
+		{06CA2C2B-83B0-4D83-905A-E0C74790009E} = {04B1EDB6-E967-4D25-89B9-E6F8304038CD}
+		{4787A64F-9A3E-4867-A55A-70CB4B2B2FFE} = {16E521CE-77F1-4B1C-A183-520A41C4F372}
+		{439824F9-1455-4CC4-BD79-B44FA0A16552} = {16E521CE-77F1-4B1C-A183-520A41C4F372}
+		{EC82302F-D2F0-4727-99D1-EABC0DD9DC3B} = {06CA2C2B-83B0-4D83-905A-E0C74790009E}
+		{55494E58-E061-4C4C-A0A8-837008E72F85} = {06CA2C2B-83B0-4D83-905A-E0C74790009E}
+		{09D9D1D6-2951-4E14-BC35-76A23CF9391A} = {06CA2C2B-83B0-4D83-905A-E0C74790009E}
+		{D57EA297-6DC2-4BC0-8C91-334863327863} = {06CA2C2B-83B0-4D83-905A-E0C74790009E}
+	EndGlobalSection
+	GlobalSection(ExtensibilityGlobals) = postSolution
+		SolutionGuid = {DB4F868D-E1AE-4FD7-9333-69FA15B268C5}
+	EndGlobalSection
+EndGlobal
diff --git a/src/IISIntegration/LICENSE.txt b/src/IISIntegration/LICENSE.txt
new file mode 100644
index 0000000000000000000000000000000000000000..d50cef4a3fd839d7b9609f9b999140138b51f92f
--- /dev/null
+++ b/src/IISIntegration/LICENSE.txt
@@ -0,0 +1,38 @@
+Copyright (c) .NET Foundation and Contributors
+
+All rights reserved.
+
+Licensed under the Apache License, Version 2.0 (the "License"); you may not use
+this file except in compliance with the License. You may obtain a copy of the
+License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software distributed
+under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+CONDITIONS OF ANY KIND, either express or implied. See the License for the
+specific language governing permissions and limitations under the License.
+
+ASP.NET Core Module
+
+Copyright (c) .NET Foundation
+All rights reserved.
+
+MIT License
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the ""Software""), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\ No newline at end of file
diff --git a/src/IISIntegration/NuGetPackageVerifier.json b/src/IISIntegration/NuGetPackageVerifier.json
new file mode 100644
index 0000000000000000000000000000000000000000..eea701bb65c5285b68dd3481341fa62c22999bdf
--- /dev/null
+++ b/src/IISIntegration/NuGetPackageVerifier.json
@@ -0,0 +1,14 @@
+{
+    "adx-nonshipping": {
+        "rules": [],
+        "packages": {
+            "Microsoft.AspNetCore.AspNetCoreModule": {},
+            "Microsoft.AspNetCore.AspNetCoreModuleV1": {}
+        }
+    },
+    "Default": {
+        "rules": [
+            "DefaultCompositeRule"
+        ]
+    }
+}
\ No newline at end of file
diff --git a/src/IISIntegration/NuGetPackageVerifier.xplat.json b/src/IISIntegration/NuGetPackageVerifier.xplat.json
new file mode 100644
index 0000000000000000000000000000000000000000..c5f5582998986bd4a03de59450eccf32d317a190
--- /dev/null
+++ b/src/IISIntegration/NuGetPackageVerifier.xplat.json
@@ -0,0 +1,7 @@
+{
+    "Default": {
+        "rules": [
+            "DefaultCompositeRule"
+        ]
+    }
+}
diff --git a/src/IISIntegration/README.md b/src/IISIntegration/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..f9310e5d9e5e26b1013a02f484936547b37abf3c
--- /dev/null
+++ b/src/IISIntegration/README.md
@@ -0,0 +1,3 @@
+This repo hosts the ASP.NET Core middleware for IIS integration and the ASP.NET Core Module.
+
+This project is part of ASP.NET Core. You can find samples, documentation and getting started instructions for ASP.NET Core at the [Home](https://github.com/aspnet/home) repo.
diff --git a/src/IISIntegration/build.cmd b/src/IISIntegration/build.cmd
new file mode 100644
index 0000000000000000000000000000000000000000..f4169ea5e41154062f761c9b68e28a143e4c6a89
--- /dev/null
+++ b/src/IISIntegration/build.cmd
@@ -0,0 +1,3 @@
+@ECHO OFF
+SET RepoRoot="%~dp0..\.."
+%RepoRoot%\build.cmd -LockFile %RepoRoot%\korebuild-lock.txt -Path %~dp0 %*
diff --git a/src/IISIntegration/build.sh b/src/IISIntegration/build.sh
new file mode 100644
index 0000000000000000000000000000000000000000..d5bb0cf6312d439ea4d35b1c836db3e040103e8d
--- /dev/null
+++ b/src/IISIntegration/build.sh
@@ -0,0 +1,7 @@
+#!/usr/bin/env bash
+
+set -euo pipefail
+
+DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+repo_root="$DIR/../.."
+"$repo_root/build.sh" --path "$DIR" --lockfile "$repo_root/korebuild-lock.txt" "$@"
diff --git a/src/IISIntegration/build/Build.Settings b/src/IISIntegration/build/Build.Settings
new file mode 100644
index 0000000000000000000000000000000000000000..9daccf4aaab2fb7c596b5b39e7d8fd05ef272a97
--- /dev/null
+++ b/src/IISIntegration/build/Build.Settings
@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="utf-8"?>
+ <Project ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+   <PropertyGroup>
+     <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">$(MSBuildThisFileDirectory)..\</SolutionDir>
+     <Configuration Condition="'$(Configuration)'==''">Debug</Configuration>
+     <Platform Condition="'$(Platform)' == ''">Win32</Platform>
+     <PlatformToolset Condition=" '$(VisualStudioVersion)' == '12.0'">v120</PlatformToolset>
+     <PlatformToolset Condition=" '$(VisualStudioVersion)' == '14.0'">v140</PlatformToolset>
+     <PlatformToolset Condition=" '$(PlatformToolset)' == ''">v120</PlatformToolset>
+     <OutputPath Condition="'$(OutputPath)' == ''">$(MSBuildProjectDirectory)\bin\$(Configuration)\$(Platform)\</OutputPath>
+     <OutDir>$(OutputPath)</OutDir>
+     <AspNetCoreModuleTargetName>aspnetcore</AspNetCoreModuleTargetName>
+   </PropertyGroup>
+ 
+   <PropertyGroup Condition="'$(Configuration)' == 'Debug'">
+     <UseDebugLibraries>true</UseDebugLibraries>
+     <WholeProgramOptimization>false</WholeProgramOptimization>
+   </PropertyGroup>
+ 
+   <PropertyGroup Condition="'$(Configuration)' == 'Release'">
+     <UseDebugLibraries>false</UseDebugLibraries>
+     <WholeProgramOptimization>true</WholeProgramOptimization>
+   </PropertyGroup>
+ 
+   <ItemDefinitionGroup>
+     <ClCompile>
+       <PrecompiledHeader>Use</PrecompiledHeader>
+       <TreatWarningAsError Condition="'$(TreatWarningsAsErrors)' != ''">true</TreatWarningAsError>
+       <SDLCheck>true</SDLCheck>
+       <StringPooling>true</StringPooling>
+     </ClCompile>
+     <Link>
+       <SubSystem>Windows</SubSystem>
+       <GenerateDebugInformation>true</GenerateDebugInformation>
+       <ProgramDatabaseFile>$(OutDir)$(TargetName).pdb</ProgramDatabaseFile>
+       <StripPrivateSymbols>$(OutDir)$(TargetName).pub.pdb</StripPrivateSymbols>
+       <OptimizeReferences>true</OptimizeReferences>
+       <EnableCOMDATFolding>true</EnableCOMDATFolding>
+       <Profile>true</Profile>
+     </Link>
+   </ItemDefinitionGroup>
+ 
+   <ItemDefinitionGroup Condition="'$(Configuration)'=='Debug'">
+     <ClCompile>
+       <Optimization>Disabled</Optimization>
+     </ClCompile>
+   </ItemDefinitionGroup>
+ 
+   <ItemDefinitionGroup Condition="'$(Configuration)'=='Release'">
+     <ClCompile>
+       <Optimization>MaxSpeed</Optimization>
+       <FunctionLevelLinking>true</FunctionLevelLinking>
+       <IntrinsicFunctions>true</IntrinsicFunctions>
+     </ClCompile>
+   </ItemDefinitionGroup>
+ 
+   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+     <ClCompile>
+       <PreprocessorDefinitions>WIN32;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+     </ClCompile>
+   </ItemDefinitionGroup>
+ 
+   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+     <ClCompile>
+       <PreprocessorDefinitions>_WIN64;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+     </ClCompile>
+   </ItemDefinitionGroup>
+ 
+   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+     <ClCompile>
+       <PreprocessorDefinitions>WIN32;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+     </ClCompile>
+     <Link>
+       <GenerateDebugInformation>true</GenerateDebugInformation>
+     </Link>
+   </ItemDefinitionGroup>
+ 
+   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+     <ClCompile>
+       <PreprocessorDefinitions>_WIN64;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+     </ClCompile>
+     <Link>
+       <GenerateDebugInformation>true</GenerateDebugInformation>
+     </Link>
+   </ItemDefinitionGroup>
+ 
+  <PropertyGroup>
+    <_TwoDigitYear>$([MSBuild]::Subtract($([System.DateTime]::UtcNow.Year), 2000))</_TwoDigitYear>
+    <_ThreeDigitDayOfYear>$([System.DateTime]::UtcNow.DayOfYear.ToString().PadLeft(3, '0'))</_ThreeDigitDayOfYear>
+    <AssemblyBuild>$(_TwoDigitYear)$(_ThreeDigitDayOfYear)</AssemblyBuild>
+  </PropertyGroup>
+
+ </Project>
\ No newline at end of file
diff --git a/src/IISIntegration/build/Config.Definitions.Props b/src/IISIntegration/build/Config.Definitions.Props
new file mode 100644
index 0000000000000000000000000000000000000000..974816b5d79e95fc8fe83e2179b0a8629e19befd
--- /dev/null
+++ b/src/IISIntegration/build/Config.Definitions.Props
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?> 
+ <Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> 
+   <ItemGroup Label="ProjectConfigurations"> 
+     <ProjectConfiguration Include="Debug|Win32"> 
+       <Configuration>Debug</Configuration> 
+       <Platform>Win32</Platform> 
+     </ProjectConfiguration> 
+     <ProjectConfiguration Include="Debug|x64"> 
+       <Configuration>Debug</Configuration> 
+       <Platform>x64</Platform> 
+     </ProjectConfiguration> 
+     <ProjectConfiguration Include="Release|Win32"> 
+       <Configuration>Release</Configuration> 
+       <Platform>Win32</Platform> 
+     </ProjectConfiguration> 
+     <ProjectConfiguration Include="Release|x64"> 
+       <Configuration>Release</Configuration> 
+       <Platform>x64</Platform> 
+     </ProjectConfiguration> 
+   </ItemGroup> 
+ </Project>
\ No newline at end of file
diff --git a/src/IISIntegration/build/Key.snk b/src/IISIntegration/build/Key.snk
new file mode 100644
index 0000000000000000000000000000000000000000..e10e4889c125d3120cd9e81582243d70f7cbb806
Binary files /dev/null and b/src/IISIntegration/build/Key.snk differ
diff --git a/src/IISIntegration/build/applicationhost.config b/src/IISIntegration/build/applicationhost.config
new file mode 100644
index 0000000000000000000000000000000000000000..9af39ac631af1d50a0fda5708bfbd6c92bd33cca
--- /dev/null
+++ b/src/IISIntegration/build/applicationhost.config
@@ -0,0 +1,966 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    IIS configuration sections.
+
+    For schema documentation, see
+    %IIS_BIN%\config\schema\IIS_schema.xml.
+
+    Please make a backup of this file before making any changes to it.
+
+    NOTE: The following environment variables are available to be used
+          within this file and are understood by the IIS Express.
+
+          %IIS_USER_HOME% - The IIS Express home directory for the user
+          %IIS_SITES_HOME% - The default home directory for sites
+          %IIS_BIN% - The location of the IIS Express binaries
+          %SYSTEMDRIVE% - The drive letter of %IIS_BIN%
+
+-->
+<configuration>
+  <!--
+
+        The <configSections> section controls the registration of sections.
+        Section is the basic unit of deployment, locking, searching and
+        containment for configuration settings.
+
+        Every section belongs to one section group.
+        A section group is a container of logically-related sections.
+
+        Sections cannot be nested.
+        Section groups may be nested.
+
+        <section
+            name=""  [Required, Collection Key] [XML name of the section]
+            allowDefinition="Everywhere" [MachineOnly|MachineToApplication|AppHostOnly|Everywhere] [Level where it can be set]
+            overrideModeDefault="Allow"  [Allow|Deny] [Default delegation mode]
+            allowLocation="true"  [true|false] [Allowed in location tags]
+        />
+
+        The recommended way to unlock sections is by using a location tag:
+        <location path="Default Web Site" overrideMode="Allow">
+            <system.webServer>
+                <asp />
+            </system.webServer>
+        </location>
+
+    -->
+  <configSections>
+    <sectionGroup name="system.applicationHost">
+      <section name="applicationPools" allowDefinition="AppHostOnly" overrideModeDefault="Deny" />
+      <section name="configHistory" allowDefinition="AppHostOnly" overrideModeDefault="Deny" />
+      <section name="customMetadata" allowDefinition="AppHostOnly" overrideModeDefault="Deny" />
+      <section name="listenerAdapters" allowDefinition="AppHostOnly" overrideModeDefault="Deny" />
+      <section name="log" allowDefinition="AppHostOnly" overrideModeDefault="Deny" />
+      <section name="serviceAutoStartProviders" allowDefinition="AppHostOnly" overrideModeDefault="Deny" />
+      <section name="sites" allowDefinition="AppHostOnly" overrideModeDefault="Deny" />
+      <section name="webLimits" allowDefinition="AppHostOnly" overrideModeDefault="Deny" />
+    </sectionGroup>
+    <sectionGroup name="system.webServer">
+      <section name="asp" overrideModeDefault="Deny" />
+      <section name="caching" overrideModeDefault="Allow" />
+      <section name="cgi" overrideModeDefault="Deny" />
+      <section name="defaultDocument" overrideModeDefault="Allow" />
+      <section name="directoryBrowse" overrideModeDefault="Allow" />
+      <section name="fastCgi" allowDefinition="AppHostOnly" overrideModeDefault="Deny" />
+      <section name="globalModules" allowDefinition="AppHostOnly" overrideModeDefault="Deny" />
+      <section name="handlers" overrideModeDefault="Deny" />
+      <section name="httpCompression" overrideModeDefault="Allow" />
+      <section name="httpErrors" overrideModeDefault="Allow" />
+      <section name="httpLogging" overrideModeDefault="Deny" />
+      <section name="httpProtocol" overrideModeDefault="Allow" />
+      <section name="httpRedirect" overrideModeDefault="Allow" />
+      <section name="httpTracing" overrideModeDefault="Deny" />
+      <section name="isapiFilters" allowDefinition="MachineToApplication" overrideModeDefault="Deny" />
+      <section name="modules" allowDefinition="MachineToApplication" overrideModeDefault="Deny" />
+      <section name="applicationInitialization" allowDefinition="MachineToApplication" overrideModeDefault="Allow" />
+      <section name="odbcLogging" overrideModeDefault="Deny" />
+      <sectionGroup name="security">
+        <section name="access" overrideModeDefault="Deny" />
+        <section name="applicationDependencies" overrideModeDefault="Deny" />
+        <sectionGroup name="authentication">
+          <section name="anonymousAuthentication" overrideModeDefault="Deny" />
+          <section name="basicAuthentication" overrideModeDefault="Deny" />
+          <section name="clientCertificateMappingAuthentication" overrideModeDefault="Deny" />
+          <section name="digestAuthentication" overrideModeDefault="Deny" />
+          <section name="iisClientCertificateMappingAuthentication" overrideModeDefault="Deny" />
+          <section name="windowsAuthentication" overrideModeDefault="Deny" />
+        </sectionGroup>
+        <section name="authorization" overrideModeDefault="Allow" />
+        <section name="ipSecurity" overrideModeDefault="Deny" />
+        <section name="dynamicIpSecurity" overrideModeDefault="Deny" />
+        <section name="isapiCgiRestriction" allowDefinition="AppHostOnly" overrideModeDefault="Deny" />
+        <section name="requestFiltering" overrideModeDefault="Allow" />
+      </sectionGroup>
+      <section name="serverRuntime" overrideModeDefault="Deny" />
+      <section name="serverSideInclude" overrideModeDefault="Deny" />
+      <section name="staticContent" overrideModeDefault="Allow" />
+      <sectionGroup name="tracing">
+        <section name="traceFailedRequests" overrideModeDefault="Allow" />
+        <section name="traceProviderDefinitions" overrideModeDefault="Deny" />
+      </sectionGroup>
+      <section name="urlCompression" overrideModeDefault="Allow" />
+      <section name="validation" overrideModeDefault="Allow" />
+      <sectionGroup name="webdav">
+        <section name="globalSettings" overrideModeDefault="Deny" />
+        <section name="authoring" overrideModeDefault="Deny" />
+        <section name="authoringRules" overrideModeDefault="Deny" />
+      </sectionGroup>
+      <sectionGroup name="rewrite">
+        <section name="allowedServerVariables" overrideModeDefault="Deny" />
+        <section name="rules" overrideModeDefault="Allow" />
+        <section name="outboundRules" overrideModeDefault="Allow" />
+        <section name="globalRules" overrideModeDefault="Deny" allowDefinition="AppHostOnly" />
+        <section name="providers" overrideModeDefault="Allow" />
+        <section name="rewriteMaps" overrideModeDefault="Allow" />
+      </sectionGroup>
+      <section name="webSocket" overrideModeDefault="Deny" />
+      <section name="aspNetCore" overrideModeDefault="Allow" />
+    </sectionGroup>
+  </configSections>
+  <configProtectedData>
+    <providers>
+      <add name="IISWASOnlyRsaProvider" type="" description="Uses RsaCryptoServiceProvider to encrypt and decrypt" keyContainerName="iisWasKey" cspProviderName="" useMachineContainer="true" useOAEP="false" />
+      <add name="AesProvider" type="Microsoft.ApplicationHost.AesProtectedConfigurationProvider" description="Uses an AES session key to encrypt and decrypt" keyContainerName="iisConfigurationKey" cspProviderName="" useOAEP="false" useMachineContainer="true" sessionKey="AQIAAA5mAAAApAAAKmFQvWHDEETRz8l2bjZlRxIkwcqTFaCUnCLljn3Q1OkesrhEO9YyLyx4bUhsj1/DyShAv7OAFFhXlrlomaornnk5PLeyO4lIXxaiT33yOFUUgxDx4GSaygkqghVV0tO5yQ/XguUBp2juMfZyztnsNa4pLcz7ZNZQ6p4yn9hxwNs=" />
+      <add name="IISWASOnlyAesProvider" type="Microsoft.ApplicationHost.AesProtectedConfigurationProvider" description="Uses an AES session key to encrypt and decrypt" keyContainerName="iisWasKey" cspProviderName="" useOAEP="false" useMachineContainer="true" sessionKey="AQIAAA5mAAAApAAA4WoiRJ8KHwzAG8AgejPxEOO4/2Vhkolbwo/8gZeNdUDSD36m55hWv4uC9tr/MlKdnwRLL0NhT50Gccyftqz5xTZ0dg5FtvQhTw/he1NwexTKbV+I4Zrd+sZUqHZTsr7JiEr6OHGXL70qoISW5G2m9U8wKT3caPiDPNj2aAaYPLo=" />
+    </providers>
+  </configProtectedData>
+  <system.applicationHost>
+    <applicationPools>
+      <add name="Clr4IntegratedAppPool" managedRuntimeVersion="v4.0" managedPipelineMode="Integrated" CLRConfigFile="%IIS_USER_HOME%\config\aspnet.config" autoStart="true" />
+      <add name="Clr4ClassicAppPool" managedRuntimeVersion="v4.0" managedPipelineMode="Classic" CLRConfigFile="%IIS_USER_HOME%\config\aspnet.config" autoStart="true" />
+      <add name="Clr2IntegratedAppPool" managedRuntimeVersion="v2.0" managedPipelineMode="Integrated" CLRConfigFile="%IIS_USER_HOME%\config\aspnet.config" autoStart="true" />
+      <add name="Clr2ClassicAppPool" managedRuntimeVersion="v2.0" managedPipelineMode="Classic" CLRConfigFile="%IIS_USER_HOME%\config\aspnet.config" autoStart="true" />
+      <add name="UnmanagedClassicAppPool" managedRuntimeVersion="" managedPipelineMode="Classic" autoStart="true" />
+      <applicationPoolDefaults managedRuntimeLoader="v4.0">
+        <processModel />
+      </applicationPoolDefaults>
+    </applicationPools>
+    <!--
+
+          The <listenerAdapters> section defines the protocols with which the
+          Windows Process Activation Service (WAS) binds.
+
+        -->
+    <listenerAdapters>
+      <add name="http" />
+    </listenerAdapters>
+    <sites>
+      <site name="DefaultSite" id="1">
+        <application path="/" applicationPool="Clr4IntegratedAppPool">
+          <virtualDirectory path="/" physicalPath="%IIS_SITE_PATH%" />
+        </application>
+        <bindings>
+          <binding protocol="http" bindingInformation="*:50690:localhost" />
+        </bindings>
+      </site>
+      <siteDefaults>
+        <logFile logFormat="W3C" directory="%IIS_USER_HOME%\Logs" />
+        <traceFailedRequestsLogging directory="%IIS_USER_HOME%\TraceLogFiles" enabled="true" maxLogFileSizeKB="1024" />
+      </siteDefaults>
+      <applicationDefaults applicationPool="Clr4IntegratedAppPool" />
+      <virtualDirectoryDefaults allowSubDirConfig="true" />
+    </sites>
+    <webLimits />
+  </system.applicationHost>
+  <system.webServer>
+    <serverRuntime />
+    <asp scriptErrorSentToBrowser="true">
+      <cache diskTemplateCacheDirectory="%TEMP%\iisexpress\ASP Compiled Templates" />
+      <limits />
+    </asp>
+    <caching enabled="true" enableKernelCache="true"></caching>
+    <cgi />
+    <defaultDocument enabled="true">
+      <files>
+        <add value="Default.htm" />
+        <add value="Default.asp" />
+        <add value="index.htm" />
+        <add value="index.html" />
+        <add value="iisstart.htm" />
+        <add value="default.aspx" />
+      </files>
+    </defaultDocument>
+    <directoryBrowse enabled="false" />
+    <fastCgi />
+    <!--
+
+          The <globalModules> section defines all native-code modules.
+          To enable a module, specify it in the <modules> section.
+
+        -->
+    <globalModules>
+      <add name="HttpLoggingModule" image="%IIS_BIN%\loghttp.dll" />
+      <add name="UriCacheModule" image="%IIS_BIN%\cachuri.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="DynamicCompressionModule" image="%IIS_BIN%\compdyn.dll" />
+      <add name="StaticCompressionModule" image="%IIS_BIN%\compstat.dll" />
+      <add name="DefaultDocumentModule" image="%IIS_BIN%\defdoc.dll" />
+      <add name="DirectoryListingModule" image="%IIS_BIN%\dirlist.dll" />
+      <add name="ProtocolSupportModule" image="%IIS_BIN%\protsup.dll" />
+      <add name="HttpRedirectionModule" image="%IIS_BIN%\redirect.dll" />
+      <add name="ServerSideIncludeModule" image="%IIS_BIN%\iis_ssi.dll" />
+      <add name="StaticFileModule" image="%IIS_BIN%\static.dll" />
+      <add name="AnonymousAuthenticationModule" image="%IIS_BIN%\authanon.dll" />
+      <add name="CertificateMappingAuthenticationModule" image="%IIS_BIN%\authcert.dll" />
+      <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="IISCertificateMappingAuthenticationModule" image="%IIS_BIN%\authmap.dll" />
+      <add name="IpRestrictionModule" image="%IIS_BIN%\iprestr.dll" />
+      <add name="DynamicIpRestrictionModule" image="%IIS_BIN%\diprestr.dll" />
+      <add name="RequestFilteringModule" image="%IIS_BIN%\modrqflt.dll" />
+      <add name="CustomLoggingModule" image="%IIS_BIN%\logcust.dll" />
+      <add name="CustomErrorModule" image="%IIS_BIN%\custerr.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="RewriteModule" image="%IIS_BIN%\rewrite.dll" />
+      <add name="ConfigurationValidationModule" image="%IIS_BIN%\validcfg.dll" />
+      <add name="WebSocketModule" image="%IIS_BIN%\iiswsock.dll" />
+      <add name="WebMatrixSupportModule" image="%IIS_BIN%\webmatrixsup.dll" />
+      <add name="ManagedEngine" image="%windir%\Microsoft.NET\Framework\v2.0.50727\webengine.dll" preCondition="integratedMode,runtimeVersionv2.0,bitness32" />
+      <add name="ManagedEngine64" image="%windir%\Microsoft.NET\Framework64\v2.0.50727\webengine.dll" preCondition="integratedMode,runtimeVersionv2.0,bitness64" />
+      <add name="ManagedEngineV4.0_32bit" image="%windir%\Microsoft.NET\Framework\v4.0.30319\webengine4.dll" preCondition="integratedMode,runtimeVersionv4.0,bitness32" />
+      <add name="ManagedEngineV4.0_64bit" image="%windir%\Microsoft.NET\Framework64\v4.0.30319\webengine4.dll" preCondition="integratedMode,runtimeVersionv4.0,bitness64" />
+      <add name="ApplicationInitializationModule" image="%IIS_BIN%\warmup.dll" />
+      <add name="AspNetCoreModule" image="%ANCM_PATH%" />
+    </globalModules>
+    <httpCompression directory="%TEMP%\iisexpress\IIS Temporary Compressed Files">
+      <scheme name="gzip" dll="%IIS_BIN%\gzip.dll" />
+      <dynamicTypes>
+        <add mimeType="text/*" enabled="true" />
+        <add mimeType="message/*" enabled="true" />
+        <add mimeType="application/javascript" enabled="true" />
+        <add mimeType="application/atom+xml" enabled="true" />
+        <add mimeType="application/xaml+xml" enabled="true" />
+        <add mimeType="*/*" enabled="false" />
+      </dynamicTypes>
+      <staticTypes>
+        <add mimeType="text/*" enabled="true" />
+        <add mimeType="message/*" enabled="true" />
+        <add mimeType="image/svg+xml" enabled="true" />
+        <add mimeType="application/javascript" enabled="true" />
+        <add mimeType="application/atom+xml" enabled="true" />
+        <add mimeType="application/xaml+xml" enabled="true" />
+        <add mimeType="*/*" enabled="false" />
+      </staticTypes>
+    </httpCompression>
+    <httpErrors lockAttributes="allowAbsolutePathsWhenDelegated,defaultPath">
+      <error statusCode="401" prefixLanguageFilePath="%IIS_BIN%\custerr" path="401.htm" />
+      <error statusCode="403" prefixLanguageFilePath="%IIS_BIN%\custerr" path="403.htm" />
+      <error statusCode="404" prefixLanguageFilePath="%IIS_BIN%\custerr" path="404.htm" />
+      <error statusCode="405" prefixLanguageFilePath="%IIS_BIN%\custerr" path="405.htm" />
+      <error statusCode="406" prefixLanguageFilePath="%IIS_BIN%\custerr" path="406.htm" />
+      <error statusCode="412" prefixLanguageFilePath="%IIS_BIN%\custerr" path="412.htm" />
+      <error statusCode="500" prefixLanguageFilePath="%IIS_BIN%\custerr" path="500.htm" />
+      <error statusCode="501" prefixLanguageFilePath="%IIS_BIN%\custerr" path="501.htm" />
+      <error statusCode="502" prefixLanguageFilePath="%IIS_BIN%\custerr" path="502.htm" />
+    </httpErrors>
+    <httpLogging dontLog="false" />
+    <httpProtocol>
+      <customHeaders>
+        <clear />
+        <add name="X-Powered-By" value="ASP.NET" />
+      </customHeaders>
+      <redirectHeaders>
+        <clear />
+      </redirectHeaders>
+    </httpProtocol>
+    <httpRedirect enabled="false" />
+    <httpTracing></httpTracing>
+    <isapiFilters>
+      <filter name="ASP.Net_2.0.50727-64" path="%windir%\Microsoft.NET\Framework64\v2.0.50727\aspnet_filter.dll" enableCache="true" preCondition="bitness64,runtimeVersionv2.0" />
+      <filter name="ASP.Net_2.0.50727.0" path="%windir%\Microsoft.NET\Framework\v2.0.50727\aspnet_filter.dll" enableCache="true" preCondition="bitness32,runtimeVersionv2.0" />
+      <filter name="ASP.Net_2.0_for_v1.1" path="%windir%\Microsoft.NET\Framework\v2.0.50727\aspnet_filter.dll" enableCache="true" preCondition="runtimeVersionv1.1" />
+      <filter name="ASP.Net_4.0_32bit" path="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_filter.dll" enableCache="true" preCondition="bitness32,runtimeVersionv4.0" />
+      <filter name="ASP.Net_4.0_64bit" path="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_filter.dll" enableCache="true" preCondition="bitness64,runtimeVersionv4.0" />
+    </isapiFilters>
+    <odbcLogging />
+    <security>
+      <access sslFlags="None" />
+      <applicationDependencies>
+        <application name="Active Server Pages" groupId="ASP" />
+      </applicationDependencies>
+      <authentication>
+        <anonymousAuthentication enabled="true" userName="" />
+        <basicAuthentication enabled="false" />
+        <clientCertificateMappingAuthentication enabled="false" />
+        <digestAuthentication enabled="false" />
+        <iisClientCertificateMappingAuthentication enabled="false"></iisClientCertificateMappingAuthentication>
+        <windowsAuthentication enabled="false">
+          <providers>
+            <add value="Negotiate" />
+            <add value="NTLM" />
+          </providers>
+        </windowsAuthentication>
+      </authentication>
+      <authorization>
+        <add accessType="Allow" users="*" />
+      </authorization>
+      <ipSecurity allowUnlisted="true" />
+      <isapiCgiRestriction notListedIsapisAllowed="true" notListedCgisAllowed="true">
+        <add path="%windir%\Microsoft.NET\Framework64\v4.0.30319\webengine4.dll" allowed="true" groupId="ASP.NET_v4.0" description="ASP.NET_v4.0" />
+        <add path="%windir%\Microsoft.NET\Framework\v4.0.30319\webengine4.dll" allowed="true" groupId="ASP.NET_v4.0" description="ASP.NET_v4.0" />
+        <add path="%windir%\Microsoft.NET\Framework64\v2.0.50727\aspnet_isapi.dll" allowed="true" groupId="ASP.NET v2.0.50727" description="ASP.NET v2.0.50727" />
+        <add path="%windir%\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll" allowed="true" groupId="ASP.NET v2.0.50727" description="ASP.NET v2.0.50727" />
+      </isapiCgiRestriction>
+      <requestFiltering>
+        <fileExtensions allowUnlisted="true" applyToWebDAV="true">
+          <add fileExtension=".asa" allowed="false" />
+          <add fileExtension=".asax" allowed="false" />
+          <add fileExtension=".ascx" allowed="false" />
+          <add fileExtension=".master" allowed="false" />
+          <add fileExtension=".skin" allowed="false" />
+          <add fileExtension=".browser" allowed="false" />
+          <add fileExtension=".sitemap" allowed="false" />
+          <add fileExtension=".config" allowed="false" />
+          <add fileExtension=".cs" allowed="false" />
+          <add fileExtension=".csproj" allowed="false" />
+          <add fileExtension=".vb" allowed="false" />
+          <add fileExtension=".vbproj" allowed="false" />
+          <add fileExtension=".webinfo" allowed="false" />
+          <add fileExtension=".licx" allowed="false" />
+          <add fileExtension=".resx" allowed="false" />
+          <add fileExtension=".resources" allowed="false" />
+          <add fileExtension=".mdb" allowed="false" />
+          <add fileExtension=".vjsproj" allowed="false" />
+          <add fileExtension=".java" allowed="false" />
+          <add fileExtension=".jsl" allowed="false" />
+          <add fileExtension=".ldb" allowed="false" />
+          <add fileExtension=".dsdgm" allowed="false" />
+          <add fileExtension=".ssdgm" allowed="false" />
+          <add fileExtension=".lsad" allowed="false" />
+          <add fileExtension=".ssmap" allowed="false" />
+          <add fileExtension=".cd" allowed="false" />
+          <add fileExtension=".dsprototype" allowed="false" />
+          <add fileExtension=".lsaprototype" allowed="false" />
+          <add fileExtension=".sdm" allowed="false" />
+          <add fileExtension=".sdmDocument" allowed="false" />
+          <add fileExtension=".mdf" allowed="false" />
+          <add fileExtension=".ldf" allowed="false" />
+          <add fileExtension=".ad" allowed="false" />
+          <add fileExtension=".dd" allowed="false" />
+          <add fileExtension=".ldd" allowed="false" />
+          <add fileExtension=".sd" allowed="false" />
+          <add fileExtension=".adprototype" allowed="false" />
+          <add fileExtension=".lddprototype" allowed="false" />
+          <add fileExtension=".exclude" allowed="false" />
+          <add fileExtension=".refresh" allowed="false" />
+          <add fileExtension=".compiled" allowed="false" />
+          <add fileExtension=".msgx" allowed="false" />
+          <add fileExtension=".vsdisco" allowed="false" />
+          <add fileExtension=".rules" allowed="false" />
+        </fileExtensions>
+        <verbs allowUnlisted="true" applyToWebDAV="true" />
+        <hiddenSegments applyToWebDAV="true">
+          <add segment="web.config" />
+          <add segment="bin" />
+          <add segment="App_code" />
+          <add segment="App_GlobalResources" />
+          <add segment="App_LocalResources" />
+          <add segment="App_WebReferences" />
+          <add segment="App_Data" />
+          <add segment="App_Browsers" />
+        </hiddenSegments>
+      </requestFiltering>
+    </security>
+    <serverSideInclude ssiExecDisable="false" />
+    <staticContent lockAttributes="isDocFooterFileName">
+      <mimeMap fileExtension=".323" mimeType="text/h323" />
+      <mimeMap fileExtension=".3g2" mimeType="video/3gpp2" />
+      <mimeMap fileExtension=".3gp2" mimeType="video/3gpp2" />
+      <mimeMap fileExtension=".3gp" mimeType="video/3gpp" />
+      <mimeMap fileExtension=".3gpp" mimeType="video/3gpp" />
+      <mimeMap fileExtension=".aac" mimeType="audio/aac" />
+      <mimeMap fileExtension=".aaf" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".aca" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".accdb" mimeType="application/msaccess" />
+      <mimeMap fileExtension=".accde" mimeType="application/msaccess" />
+      <mimeMap fileExtension=".accdt" mimeType="application/msaccess" />
+      <mimeMap fileExtension=".acx" mimeType="application/internet-property-stream" />
+      <mimeMap fileExtension=".adt" mimeType="audio/vnd.dlna.adts" />
+      <mimeMap fileExtension=".adts" mimeType="audio/vnd.dlna.adts" />
+      <mimeMap fileExtension=".afm" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".ai" mimeType="application/postscript" />
+      <mimeMap fileExtension=".aif" mimeType="audio/x-aiff" />
+      <mimeMap fileExtension=".aifc" mimeType="audio/aiff" />
+      <mimeMap fileExtension=".aiff" mimeType="audio/aiff" />
+      <mimeMap fileExtension=".appcache" mimeType="text/cache-manifest" />
+      <mimeMap fileExtension=".application" mimeType="application/x-ms-application" />
+      <mimeMap fileExtension=".art" mimeType="image/x-jg" />
+      <mimeMap fileExtension=".asd" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".asf" mimeType="video/x-ms-asf" />
+      <mimeMap fileExtension=".asi" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".asm" mimeType="text/plain" />
+      <mimeMap fileExtension=".asr" mimeType="video/x-ms-asf" />
+      <mimeMap fileExtension=".asx" mimeType="video/x-ms-asf" />
+      <mimeMap fileExtension=".atom" mimeType="application/atom+xml" />
+      <mimeMap fileExtension=".au" mimeType="audio/basic" />
+      <mimeMap fileExtension=".avi" mimeType="video/msvideo" />
+      <mimeMap fileExtension=".axs" mimeType="application/olescript" />
+      <mimeMap fileExtension=".bas" mimeType="text/plain" />
+      <mimeMap fileExtension=".bcpio" mimeType="application/x-bcpio" />
+      <mimeMap fileExtension=".bin" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".bmp" mimeType="image/bmp" />
+      <mimeMap fileExtension=".c" mimeType="text/plain" />
+      <mimeMap fileExtension=".cab" mimeType="application/vnd.ms-cab-compressed" />
+      <mimeMap fileExtension=".calx" mimeType="application/vnd.ms-office.calx" />
+      <mimeMap fileExtension=".cat" mimeType="application/vnd.ms-pki.seccat" />
+      <mimeMap fileExtension=".cdf" mimeType="application/x-cdf" />
+      <mimeMap fileExtension=".chm" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".class" mimeType="application/x-java-applet" />
+      <mimeMap fileExtension=".clp" mimeType="application/x-msclip" />
+      <mimeMap fileExtension=".cmx" mimeType="image/x-cmx" />
+      <mimeMap fileExtension=".cnf" mimeType="text/plain" />
+      <mimeMap fileExtension=".cod" mimeType="image/cis-cod" />
+      <mimeMap fileExtension=".cpio" mimeType="application/x-cpio" />
+      <mimeMap fileExtension=".cpp" mimeType="text/plain" />
+      <mimeMap fileExtension=".crd" mimeType="application/x-mscardfile" />
+      <mimeMap fileExtension=".crl" mimeType="application/pkix-crl" />
+      <mimeMap fileExtension=".crt" mimeType="application/x-x509-ca-cert" />
+      <mimeMap fileExtension=".csh" mimeType="application/x-csh" />
+      <mimeMap fileExtension=".css" mimeType="text/css" />
+      <mimeMap fileExtension=".csv" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".cur" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".dcr" mimeType="application/x-director" />
+      <mimeMap fileExtension=".deploy" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".der" mimeType="application/x-x509-ca-cert" />
+      <mimeMap fileExtension=".dib" mimeType="image/bmp" />
+      <mimeMap fileExtension=".dir" mimeType="application/x-director" />
+      <mimeMap fileExtension=".disco" mimeType="text/xml" />
+      <mimeMap fileExtension=".dll" mimeType="application/x-msdownload" />
+      <mimeMap fileExtension=".dll.config" mimeType="text/xml" />
+      <mimeMap fileExtension=".dlm" mimeType="text/dlm" />
+      <mimeMap fileExtension=".doc" mimeType="application/msword" />
+      <mimeMap fileExtension=".docm" mimeType="application/vnd.ms-word.document.macroEnabled.12" />
+      <mimeMap fileExtension=".docx" mimeType="application/vnd.openxmlformats-officedocument.wordprocessingml.document" />
+      <mimeMap fileExtension=".dot" mimeType="application/msword" />
+      <mimeMap fileExtension=".dotm" mimeType="application/vnd.ms-word.template.macroEnabled.12" />
+      <mimeMap fileExtension=".dotx" mimeType="application/vnd.openxmlformats-officedocument.wordprocessingml.template" />
+      <mimeMap fileExtension=".dsp" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".dtd" mimeType="text/xml" />
+      <mimeMap fileExtension=".dvi" mimeType="application/x-dvi" />
+      <mimeMap fileExtension=".dvr-ms" mimeType="video/x-ms-dvr" />
+      <mimeMap fileExtension=".dwf" mimeType="drawing/x-dwf" />
+      <mimeMap fileExtension=".dwp" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".dxr" mimeType="application/x-director" />
+      <mimeMap fileExtension=".eml" mimeType="message/rfc822" />
+      <mimeMap fileExtension=".emz" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".eot" mimeType="application/vnd.ms-fontobject" />
+      <mimeMap fileExtension=".eps" mimeType="application/postscript" />
+      <mimeMap fileExtension=".etx" mimeType="text/x-setext" />
+      <mimeMap fileExtension=".evy" mimeType="application/envoy" />
+      <mimeMap fileExtension=".exe" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".exe.config" mimeType="text/xml" />
+      <mimeMap fileExtension=".fdf" mimeType="application/vnd.fdf" />
+      <mimeMap fileExtension=".fif" mimeType="application/fractals" />
+      <mimeMap fileExtension=".fla" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".flr" mimeType="x-world/x-vrml" />
+      <mimeMap fileExtension=".flv" mimeType="video/x-flv" />
+      <mimeMap fileExtension=".gif" mimeType="image/gif" />
+      <mimeMap fileExtension=".gtar" mimeType="application/x-gtar" />
+      <mimeMap fileExtension=".gz" mimeType="application/x-gzip" />
+      <mimeMap fileExtension=".h" mimeType="text/plain" />
+      <mimeMap fileExtension=".hdf" mimeType="application/x-hdf" />
+      <mimeMap fileExtension=".hdml" mimeType="text/x-hdml" />
+      <mimeMap fileExtension=".hhc" mimeType="application/x-oleobject" />
+      <mimeMap fileExtension=".hhk" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".hhp" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".hlp" mimeType="application/winhlp" />
+      <mimeMap fileExtension=".hqx" mimeType="application/mac-binhex40" />
+      <mimeMap fileExtension=".hta" mimeType="application/hta" />
+      <mimeMap fileExtension=".htc" mimeType="text/x-component" />
+      <mimeMap fileExtension=".htm" mimeType="text/html" />
+      <mimeMap fileExtension=".html" mimeType="text/html" />
+      <mimeMap fileExtension=".htt" mimeType="text/webviewhtml" />
+      <mimeMap fileExtension=".hxt" mimeType="text/html" />
+      <mimeMap fileExtension=".ico" mimeType="image/x-icon" />
+      <mimeMap fileExtension=".ics" mimeType="text/calendar" />
+      <mimeMap fileExtension=".ief" mimeType="image/ief" />
+      <mimeMap fileExtension=".iii" mimeType="application/x-iphone" />
+      <mimeMap fileExtension=".inf" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".ins" mimeType="application/x-internet-signup" />
+      <mimeMap fileExtension=".isp" mimeType="application/x-internet-signup" />
+      <mimeMap fileExtension=".IVF" mimeType="video/x-ivf" />
+      <mimeMap fileExtension=".jar" mimeType="application/java-archive" />
+      <mimeMap fileExtension=".java" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".jck" mimeType="application/liquidmotion" />
+      <mimeMap fileExtension=".jcz" mimeType="application/liquidmotion" />
+      <mimeMap fileExtension=".jfif" mimeType="image/pjpeg" />
+      <mimeMap fileExtension=".jpb" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".jpe" mimeType="image/jpeg" />
+      <mimeMap fileExtension=".jpeg" mimeType="image/jpeg" />
+      <mimeMap fileExtension=".jpg" mimeType="image/jpeg" />
+      <mimeMap fileExtension=".js" mimeType="application/javascript" />
+      <mimeMap fileExtension=".json" mimeType="application/json" />
+      <mimeMap fileExtension=".jsonld" mimeType="application/ld+json" />
+      <mimeMap fileExtension=".jsx" mimeType="text/jscript" />
+      <mimeMap fileExtension=".latex" mimeType="application/x-latex" />
+      <mimeMap fileExtension=".less" mimeType="text/css" />
+      <mimeMap fileExtension=".lit" mimeType="application/x-ms-reader" />
+      <mimeMap fileExtension=".lpk" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".lsf" mimeType="video/x-la-asf" />
+      <mimeMap fileExtension=".lsx" mimeType="video/x-la-asf" />
+      <mimeMap fileExtension=".lzh" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".m13" mimeType="application/x-msmediaview" />
+      <mimeMap fileExtension=".m14" mimeType="application/x-msmediaview" />
+      <mimeMap fileExtension=".m1v" mimeType="video/mpeg" />
+      <mimeMap fileExtension=".m2ts" mimeType="video/vnd.dlna.mpeg-tts" />
+      <mimeMap fileExtension=".m3u" mimeType="audio/x-mpegurl" />
+      <mimeMap fileExtension=".m4a" mimeType="audio/mp4" />
+      <mimeMap fileExtension=".m4v" mimeType="video/mp4" />
+      <mimeMap fileExtension=".man" mimeType="application/x-troff-man" />
+      <mimeMap fileExtension=".manifest" mimeType="application/x-ms-manifest" />
+      <mimeMap fileExtension=".map" mimeType="text/plain" />
+      <mimeMap fileExtension=".mdb" mimeType="application/x-msaccess" />
+      <mimeMap fileExtension=".mdp" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".me" mimeType="application/x-troff-me" />
+      <mimeMap fileExtension=".mht" mimeType="message/rfc822" />
+      <mimeMap fileExtension=".mhtml" mimeType="message/rfc822" />
+      <mimeMap fileExtension=".mid" mimeType="audio/mid" />
+      <mimeMap fileExtension=".midi" mimeType="audio/mid" />
+      <mimeMap fileExtension=".mix" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".mmf" mimeType="application/x-smaf" />
+      <mimeMap fileExtension=".mno" mimeType="text/xml" />
+      <mimeMap fileExtension=".mny" mimeType="application/x-msmoney" />
+      <mimeMap fileExtension=".mov" mimeType="video/quicktime" />
+      <mimeMap fileExtension=".movie" mimeType="video/x-sgi-movie" />
+      <mimeMap fileExtension=".mp2" mimeType="video/mpeg" />
+      <mimeMap fileExtension=".mp3" mimeType="audio/mpeg" />
+      <mimeMap fileExtension=".mp4" mimeType="video/mp4" />
+      <mimeMap fileExtension=".mp4v" mimeType="video/mp4" />
+      <mimeMap fileExtension=".mpa" mimeType="video/mpeg" />
+      <mimeMap fileExtension=".mpe" mimeType="video/mpeg" />
+      <mimeMap fileExtension=".mpeg" mimeType="video/mpeg" />
+      <mimeMap fileExtension=".mpg" mimeType="video/mpeg" />
+      <mimeMap fileExtension=".mpp" mimeType="application/vnd.ms-project" />
+      <mimeMap fileExtension=".mpv2" mimeType="video/mpeg" />
+      <mimeMap fileExtension=".ms" mimeType="application/x-troff-ms" />
+      <mimeMap fileExtension=".msi" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".mso" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".mvb" mimeType="application/x-msmediaview" />
+      <mimeMap fileExtension=".mvc" mimeType="application/x-miva-compiled" />
+      <mimeMap fileExtension=".nc" mimeType="application/x-netcdf" />
+      <mimeMap fileExtension=".nsc" mimeType="video/x-ms-asf" />
+      <mimeMap fileExtension=".nws" mimeType="message/rfc822" />
+      <mimeMap fileExtension=".ocx" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".oda" mimeType="application/oda" />
+      <mimeMap fileExtension=".odc" mimeType="text/x-ms-odc" />
+      <mimeMap fileExtension=".ods" mimeType="application/oleobject" />
+      <mimeMap fileExtension=".oga" mimeType="audio/ogg" />
+      <mimeMap fileExtension=".ogg" mimeType="video/ogg" />
+      <mimeMap fileExtension=".ogv" mimeType="video/ogg" />
+      <mimeMap fileExtension=".one" mimeType="application/onenote" />
+      <mimeMap fileExtension=".onea" mimeType="application/onenote" />
+      <mimeMap fileExtension=".onetoc" mimeType="application/onenote" />
+      <mimeMap fileExtension=".onetoc2" mimeType="application/onenote" />
+      <mimeMap fileExtension=".onetmp" mimeType="application/onenote" />
+      <mimeMap fileExtension=".onepkg" mimeType="application/onenote" />
+      <mimeMap fileExtension=".osdx" mimeType="application/opensearchdescription+xml" />
+      <mimeMap fileExtension=".otf" mimeType="font/otf" />
+      <mimeMap fileExtension=".p10" mimeType="application/pkcs10" />
+      <mimeMap fileExtension=".p12" mimeType="application/x-pkcs12" />
+      <mimeMap fileExtension=".p7b" mimeType="application/x-pkcs7-certificates" />
+      <mimeMap fileExtension=".p7c" mimeType="application/pkcs7-mime" />
+      <mimeMap fileExtension=".p7m" mimeType="application/pkcs7-mime" />
+      <mimeMap fileExtension=".p7r" mimeType="application/x-pkcs7-certreqresp" />
+      <mimeMap fileExtension=".p7s" mimeType="application/pkcs7-signature" />
+      <mimeMap fileExtension=".pbm" mimeType="image/x-portable-bitmap" />
+      <mimeMap fileExtension=".pcx" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".pcz" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".pdf" mimeType="application/pdf" />
+      <mimeMap fileExtension=".pfb" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".pfm" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".pfx" mimeType="application/x-pkcs12" />
+      <mimeMap fileExtension=".pgm" mimeType="image/x-portable-graymap" />
+      <mimeMap fileExtension=".pko" mimeType="application/vnd.ms-pki.pko" />
+      <mimeMap fileExtension=".pma" mimeType="application/x-perfmon" />
+      <mimeMap fileExtension=".pmc" mimeType="application/x-perfmon" />
+      <mimeMap fileExtension=".pml" mimeType="application/x-perfmon" />
+      <mimeMap fileExtension=".pmr" mimeType="application/x-perfmon" />
+      <mimeMap fileExtension=".pmw" mimeType="application/x-perfmon" />
+      <mimeMap fileExtension=".png" mimeType="image/png" />
+      <mimeMap fileExtension=".pnm" mimeType="image/x-portable-anymap" />
+      <mimeMap fileExtension=".pnz" mimeType="image/png" />
+      <mimeMap fileExtension=".pot" mimeType="application/vnd.ms-powerpoint" />
+      <mimeMap fileExtension=".potm" mimeType="application/vnd.ms-powerpoint.template.macroEnabled.12" />
+      <mimeMap fileExtension=".potx" mimeType="application/vnd.openxmlformats-officedocument.presentationml.template" />
+      <mimeMap fileExtension=".ppam" mimeType="application/vnd.ms-powerpoint.addin.macroEnabled.12" />
+      <mimeMap fileExtension=".ppm" mimeType="image/x-portable-pixmap" />
+      <mimeMap fileExtension=".pps" mimeType="application/vnd.ms-powerpoint" />
+      <mimeMap fileExtension=".ppsm" mimeType="application/vnd.ms-powerpoint.slideshow.macroEnabled.12" />
+      <mimeMap fileExtension=".ppsx" mimeType="application/vnd.openxmlformats-officedocument.presentationml.slideshow" />
+      <mimeMap fileExtension=".ppt" mimeType="application/vnd.ms-powerpoint" />
+      <mimeMap fileExtension=".pptm" mimeType="application/vnd.ms-powerpoint.presentation.macroEnabled.12" />
+      <mimeMap fileExtension=".pptx" mimeType="application/vnd.openxmlformats-officedocument.presentationml.presentation" />
+      <mimeMap fileExtension=".prf" mimeType="application/pics-rules" />
+      <mimeMap fileExtension=".prm" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".prx" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".ps" mimeType="application/postscript" />
+      <mimeMap fileExtension=".psd" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".psm" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".psp" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".pub" mimeType="application/x-mspublisher" />
+      <mimeMap fileExtension=".qt" mimeType="video/quicktime" />
+      <mimeMap fileExtension=".qtl" mimeType="application/x-quicktimeplayer" />
+      <mimeMap fileExtension=".qxd" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".ra" mimeType="audio/x-pn-realaudio" />
+      <mimeMap fileExtension=".ram" mimeType="audio/x-pn-realaudio" />
+      <mimeMap fileExtension=".rar" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".ras" mimeType="image/x-cmu-raster" />
+      <mimeMap fileExtension=".rf" mimeType="image/vnd.rn-realflash" />
+      <mimeMap fileExtension=".rgb" mimeType="image/x-rgb" />
+      <mimeMap fileExtension=".rm" mimeType="application/vnd.rn-realmedia" />
+      <mimeMap fileExtension=".rmi" mimeType="audio/mid" />
+      <mimeMap fileExtension=".roff" mimeType="application/x-troff" />
+      <mimeMap fileExtension=".rpm" mimeType="audio/x-pn-realaudio-plugin" />
+      <mimeMap fileExtension=".rtf" mimeType="application/rtf" />
+      <mimeMap fileExtension=".rtx" mimeType="text/richtext" />
+      <mimeMap fileExtension=".scd" mimeType="application/x-msschedule" />
+      <mimeMap fileExtension=".sct" mimeType="text/scriptlet" />
+      <mimeMap fileExtension=".sea" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".setpay" mimeType="application/set-payment-initiation" />
+      <mimeMap fileExtension=".setreg" mimeType="application/set-registration-initiation" />
+      <mimeMap fileExtension=".sgml" mimeType="text/sgml" />
+      <mimeMap fileExtension=".sh" mimeType="application/x-sh" />
+      <mimeMap fileExtension=".shar" mimeType="application/x-shar" />
+      <mimeMap fileExtension=".sit" mimeType="application/x-stuffit" />
+      <mimeMap fileExtension=".sldm" mimeType="application/vnd.ms-powerpoint.slide.macroEnabled.12" />
+      <mimeMap fileExtension=".sldx" mimeType="application/vnd.openxmlformats-officedocument.presentationml.slide" />
+      <mimeMap fileExtension=".smd" mimeType="audio/x-smd" />
+      <mimeMap fileExtension=".smi" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".smx" mimeType="audio/x-smd" />
+      <mimeMap fileExtension=".smz" mimeType="audio/x-smd" />
+      <mimeMap fileExtension=".snd" mimeType="audio/basic" />
+      <mimeMap fileExtension=".snp" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".spc" mimeType="application/x-pkcs7-certificates" />
+      <mimeMap fileExtension=".spl" mimeType="application/futuresplash" />
+      <mimeMap fileExtension=".spx" mimeType="audio/ogg" />
+      <mimeMap fileExtension=".src" mimeType="application/x-wais-source" />
+      <mimeMap fileExtension=".ssm" mimeType="application/streamingmedia" />
+      <mimeMap fileExtension=".sst" mimeType="application/vnd.ms-pki.certstore" />
+      <mimeMap fileExtension=".stl" mimeType="application/vnd.ms-pki.stl" />
+      <mimeMap fileExtension=".sv4cpio" mimeType="application/x-sv4cpio" />
+      <mimeMap fileExtension=".sv4crc" mimeType="application/x-sv4crc" />
+      <mimeMap fileExtension=".svg" mimeType="image/svg+xml" />
+      <mimeMap fileExtension=".svgz" mimeType="image/svg+xml" />
+      <mimeMap fileExtension=".swf" mimeType="application/x-shockwave-flash" />
+      <mimeMap fileExtension=".t" mimeType="application/x-troff" />
+      <mimeMap fileExtension=".tar" mimeType="application/x-tar" />
+      <mimeMap fileExtension=".tcl" mimeType="application/x-tcl" />
+      <mimeMap fileExtension=".tex" mimeType="application/x-tex" />
+      <mimeMap fileExtension=".texi" mimeType="application/x-texinfo" />
+      <mimeMap fileExtension=".texinfo" mimeType="application/x-texinfo" />
+      <mimeMap fileExtension=".tgz" mimeType="application/x-compressed" />
+      <mimeMap fileExtension=".thmx" mimeType="application/vnd.ms-officetheme" />
+      <mimeMap fileExtension=".thn" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".tif" mimeType="image/tiff" />
+      <mimeMap fileExtension=".tiff" mimeType="image/tiff" />
+      <mimeMap fileExtension=".toc" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".tr" mimeType="application/x-troff" />
+      <mimeMap fileExtension=".trm" mimeType="application/x-msterminal" />
+      <mimeMap fileExtension=".ts" mimeType="video/vnd.dlna.mpeg-tts" />
+      <mimeMap fileExtension=".tsv" mimeType="text/tab-separated-values" />
+      <mimeMap fileExtension=".ttf" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".tts" mimeType="video/vnd.dlna.mpeg-tts" />
+      <mimeMap fileExtension=".txt" mimeType="text/plain" />
+      <mimeMap fileExtension=".u32" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".uls" mimeType="text/iuls" />
+      <mimeMap fileExtension=".ustar" mimeType="application/x-ustar" />
+      <mimeMap fileExtension=".vbs" mimeType="text/vbscript" />
+      <mimeMap fileExtension=".vcf" mimeType="text/x-vcard" />
+      <mimeMap fileExtension=".vcs" mimeType="text/plain" />
+      <mimeMap fileExtension=".vdx" mimeType="application/vnd.ms-visio.viewer" />
+      <mimeMap fileExtension=".vml" mimeType="text/xml" />
+      <mimeMap fileExtension=".vsd" mimeType="application/vnd.visio" />
+      <mimeMap fileExtension=".vss" mimeType="application/vnd.visio" />
+      <mimeMap fileExtension=".vst" mimeType="application/vnd.visio" />
+      <mimeMap fileExtension=".vsto" mimeType="application/x-ms-vsto" />
+      <mimeMap fileExtension=".vsw" mimeType="application/vnd.visio" />
+      <mimeMap fileExtension=".vsx" mimeType="application/vnd.visio" />
+      <mimeMap fileExtension=".vtx" mimeType="application/vnd.visio" />
+      <mimeMap fileExtension=".wav" mimeType="audio/wav" />
+      <mimeMap fileExtension=".wax" mimeType="audio/x-ms-wax" />
+      <mimeMap fileExtension=".wbmp" mimeType="image/vnd.wap.wbmp" />
+      <mimeMap fileExtension=".wcm" mimeType="application/vnd.ms-works" />
+      <mimeMap fileExtension=".wdb" mimeType="application/vnd.ms-works" />
+      <mimeMap fileExtension=".webm" mimeType="video/webm" />
+      <mimeMap fileExtension=".wks" mimeType="application/vnd.ms-works" />
+      <mimeMap fileExtension=".wm" mimeType="video/x-ms-wm" />
+      <mimeMap fileExtension=".wma" mimeType="audio/x-ms-wma" />
+      <mimeMap fileExtension=".wmd" mimeType="application/x-ms-wmd" />
+      <mimeMap fileExtension=".wmf" mimeType="application/x-msmetafile" />
+      <mimeMap fileExtension=".wml" mimeType="text/vnd.wap.wml" />
+      <mimeMap fileExtension=".wmlc" mimeType="application/vnd.wap.wmlc" />
+      <mimeMap fileExtension=".wmls" mimeType="text/vnd.wap.wmlscript" />
+      <mimeMap fileExtension=".wmlsc" mimeType="application/vnd.wap.wmlscriptc" />
+      <mimeMap fileExtension=".wmp" mimeType="video/x-ms-wmp" />
+      <mimeMap fileExtension=".wmv" mimeType="video/x-ms-wmv" />
+      <mimeMap fileExtension=".wmx" mimeType="video/x-ms-wmx" />
+      <mimeMap fileExtension=".wmz" mimeType="application/x-ms-wmz" />
+      <mimeMap fileExtension=".woff" mimeType="font/x-woff" />
+      <mimeMap fileExtension=".woff2" mimeType="application/font-woff2" />
+      <mimeMap fileExtension=".wps" mimeType="application/vnd.ms-works" />
+      <mimeMap fileExtension=".wri" mimeType="application/x-mswrite" />
+      <mimeMap fileExtension=".wrl" mimeType="x-world/x-vrml" />
+      <mimeMap fileExtension=".wrz" mimeType="x-world/x-vrml" />
+      <mimeMap fileExtension=".wsdl" mimeType="text/xml" />
+      <mimeMap fileExtension=".wtv" mimeType="video/x-ms-wtv" />
+      <mimeMap fileExtension=".wvx" mimeType="video/x-ms-wvx" />
+      <mimeMap fileExtension=".x" mimeType="application/directx" />
+      <mimeMap fileExtension=".xaf" mimeType="x-world/x-vrml" />
+      <mimeMap fileExtension=".xaml" mimeType="application/xaml+xml" />
+      <mimeMap fileExtension=".xap" mimeType="application/x-silverlight-app" />
+      <mimeMap fileExtension=".xbap" mimeType="application/x-ms-xbap" />
+      <mimeMap fileExtension=".xbm" mimeType="image/x-xbitmap" />
+      <mimeMap fileExtension=".xdr" mimeType="text/plain" />
+      <mimeMap fileExtension=".xht" mimeType="application/xhtml+xml" />
+      <mimeMap fileExtension=".xhtml" mimeType="application/xhtml+xml" />
+      <mimeMap fileExtension=".xla" mimeType="application/vnd.ms-excel" />
+      <mimeMap fileExtension=".xlam" mimeType="application/vnd.ms-excel.addin.macroEnabled.12" />
+      <mimeMap fileExtension=".xlc" mimeType="application/vnd.ms-excel" />
+      <mimeMap fileExtension=".xlm" mimeType="application/vnd.ms-excel" />
+      <mimeMap fileExtension=".xls" mimeType="application/vnd.ms-excel" />
+      <mimeMap fileExtension=".xlsb" mimeType="application/vnd.ms-excel.sheet.binary.macroEnabled.12" />
+      <mimeMap fileExtension=".xlsm" mimeType="application/vnd.ms-excel.sheet.macroEnabled.12" />
+      <mimeMap fileExtension=".xlsx" mimeType="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" />
+      <mimeMap fileExtension=".xlt" mimeType="application/vnd.ms-excel" />
+      <mimeMap fileExtension=".xltm" mimeType="application/vnd.ms-excel.template.macroEnabled.12" />
+      <mimeMap fileExtension=".xltx" mimeType="application/vnd.openxmlformats-officedocument.spreadsheetml.template" />
+      <mimeMap fileExtension=".xlw" mimeType="application/vnd.ms-excel" />
+      <mimeMap fileExtension=".xml" mimeType="text/xml" />
+      <mimeMap fileExtension=".xof" mimeType="x-world/x-vrml" />
+      <mimeMap fileExtension=".xpm" mimeType="image/x-xpixmap" />
+      <mimeMap fileExtension=".xps" mimeType="application/vnd.ms-xpsdocument" />
+      <mimeMap fileExtension=".xsd" mimeType="text/xml" />
+      <mimeMap fileExtension=".xsf" mimeType="text/xml" />
+      <mimeMap fileExtension=".xsl" mimeType="text/xml" />
+      <mimeMap fileExtension=".xslt" mimeType="text/xml" />
+      <mimeMap fileExtension=".xsn" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".xtp" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".xwd" mimeType="image/x-xwindowdump" />
+      <mimeMap fileExtension=".z" mimeType="application/x-compress" />
+      <mimeMap fileExtension=".zip" mimeType="application/x-zip-compressed" />
+    </staticContent>
+    <tracing>
+      <traceProviderDefinitions>
+        <add name="WWW Server" guid="{3a2a4e84-4c21-4981-ae10-3fda0d9b0f83}">
+          <areas>
+            <clear />
+            <add name="Authentication" value="2" />
+            <add name="Security" value="4" />
+            <add name="Filter" value="8" />
+            <add name="StaticFile" value="16" />
+            <add name="CGI" value="32" />
+            <add name="Compression" value="64" />
+            <add name="Cache" value="128" />
+            <add name="RequestNotifications" value="256" />
+            <add name="Module" value="512" />
+            <add name="Rewrite" value="1024" />
+            <add name="FastCGI" value="4096" />
+            <add name="WebSocket" value="16384" />
+          </areas>
+        </add>
+        <add name="ASP" guid="{06b94d9a-b15e-456e-a4ef-37c984a2cb4b}">
+          <areas>
+            <clear />
+          </areas>
+        </add>
+        <add name="ISAPI Extension" guid="{a1c2040e-8840-4c31-ba11-9871031a19ea}">
+          <areas>
+            <clear />
+          </areas>
+        </add>
+        <add name="ASPNET" guid="{AFF081FE-0247-4275-9C4E-021F3DC1DA35}">
+          <areas>
+            <add name="Infrastructure" value="1" />
+            <add name="Module" value="2" />
+            <add name="Page" value="4" />
+            <add name="AppServices" value="8" />
+          </areas>
+        </add>
+      </traceProviderDefinitions>
+      <traceFailedRequests>
+        <add path="*">
+          <traceAreas>
+            <add provider="ASP" verbosity="Verbose" />
+            <add provider="ASPNET" areas="Infrastructure,Module,Page,AppServices" verbosity="Verbose" />
+            <add provider="ISAPI Extension" verbosity="Verbose" />
+            <add provider="WWW Server" areas="Authentication,Security,Filter,StaticFile,CGI,Compression,Cache,RequestNotifications,Module,Rewrite,WebSocket" verbosity="Verbose" />
+          </traceAreas>
+          <failureDefinitions statusCodes="200-999" />
+        </add>
+      </traceFailedRequests>
+    </tracing>
+    <urlCompression />
+    <validation />
+    <webdav>
+      <globalSettings>
+        <propertyStores>
+          <add name="webdav_simple_prop" image="%IIS_BIN%\webdav_simple_prop.dll" image32="%IIS_BIN%\webdav_simple_prop.dll" />
+        </propertyStores>
+        <lockStores>
+          <add name="webdav_simple_lock" image="%IIS_BIN%\webdav_simple_lock.dll" image32="%IIS_BIN%\webdav_simple_lock.dll" />
+        </lockStores>
+      </globalSettings>
+      <authoring>
+        <locks enabled="true" lockStore="webdav_simple_lock" />
+      </authoring>
+      <authoringRules />
+    </webdav>
+    <webSocket />
+    <applicationInitialization />
+  </system.webServer>
+  <location path="" overrideMode="Allow">
+    <system.webServer>
+      <modules>
+        <add name="IsapiFilterModule" lockItem="true" />
+        <add name="BasicAuthenticationModule" lockItem="true" />
+        <add name="IsapiModule" lockItem="true" />
+        <add name="HttpLoggingModule" lockItem="true" />
+        <!--
+                <add name="HttpCacheModule" lockItem="true" />
+-->
+        <add name="DynamicCompressionModule" lockItem="true" />
+        <add name="StaticCompressionModule" lockItem="true" />
+        <add name="DefaultDocumentModule" lockItem="true" />
+        <add name="DirectoryListingModule" lockItem="true" />
+        <add name="ProtocolSupportModule" lockItem="true" />
+        <add name="HttpRedirectionModule" lockItem="true" />
+        <add name="ServerSideIncludeModule" lockItem="true" />
+        <add name="StaticFileModule" lockItem="true" />
+        <add name="AnonymousAuthenticationModule" lockItem="true" />
+        <add name="CertificateMappingAuthenticationModule" lockItem="true" />
+        <add name="UrlAuthorizationModule" lockItem="true" />
+        <add name="WindowsAuthenticationModule" lockItem="true" />
+        <!--
+                <add name="DigestAuthenticationModule" lockItem="true" />
+-->
+        <add name="IISCertificateMappingAuthenticationModule" lockItem="true" />
+        <add name="WebMatrixSupportModule" lockItem="true" />
+        <add name="IpRestrictionModule" lockItem="true" />
+        <add name="DynamicIpRestrictionModule" lockItem="true" />
+        <add name="RequestFilteringModule" lockItem="true" />
+        <add name="CustomLoggingModule" lockItem="true" />
+        <add name="CustomErrorModule" lockItem="true" />
+        <add name="FailedRequestsTracingModule" lockItem="true" />
+        <add name="CgiModule" lockItem="true" />
+        <add name="FastCgiModule" lockItem="true" />
+        <!--                <add name="WebDAVModule" /> -->
+        <add name="RewriteModule" />
+        <add name="OutputCache" type="System.Web.Caching.OutputCacheModule" preCondition="managedHandler" />
+        <add name="Session" type="System.Web.SessionState.SessionStateModule" preCondition="managedHandler" />
+        <add name="WindowsAuthentication" type="System.Web.Security.WindowsAuthenticationModule" preCondition="managedHandler" />
+        <add name="FormsAuthentication" type="System.Web.Security.FormsAuthenticationModule" preCondition="managedHandler" />
+        <add name="DefaultAuthentication" type="System.Web.Security.DefaultAuthenticationModule" preCondition="managedHandler" />
+        <add name="RoleManager" type="System.Web.Security.RoleManagerModule" preCondition="managedHandler" />
+        <add name="UrlAuthorization" type="System.Web.Security.UrlAuthorizationModule" preCondition="managedHandler" />
+        <add name="FileAuthorization" type="System.Web.Security.FileAuthorizationModule" preCondition="managedHandler" />
+        <add name="AnonymousIdentification" type="System.Web.Security.AnonymousIdentificationModule" preCondition="managedHandler" />
+        <add name="Profile" type="System.Web.Profile.ProfileModule" preCondition="managedHandler" />
+        <add name="UrlMappingsModule" type="System.Web.UrlMappingsModule" preCondition="managedHandler" />
+        <add name="ApplicationInitializationModule" lockItem="true" />
+        <add name="WebSocketModule" lockItem="true" />
+        <add name="ServiceModel-4.0" type="System.ServiceModel.Activation.ServiceHttpModule,System.ServiceModel.Activation,Version=4.0.0.0,Culture=neutral,PublicKeyToken=31bf3856ad364e35" preCondition="managedHandler,runtimeVersionv4.0" />
+        <add name="ConfigurationValidationModule" lockItem="true" />
+        <add name="UrlRoutingModule-4.0" type="System.Web.Routing.UrlRoutingModule" preCondition="managedHandler,runtimeVersionv4.0" />
+        <add name="ScriptModule-4.0" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" preCondition="managedHandler,runtimeVersionv4.0" />
+        <add name="AspNetCoreModule" lockItem="true" />
+      </modules>
+      <handlers accessPolicy="Read, Script">
+        <!--                <add name="WebDAV" path="*" verb="PROPFIND,PROPPATCH,MKCOL,PUT,COPY,DELETE,MOVE,LOCK,UNLOCK" modules="WebDAVModule" resourceType="Unspecified" requireAccess="None" /> -->
+        <add name="AXD-ISAPI-4.0_64bit" path="*.axd" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
+        <add name="PageHandlerFactory-ISAPI-4.0_64bit" path="*.aspx" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
+        <add name="SimpleHandlerFactory-ISAPI-4.0_64bit" path="*.ashx" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
+        <add name="WebServiceHandlerFactory-ISAPI-4.0_64bit" path="*.asmx" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
+        <add name="HttpRemotingHandlerFactory-rem-ISAPI-4.0_64bit" path="*.rem" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
+        <add name="HttpRemotingHandlerFactory-soap-ISAPI-4.0_64bit" path="*.soap" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
+        <add name="svc-ISAPI-4.0_64bit" path="*.svc" verb="*" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" />
+        <add name="rules-ISAPI-4.0_64bit" path="*.rules" verb="*" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" />
+        <add name="xoml-ISAPI-4.0_64bit" path="*.xoml" verb="*" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" />
+        <add name="xamlx-ISAPI-4.0_64bit" path="*.xamlx" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" />
+        <add name="aspq-ISAPI-4.0_64bit" path="*.aspq" verb="*" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
+        <add name="cshtm-ISAPI-4.0_64bit" path="*.cshtm" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
+        <add name="cshtml-ISAPI-4.0_64bit" path="*.cshtml" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
+        <add name="vbhtm-ISAPI-4.0_64bit" path="*.vbhtm" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
+        <add name="vbhtml-ISAPI-4.0_64bit" path="*.vbhtml" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
+        <add name="AXD-ISAPI-4.0_32bit" path="*.axd" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
+        <add name="PageHandlerFactory-ISAPI-4.0_32bit" path="*.aspx" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
+        <add name="SimpleHandlerFactory-ISAPI-4.0_32bit" path="*.ashx" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
+        <add name="WebServiceHandlerFactory-ISAPI-4.0_32bit" path="*.asmx" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
+        <add name="HttpRemotingHandlerFactory-rem-ISAPI-4.0_32bit" path="*.rem" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
+        <add name="HttpRemotingHandlerFactory-soap-ISAPI-4.0_32bit" path="*.soap" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
+        <add name="svc-ISAPI-4.0_32bit" path="*.svc" verb="*" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" />
+        <add name="rules-ISAPI-4.0_32bit" path="*.rules" verb="*" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" />
+        <add name="xoml-ISAPI-4.0_32bit" path="*.xoml" verb="*" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" />
+        <add name="xamlx-ISAPI-4.0_32bit" path="*.xamlx" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" />
+        <add name="aspq-ISAPI-4.0_32bit" path="*.aspq" verb="*" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
+        <add name="cshtm-ISAPI-4.0_32bit" path="*.cshtm" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
+        <add name="cshtml-ISAPI-4.0_32bit" path="*.cshtml" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
+        <add name="vbhtm-ISAPI-4.0_32bit" path="*.vbhtm" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
+        <add name="vbhtml-ISAPI-4.0_32bit" path="*.vbhtml" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
+        <add name="TraceHandler-Integrated-4.0" path="trace.axd" verb="GET,HEAD,POST,DEBUG" type="System.Web.Handlers.TraceHandler" preCondition="integratedMode,runtimeVersionv4.0" />
+        <add name="WebAdminHandler-Integrated-4.0" path="WebAdmin.axd" verb="GET,DEBUG" type="System.Web.Handlers.WebAdminHandler" preCondition="integratedMode,runtimeVersionv4.0" />
+        <add name="AssemblyResourceLoader-Integrated-4.0" path="WebResource.axd" verb="GET,DEBUG" type="System.Web.Handlers.AssemblyResourceLoader" preCondition="integratedMode,runtimeVersionv4.0" />
+        <add name="PageHandlerFactory-Integrated-4.0" path="*.aspx" verb="GET,HEAD,POST,DEBUG" type="System.Web.UI.PageHandlerFactory" preCondition="integratedMode,runtimeVersionv4.0" />
+        <add name="SimpleHandlerFactory-Integrated-4.0" path="*.ashx" verb="GET,HEAD,POST,DEBUG" type="System.Web.UI.SimpleHandlerFactory" preCondition="integratedMode,runtimeVersionv4.0" />
+        <add name="WebServiceHandlerFactory-Integrated-4.0" path="*.asmx" verb="GET,HEAD,POST,DEBUG" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" preCondition="integratedMode,runtimeVersionv4.0" />
+        <add name="HttpRemotingHandlerFactory-rem-Integrated-4.0" path="*.rem" verb="GET,HEAD,POST,DEBUG" type="System.Runtime.Remoting.Channels.Http.HttpRemotingHandlerFactory, System.Runtime.Remoting, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" preCondition="integratedMode,runtimeVersionv4.0" />
+        <add name="HttpRemotingHandlerFactory-soap-Integrated-4.0" path="*.soap" verb="GET,HEAD,POST,DEBUG" type="System.Runtime.Remoting.Channels.Http.HttpRemotingHandlerFactory, System.Runtime.Remoting, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" preCondition="integratedMode,runtimeVersionv4.0" />
+        <add name="svc-Integrated-4.0" path="*.svc" verb="*" type="System.ServiceModel.Activation.ServiceHttpHandlerFactory, System.ServiceModel.Activation, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" preCondition="integratedMode,runtimeVersionv4.0" />
+        <add name="rules-Integrated-4.0" path="*.rules" verb="*" type="System.ServiceModel.Activation.ServiceHttpHandlerFactory, System.ServiceModel.Activation, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" preCondition="integratedMode,runtimeVersionv4.0" />
+        <add name="xoml-Integrated-4.0" path="*.xoml" verb="*" type="System.ServiceModel.Activation.ServiceHttpHandlerFactory, System.ServiceModel.Activation, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" preCondition="integratedMode,runtimeVersionv4.0" />
+        <add name="xamlx-Integrated-4.0" path="*.xamlx" verb="GET,HEAD,POST,DEBUG" type="System.Xaml.Hosting.XamlHttpHandlerFactory, System.Xaml.Hosting, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" preCondition="integratedMode,runtimeVersionv4.0" />
+        <add name="aspq-Integrated-4.0" path="*.aspq" verb="GET,HEAD,POST,DEBUG" type="System.Web.HttpForbiddenHandler" preCondition="integratedMode,runtimeVersionv4.0" />
+        <add name="cshtm-Integrated-4.0" path="*.cshtm" verb="GET,HEAD,POST,DEBUG" type="System.Web.HttpForbiddenHandler" preCondition="integratedMode,runtimeVersionv4.0" />
+        <add name="cshtml-Integrated-4.0" path="*.cshtml" verb="GET,HEAD,POST,DEBUG" type="System.Web.HttpForbiddenHandler" preCondition="integratedMode,runtimeVersionv4.0" />
+        <add name="vbhtm-Integrated-4.0" path="*.vbhtm" verb="GET,HEAD,POST,DEBUG" type="System.Web.HttpForbiddenHandler" preCondition="integratedMode,runtimeVersionv4.0" />
+        <add name="vbhtml-Integrated-4.0" path="*.vbhtml" verb="GET,HEAD,POST,DEBUG" type="System.Web.HttpForbiddenHandler" preCondition="integratedMode,runtimeVersionv4.0" />
+        <add name="ScriptHandlerFactoryAppServices-Integrated-4.0" path="*_AppService.axd" verb="*" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" preCondition="integratedMode,runtimeVersionv4.0" />
+        <add name="ScriptResourceIntegrated-4.0" path="*ScriptResource.axd" verb="GET,HEAD" type="System.Web.Handlers.ScriptResourceHandler, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" preCondition="integratedMode,runtimeVersionv4.0" />
+        <add name="ASPClassic" path="*.asp" verb="GET,HEAD,POST" modules="IsapiModule" scriptProcessor="%IIS_BIN%\asp.dll" resourceType="File" />
+        <add name="SecurityCertificate" path="*.cer" verb="GET,HEAD,POST" modules="IsapiModule" scriptProcessor="%IIS_BIN%\asp.dll" resourceType="File" />
+        <add name="ISAPI-dll" path="*.dll" verb="*" modules="IsapiModule" resourceType="File" requireAccess="Execute" allowPathInfo="true" />
+        <add name="TraceHandler-Integrated" path="trace.axd" verb="GET,HEAD,POST,DEBUG" type="System.Web.Handlers.TraceHandler" preCondition="integratedMode,runtimeVersionv2.0" />
+        <add name="WebAdminHandler-Integrated" path="WebAdmin.axd" verb="GET,DEBUG" type="System.Web.Handlers.WebAdminHandler" preCondition="integratedMode,runtimeVersionv2.0" />
+        <add name="AssemblyResourceLoader-Integrated" path="WebResource.axd" verb="GET,DEBUG" type="System.Web.Handlers.AssemblyResourceLoader" preCondition="integratedMode,runtimeVersionv2.0" />
+        <add name="PageHandlerFactory-Integrated" path="*.aspx" verb="GET,HEAD,POST,DEBUG" type="System.Web.UI.PageHandlerFactory" preCondition="integratedMode,runtimeVersionv2.0" />
+        <add name="SimpleHandlerFactory-Integrated" path="*.ashx" verb="GET,HEAD,POST,DEBUG" type="System.Web.UI.SimpleHandlerFactory" preCondition="integratedMode,runtimeVersionv2.0" />
+        <add name="WebServiceHandlerFactory-Integrated" path="*.asmx" verb="GET,HEAD,POST,DEBUG" type="System.Web.Services.Protocols.WebServiceHandlerFactory,System.Web.Services,Version=2.0.0.0,Culture=neutral,PublicKeyToken=b03f5f7f11d50a3a" preCondition="integratedMode,runtimeVersionv2.0" />
+        <add name="HttpRemotingHandlerFactory-rem-Integrated" path="*.rem" verb="GET,HEAD,POST,DEBUG" type="System.Runtime.Remoting.Channels.Http.HttpRemotingHandlerFactory,System.Runtime.Remoting,Version=2.0.0.0,Culture=neutral,PublicKeyToken=b77a5c561934e089" preCondition="integratedMode,runtimeVersionv2.0" />
+        <add name="HttpRemotingHandlerFactory-soap-Integrated" path="*.soap" verb="GET,HEAD,POST,DEBUG" type="System.Runtime.Remoting.Channels.Http.HttpRemotingHandlerFactory,System.Runtime.Remoting,Version=2.0.0.0,Culture=neutral,PublicKeyToken=b77a5c561934e089" preCondition="integratedMode,runtimeVersionv2.0" />
+        <add name="AXD-ISAPI-2.0" path="*.axd" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness32" responseBufferLimit="0" />
+        <add name="PageHandlerFactory-ISAPI-2.0" path="*.aspx" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness32" responseBufferLimit="0" />
+        <add name="SimpleHandlerFactory-ISAPI-2.0" path="*.ashx" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness32" responseBufferLimit="0" />
+        <add name="WebServiceHandlerFactory-ISAPI-2.0" path="*.asmx" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness32" responseBufferLimit="0" />
+        <add name="HttpRemotingHandlerFactory-rem-ISAPI-2.0" path="*.rem" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness32" responseBufferLimit="0" />
+        <add name="HttpRemotingHandlerFactory-soap-ISAPI-2.0" path="*.soap" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness32" responseBufferLimit="0" />
+        <add name="AXD-ISAPI-2.0-64" path="*.axd" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness64" responseBufferLimit="0" />
+        <add name="PageHandlerFactory-ISAPI-2.0-64" path="*.aspx" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness64" responseBufferLimit="0" />
+        <add name="SimpleHandlerFactory-ISAPI-2.0-64" path="*.ashx" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness64" responseBufferLimit="0" />
+        <add name="WebServiceHandlerFactory-ISAPI-2.0-64" path="*.asmx" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness64" responseBufferLimit="0" />
+        <add name="HttpRemotingHandlerFactory-rem-ISAPI-2.0-64" path="*.rem" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness64" responseBufferLimit="0" />
+        <add name="HttpRemotingHandlerFactory-soap-ISAPI-2.0-64" path="*.soap" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness64" responseBufferLimit="0" />
+        <add name="CGI-exe" path="*.exe" verb="*" modules="CgiModule" resourceType="File" requireAccess="Execute" allowPathInfo="true" />
+        <add name="SSINC-stm" path="*.stm" verb="GET,HEAD,POST" modules="ServerSideIncludeModule" resourceType="File" />
+        <add name="SSINC-shtm" path="*.shtm" verb="GET,HEAD,POST" modules="ServerSideIncludeModule" resourceType="File" />
+        <add name="SSINC-shtml" path="*.shtml" verb="GET,HEAD,POST" modules="ServerSideIncludeModule" resourceType="File" />
+        <add name="TRACEVerbHandler" path="*" verb="TRACE" modules="ProtocolSupportModule" requireAccess="None" />
+        <add name="OPTIONSVerbHandler" path="*" verb="OPTIONS" modules="ProtocolSupportModule" requireAccess="None" />
+        <add name="ExtensionlessUrl-ISAPI-4.0_32bit" path="*." verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
+        <add name="ExtensionlessUrlHandler-ISAPI-4.0_64bit" path="*." verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
+        <add name="ExtensionlessUrl-Integrated-4.0" path="*." verb="GET,HEAD,POST,DEBUG" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" responseBufferLimit="0" />
+        <add name="StaticFile" path="*" verb="*" modules="StaticFileModule,DefaultDocumentModule,DirectoryListingModule" resourceType="Either" requireAccess="Read" />
+      </handlers>
+    </system.webServer>
+  </location>
+</configuration>
diff --git a/src/IISIntegration/build/applicationhost.iis.config b/src/IISIntegration/build/applicationhost.iis.config
new file mode 100644
index 0000000000000000000000000000000000000000..1998fc2d8649a04b067fd249f59c23d9b8268849
--- /dev/null
+++ b/src/IISIntegration/build/applicationhost.iis.config
@@ -0,0 +1,730 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    IIS configuration sections.
+
+    For schema documentation, see
+    %windir%\system32\inetsrv\config\schema\IIS_schema.xml.
+
+    Please make a backup of this file before making any changes to it.
+
+-->
+
+<configuration>
+
+  <!--
+
+      The <configSections> section controls the registration of sections.
+      Section is the basic unit of deployment, locking, searching and
+      containment for configuration settings.
+
+      Every section belongs to one section group.
+      A section group is a container of logically-related sections.
+
+      Sections cannot be nested.
+      Section groups may be nested.
+
+      <section
+          name=""  [Required, Collection Key] [XML name of the section]
+          allowDefinition="Everywhere" [MachineOnly|MachineToApplication|AppHostOnly|Everywhere] [Level where it can be set]
+          overrideModeDefault="Allow"  [Allow|Deny] [Default delegation mode]
+          allowLocation="true"  [true|false] [Allowed in location tags]
+      />
+
+      The recommended way to unlock sections is by using a location tag:
+      <location path="Default Web Site" overrideMode="Allow">
+          <system.webServer>
+              <asp />
+          </system.webServer>
+      </location>
+
+  -->
+  <configSections>
+    <sectionGroup name="system.applicationHost">
+      <section name="applicationPools" allowDefinition="AppHostOnly" overrideModeDefault="Deny" />
+      <section name="configHistory" allowDefinition="AppHostOnly" overrideModeDefault="Deny" />
+      <section name="customMetadata" allowDefinition="AppHostOnly" overrideModeDefault="Deny" />
+      <section name="listenerAdapters" allowDefinition="AppHostOnly" overrideModeDefault="Deny" />
+      <section name="log" allowDefinition="AppHostOnly" overrideModeDefault="Deny" />
+      <section name="serviceAutoStartProviders" allowDefinition="AppHostOnly" overrideModeDefault="Deny" />
+      <section name="sites" overrideModeDefault="Allow" />
+      <section name="webLimits" allowDefinition="AppHostOnly" overrideModeDefault="Deny" />
+    </sectionGroup>
+
+    <sectionGroup name="system.webServer">
+      <section name="asp" overrideModeDefault="Deny" />
+      <section name="caching" overrideModeDefault="Allow" />
+      <section name="aspNetCore" overrideModeDefault="Allow" />
+      <section name="cgi" overrideModeDefault="Deny" />
+      <section name="defaultDocument" overrideModeDefault="Allow" />
+      <section name="directoryBrowse" overrideModeDefault="Allow" />
+      <section name="fastCgi" allowDefinition="AppHostOnly" overrideModeDefault="Deny" />
+      <section name="globalModules" overrideModeDefault="Allow" />
+      <section name="handlers" allowDefinition="MachineToApplication" overrideModeDefault="Allow" />
+      <section name="httpCompression" overrideModeDefault="Allow" />
+      <section name="httpErrors" overrideModeDefault="Allow" />
+      <section name="httpLogging" overrideModeDefault="Deny" />
+      <section name="httpProtocol" overrideModeDefault="Allow" />
+      <section name="httpRedirect" overrideModeDefault="Allow" />
+      <section name="httpTracing" overrideModeDefault="Deny" />
+      <section name="isapiFilters" allowDefinition="MachineToApplication" overrideModeDefault="Deny" />
+      <section name="modules" allowDefinition="MachineToApplication" overrideModeDefault="Deny" />
+      <section name="applicationInitialization" allowDefinition="MachineToApplication" overrideModeDefault="Allow" />
+      <section name="odbcLogging" overrideModeDefault="Deny" />
+      <sectionGroup name="security">
+        <section name="access" overrideModeDefault="Deny" />
+        <section name="applicationDependencies" overrideModeDefault="Deny" />
+        <sectionGroup name="authentication">
+          <section name="anonymousAuthentication" overrideModeDefault="Deny" />
+          <section name="basicAuthentication" overrideModeDefault="Deny" />
+          <section name="clientCertificateMappingAuthentication" overrideModeDefault="Deny" />
+          <section name="digestAuthentication" overrideModeDefault="Deny" />
+          <section name="iisClientCertificateMappingAuthentication" overrideModeDefault="Deny" />
+          <section name="windowsAuthentication" overrideModeDefault="Deny" />
+        </sectionGroup>
+        <section name="authorization" overrideModeDefault="Allow" />
+        <section name="ipSecurity" overrideModeDefault="Deny" />
+        <section name="dynamicIpSecurity" overrideModeDefault="Deny" />
+        <section name="isapiCgiRestriction" allowDefinition="AppHostOnly" overrideModeDefault="Deny" />
+        <section name="requestFiltering" overrideModeDefault="Allow" />
+      </sectionGroup>
+      <section name="serverRuntime" overrideModeDefault="Deny" />
+      <section name="serverSideInclude" overrideModeDefault="Deny" />
+      <section name="staticContent" overrideModeDefault="Allow" />
+      <sectionGroup name="tracing">
+        <section name="traceFailedRequests" overrideModeDefault="Allow" />
+        <section name="traceProviderDefinitions" overrideModeDefault="Deny" />
+      </sectionGroup>
+      <section name="urlCompression" overrideModeDefault="Allow" />
+      <section name="validation" overrideModeDefault="Allow" />
+      <sectionGroup name="webdav">
+        <section name="globalSettings" overrideModeDefault="Deny" />
+        <section name="authoring" overrideModeDefault="Deny" />
+        <section name="authoringRules" overrideModeDefault="Deny" />
+      </sectionGroup>
+      <section name="webSocket" overrideModeDefault="Deny" />
+    </sectionGroup>
+    <sectionGroup name="system.ftpServer">
+      <section name="log" overrideModeDefault="Deny" allowDefinition="AppHostOnly" />
+      <section name="firewallSupport" overrideModeDefault="Deny" allowDefinition="AppHostOnly" />
+      <section name="caching" overrideModeDefault="Deny" allowDefinition="AppHostOnly" />
+      <section name="providerDefinitions" overrideModeDefault="Deny" />
+      <sectionGroup name="security">
+        <section name="ipSecurity" overrideModeDefault="Deny" />
+        <section name="requestFiltering" overrideModeDefault="Deny" />
+        <section name="authorization" overrideModeDefault="Deny" />
+        <section name="authentication" overrideModeDefault="Deny" />
+      </sectionGroup>
+      <section name="serverRuntime" overrideModeDefault="Deny" allowDefinition="AppHostOnly" />
+    </sectionGroup>
+  </configSections>
+
+  <configProtectedData>
+    <providers>
+      <add name="IISWASOnlyRsaProvider" type="" description="Uses RsaCryptoServiceProvider to encrypt and decrypt" keyContainerName="iisWasKey" cspProviderName="" useMachineContainer="true" useOAEP="false" />
+      <add name="IISCngProvider" type="Microsoft.ApplicationHost.CngProtectedConfigurationProvider" description="Uses Win32 Crypto CNG to encrypt and decrypt" keyContainerName="iisCngConfigurationKey" useMachineContainer="true" />
+      <add name="IISWASOnlyCngProvider" type="Microsoft.ApplicationHost.CngProtectedConfigurationProvider" description="(WAS Only) Uses Win32 Crypto CNG to encrypt and decrypt" keyContainerName="iisCngWasKey" useMachineContainer="true" />
+      <add name="AesProvider" type="Microsoft.ApplicationHost.AesProtectedConfigurationProvider" description="Uses an AES session key to encrypt and decrypt" keyContainerName="iisConfigurationKey" cspProviderName="" useOAEP="false" useMachineContainer="true" sessionKey="AQIAAA5mAAAApAAA761WPlg/O0KIRimaL0QzaMUtBeu0wvDNy2z7w2Bt6jKMn2vd1rsTm2CkiLB9XfTVBXkd9QnX0PVkzaubmf2eJ1ZoovreHp367sKvP0ycL3wToFfOkbzmCGcyR5K97x7zqgokJ2nZ4+upP6eB5YGQbVoOvYkO124LwZdPurAepHlBF6BnLw6iOmzqEISQhjb2TnlHuI54wGy7PEqog8Yw5KWAHT1v5llXAIi3BUT4J0ALPGxzZeY6sfuupb5UWjgBmHRGxRC7Q67tY9ZrjSHynIazcroAreBHJHD7V4Ie4I+8y32Vupej3HhN0WPZIVgIERN6XH7/88IQbO7oGdRKMw==" />
+      <add name="IISWASOnlyAesProvider" type="Microsoft.ApplicationHost.AesProtectedConfigurationProvider" description="Uses an AES session key to encrypt and decrypt" keyContainerName="iisWasKey" cspProviderName="" useOAEP="false" useMachineContainer="true" sessionKey="AQIAAA5mAAAApAAAyfG50d0OvPU6AmHdvHBKc9XoUZKF24/cmB4ZU2ol04N+Hj++IytaIbPR6hRXwZGGXqRnFunrCtHbNvjXinU3esyYJ2ij+HZCzAfUspWbfK+tyyGKQ+E2GY65mKqwfXu2BcZBO5At/LxOAwDqVwl9iFsMhtqfAoe/SxQXh1a1T3oSRYUBfsr6jvfWeH0lI8AznEG2KdPS8Smaf8XtF51R3Z0JbbWfIa+WmvmfUkHgcFHHqlDd2LOuB3cWNJhSR9EX2h4t1v3AvGqHmYs5bq63/p5I3aW6jQ4r3HfNWm1TGEvXgeNqOZHZvGSMxKN1TE0AAWd17WTP4tn6icEblR4YGw==" />
+    </providers>
+  </configProtectedData>
+
+  <system.applicationHost>
+
+    <applicationPools>
+      <add name="DefaultAppPool" />
+      <applicationPoolDefaults managedRuntimeVersion="v4.0">
+        <processModel identityType="ApplicationPoolIdentity" />
+      </applicationPoolDefaults>
+    </applicationPools>
+
+    <!--
+
+      The <customMetadata> section is used internally by the Admin Base Objects
+      (ABO) Compatibility component. Please do not modify its content.
+
+    -->
+    <customMetadata />
+
+    <!--
+
+      The <listenerAdapters> section defines the protocols with which the
+      Windows Process Activation Service (WAS) binds.
+
+    -->
+    <listenerAdapters>
+      <add name="http" />
+    </listenerAdapters>
+
+    <log>
+      <centralBinaryLogFile enabled="true" directory="%SystemDrive%\inetpub\logs\LogFiles" />
+      <centralW3CLogFile enabled="true" directory="%SystemDrive%\inetpub\logs\LogFiles" />
+    </log>
+
+    <sites>
+      <site name="Default Web Site" id="1">
+        <application path="/">
+          <virtualDirectory path="/" physicalPath="%IIS_SITE_PATH%" />
+        </application>
+        <bindings>
+          <binding protocol="http" bindingInformation="*:50690:localhost" />
+        </bindings>
+      </site>
+      <siteDefaults>
+        <logFile logFormat="W3C" directory="%SystemDrive%\inetpub\logs\LogFiles" />
+        <traceFailedRequestsLogging directory="%SystemDrive%\inetpub\logs\FailedReqLogFiles" />
+      </siteDefaults>
+      <applicationDefaults applicationPool="DefaultAppPool" />
+      <virtualDirectoryDefaults allowSubDirConfig="true" />
+    </sites>
+
+    <webLimits />
+
+  </system.applicationHost>
+
+  <system.webServer>
+
+    <asp />
+
+    <caching enabled="true" enableKernelCache="true">
+    </caching>
+
+    <cgi />
+
+    <defaultDocument enabled="true">
+      <files>
+        <add value="Default.htm" />
+        <add value="Default.asp" />
+        <add value="index.htm" />
+        <add value="index.html" />
+        <add value="iisstart.htm" />
+      </files>
+    </defaultDocument>
+
+    <directoryBrowse enabled="false" />
+
+    <fastCgi />
+
+    <!--
+
+      The <globalModules> section defines all native-code modules.
+      To enable a module, specify it in the <modules> section.
+
+    -->
+    <globalModules>
+      <add name="HttpLoggingModule" image="%windir%\System32\inetsrv\loghttp.dll" />
+      <add name="UriCacheModule" image="%windir%\System32\inetsrv\cachuri.dll" />
+      <add name="FileCacheModule" image="%windir%\System32\inetsrv\cachfile.dll" />
+      <add name="TokenCacheModule" image="%windir%\System32\inetsrv\cachtokn.dll" />
+      <add name="HttpCacheModule" image="%windir%\System32\inetsrv\cachhttp.dll" />
+      <add name="StaticCompressionModule" image="%windir%\System32\inetsrv\compstat.dll" />
+      <add name="DefaultDocumentModule" image="%windir%\System32\inetsrv\defdoc.dll" />
+      <add name="DirectoryListingModule" image="%windir%\System32\inetsrv\dirlist.dll" />
+      <add name="ProtocolSupportModule" image="%windir%\System32\inetsrv\protsup.dll" />
+      <add name="StaticFileModule" image="%windir%\System32\inetsrv\static.dll" />
+      <add name="AnonymousAuthenticationModule" image="%windir%\System32\inetsrv\authanon.dll" />
+      <add name="RequestFilteringModule" image="%windir%\System32\inetsrv\modrqflt.dll" />
+      <add name="CustomErrorModule" image="%windir%\System32\inetsrv\custerr.dll" />
+      <add name="AspNetCoreModule" image="%ANCM_PATH%" />
+    </globalModules>
+
+    <handlers accessPolicy="Read, Script">
+      <add name="TRACEVerbHandler" path="*" verb="TRACE" modules="ProtocolSupportModule" requireAccess="None" />
+      <add name="OPTIONSVerbHandler" path="*" verb="OPTIONS" modules="ProtocolSupportModule" requireAccess="None" />
+      <add name="StaticFile" path="*" verb="*" modules="StaticFileModule,DefaultDocumentModule,DirectoryListingModule" resourceType="Either" requireAccess="Read" />
+    </handlers>
+
+    <httpCompression directory="%SystemDrive%\inetpub\temp\IIS Temporary Compressed Files">
+      <scheme name="gzip" dll="%Windir%\system32\inetsrv\gzip.dll" />
+      <staticTypes>
+        <add mimeType="text/*" enabled="true" />
+        <add mimeType="message/*" enabled="true" />
+        <add mimeType="application/javascript" enabled="true" />
+        <add mimeType="application/atom+xml" enabled="true" />
+        <add mimeType="application/xaml+xml" enabled="true" />
+        <add mimeType="image/svg+xml" enabled="true" />
+        <add mimeType="*/*" enabled="false" />
+      </staticTypes>
+    </httpCompression>
+
+    <httpErrors lockAttributes="allowAbsolutePathsWhenDelegated,defaultPath">
+      <error statusCode="401" prefixLanguageFilePath="%SystemDrive%\inetpub\custerr" path="401.htm" />
+      <error statusCode="403" prefixLanguageFilePath="%SystemDrive%\inetpub\custerr" path="403.htm" />
+      <error statusCode="404" prefixLanguageFilePath="%SystemDrive%\inetpub\custerr" path="404.htm" />
+      <error statusCode="405" prefixLanguageFilePath="%SystemDrive%\inetpub\custerr" path="405.htm" />
+      <error statusCode="406" prefixLanguageFilePath="%SystemDrive%\inetpub\custerr" path="406.htm" />
+      <error statusCode="412" prefixLanguageFilePath="%SystemDrive%\inetpub\custerr" path="412.htm" />
+      <error statusCode="500" prefixLanguageFilePath="%SystemDrive%\inetpub\custerr" path="500.htm" />
+      <error statusCode="501" prefixLanguageFilePath="%SystemDrive%\inetpub\custerr" path="501.htm" />
+      <error statusCode="502" prefixLanguageFilePath="%SystemDrive%\inetpub\custerr" path="502.htm" />
+    </httpErrors>
+
+    <httpLogging dontLog="false" />
+
+    <httpProtocol>
+      <customHeaders>
+        <clear />
+      </customHeaders>
+      <redirectHeaders>
+        <clear />
+      </redirectHeaders>
+    </httpProtocol>
+
+    <httpRedirect />
+
+    <httpTracing />
+
+    <isapiFilters />
+
+    <modules>
+      <add name="HttpLoggingModule" lockItem="true" />
+      <add name="HttpCacheModule" lockItem="true" />
+      <add name="StaticCompressionModule" lockItem="true" />
+      <add name="DefaultDocumentModule" lockItem="true" />
+      <add name="DirectoryListingModule" lockItem="true" />
+      <add name="ProtocolSupportModule" lockItem="true" />
+      <add name="StaticFileModule" lockItem="true" />
+      <add name="AnonymousAuthenticationModule" lockItem="true" />
+      <add name="RequestFilteringModule" lockItem="true" />
+      <add name="CustomErrorModule" lockItem="true" />
+      <add name="AspNetCoreModule" lockItem="true" />
+    </modules>
+
+    <odbcLogging />
+
+    <security>
+
+      <access sslFlags="None" />
+
+      <applicationDependencies />
+
+      <authentication>
+
+        <anonymousAuthentication enabled="true" userName="IUSR" />
+
+        <basicAuthentication />
+
+        <clientCertificateMappingAuthentication />
+
+        <digestAuthentication />
+
+        <iisClientCertificateMappingAuthentication />
+
+        <windowsAuthentication />
+
+      </authentication>
+
+      <authorization />
+
+      <ipSecurity />
+
+      <isapiCgiRestriction />
+
+      <requestFiltering>
+        <fileExtensions allowUnlisted="true" applyToWebDAV="true" />
+        <verbs allowUnlisted="true" applyToWebDAV="true" />
+        <hiddenSegments applyToWebDAV="true">
+          <add segment="web.config" />
+        </hiddenSegments>
+      </requestFiltering>
+
+    </security>
+
+    <serverRuntime />
+
+    <serverSideInclude />
+
+    <staticContent lockAttributes="isDocFooterFileName">
+      <mimeMap fileExtension=".323" mimeType="text/h323" />
+      <mimeMap fileExtension=".3g2" mimeType="video/3gpp2" />
+      <mimeMap fileExtension=".3gp2" mimeType="video/3gpp2" />
+      <mimeMap fileExtension=".3gp" mimeType="video/3gpp" />
+      <mimeMap fileExtension=".3gpp" mimeType="video/3gpp" />
+      <mimeMap fileExtension=".aaf" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".aac" mimeType="audio/aac" />
+      <mimeMap fileExtension=".aca" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".accdb" mimeType="application/msaccess" />
+      <mimeMap fileExtension=".accde" mimeType="application/msaccess" />
+      <mimeMap fileExtension=".accdt" mimeType="application/msaccess" />
+      <mimeMap fileExtension=".acx" mimeType="application/internet-property-stream" />
+      <mimeMap fileExtension=".adt" mimeType="audio/vnd.dlna.adts" />
+      <mimeMap fileExtension=".adts" mimeType="audio/vnd.dlna.adts" />
+      <mimeMap fileExtension=".afm" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".ai" mimeType="application/postscript" />
+      <mimeMap fileExtension=".aif" mimeType="audio/x-aiff" />
+      <mimeMap fileExtension=".aifc" mimeType="audio/aiff" />
+      <mimeMap fileExtension=".aiff" mimeType="audio/aiff" />
+      <mimeMap fileExtension=".appcache" mimeType="text/cache-manifest" />
+      <mimeMap fileExtension=".application" mimeType="application/x-ms-application" />
+      <mimeMap fileExtension=".art" mimeType="image/x-jg" />
+      <mimeMap fileExtension=".asd" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".asf" mimeType="video/x-ms-asf" />
+      <mimeMap fileExtension=".asi" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".asm" mimeType="text/plain" />
+      <mimeMap fileExtension=".asr" mimeType="video/x-ms-asf" />
+      <mimeMap fileExtension=".asx" mimeType="video/x-ms-asf" />
+      <mimeMap fileExtension=".atom" mimeType="application/atom+xml" />
+      <mimeMap fileExtension=".au" mimeType="audio/basic" />
+      <mimeMap fileExtension=".avi" mimeType="video/avi" />
+      <mimeMap fileExtension=".axs" mimeType="application/olescript" />
+      <mimeMap fileExtension=".bas" mimeType="text/plain" />
+      <mimeMap fileExtension=".bcpio" mimeType="application/x-bcpio" />
+      <mimeMap fileExtension=".bin" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".bmp" mimeType="image/bmp" />
+      <mimeMap fileExtension=".c" mimeType="text/plain" />
+      <mimeMap fileExtension=".cab" mimeType="application/vnd.ms-cab-compressed" />
+      <mimeMap fileExtension=".calx" mimeType="application/vnd.ms-office.calx" />
+      <mimeMap fileExtension=".cat" mimeType="application/vnd.ms-pki.seccat" />
+      <mimeMap fileExtension=".cdf" mimeType="application/x-cdf" />
+      <mimeMap fileExtension=".chm" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".class" mimeType="application/x-java-applet" />
+      <mimeMap fileExtension=".clp" mimeType="application/x-msclip" />
+      <mimeMap fileExtension=".cmx" mimeType="image/x-cmx" />
+      <mimeMap fileExtension=".cnf" mimeType="text/plain" />
+      <mimeMap fileExtension=".cod" mimeType="image/cis-cod" />
+      <mimeMap fileExtension=".cpio" mimeType="application/x-cpio" />
+      <mimeMap fileExtension=".cpp" mimeType="text/plain" />
+      <mimeMap fileExtension=".crd" mimeType="application/x-mscardfile" />
+      <mimeMap fileExtension=".crl" mimeType="application/pkix-crl" />
+      <mimeMap fileExtension=".crt" mimeType="application/x-x509-ca-cert" />
+      <mimeMap fileExtension=".csh" mimeType="application/x-csh" />
+      <mimeMap fileExtension=".css" mimeType="text/css" />
+      <mimeMap fileExtension=".csv" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".cur" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".dcr" mimeType="application/x-director" />
+      <mimeMap fileExtension=".deploy" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".der" mimeType="application/x-x509-ca-cert" />
+      <mimeMap fileExtension=".dib" mimeType="image/bmp" />
+      <mimeMap fileExtension=".dir" mimeType="application/x-director" />
+      <mimeMap fileExtension=".disco" mimeType="text/xml" />
+      <mimeMap fileExtension=".dll" mimeType="application/x-msdownload" />
+      <mimeMap fileExtension=".dll.config" mimeType="text/xml" />
+      <mimeMap fileExtension=".dlm" mimeType="text/dlm" />
+      <mimeMap fileExtension=".doc" mimeType="application/msword" />
+      <mimeMap fileExtension=".docm" mimeType="application/vnd.ms-word.document.macroEnabled.12" />
+      <mimeMap fileExtension=".docx" mimeType="application/vnd.openxmlformats-officedocument.wordprocessingml.document" />
+      <mimeMap fileExtension=".dot" mimeType="application/msword" />
+      <mimeMap fileExtension=".dotm" mimeType="application/vnd.ms-word.template.macroEnabled.12" />
+      <mimeMap fileExtension=".dotx" mimeType="application/vnd.openxmlformats-officedocument.wordprocessingml.template" />
+      <mimeMap fileExtension=".dsp" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".dtd" mimeType="text/xml" />
+      <mimeMap fileExtension=".dvi" mimeType="application/x-dvi" />
+      <mimeMap fileExtension=".dvr-ms" mimeType="video/x-ms-dvr" />
+      <mimeMap fileExtension=".dwf" mimeType="drawing/x-dwf" />
+      <mimeMap fileExtension=".dwp" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".dxr" mimeType="application/x-director" />
+      <mimeMap fileExtension=".eml" mimeType="message/rfc822" />
+      <mimeMap fileExtension=".emz" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".eot" mimeType="application/vnd.ms-fontobject" />
+      <mimeMap fileExtension=".eps" mimeType="application/postscript" />
+      <mimeMap fileExtension=".esd" mimeType="application/vnd.ms-cab-compressed" />
+      <mimeMap fileExtension=".etx" mimeType="text/x-setext" />
+      <mimeMap fileExtension=".evy" mimeType="application/envoy" />
+      <mimeMap fileExtension=".exe" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".exe.config" mimeType="text/xml" />
+      <mimeMap fileExtension=".fdf" mimeType="application/vnd.fdf" />
+      <mimeMap fileExtension=".fif" mimeType="application/fractals" />
+      <mimeMap fileExtension=".fla" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".flr" mimeType="x-world/x-vrml" />
+      <mimeMap fileExtension=".flv" mimeType="video/x-flv" />
+      <mimeMap fileExtension=".gif" mimeType="image/gif" />
+      <mimeMap fileExtension=".gtar" mimeType="application/x-gtar" />
+      <mimeMap fileExtension=".gz" mimeType="application/x-gzip" />
+      <mimeMap fileExtension=".h" mimeType="text/plain" />
+      <mimeMap fileExtension=".hdf" mimeType="application/x-hdf" />
+      <mimeMap fileExtension=".hdml" mimeType="text/x-hdml" />
+      <mimeMap fileExtension=".hhc" mimeType="application/x-oleobject" />
+      <mimeMap fileExtension=".hhk" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".hhp" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".hlp" mimeType="application/winhlp" />
+      <mimeMap fileExtension=".hqx" mimeType="application/mac-binhex40" />
+      <mimeMap fileExtension=".hta" mimeType="application/hta" />
+      <mimeMap fileExtension=".htc" mimeType="text/x-component" />
+      <mimeMap fileExtension=".htm" mimeType="text/html" />
+      <mimeMap fileExtension=".html" mimeType="text/html" />
+      <mimeMap fileExtension=".htt" mimeType="text/webviewhtml" />
+      <mimeMap fileExtension=".hxt" mimeType="text/html" />
+      <mimeMap fileExtension=".ico" mimeType="image/x-icon" />
+      <mimeMap fileExtension=".ics" mimeType="text/calendar" />
+      <mimeMap fileExtension=".ief" mimeType="image/ief" />
+      <mimeMap fileExtension=".iii" mimeType="application/x-iphone" />
+      <mimeMap fileExtension=".inf" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".ins" mimeType="application/x-internet-signup" />
+      <mimeMap fileExtension=".isp" mimeType="application/x-internet-signup" />
+      <mimeMap fileExtension=".IVF" mimeType="video/x-ivf" />
+      <mimeMap fileExtension=".jar" mimeType="application/java-archive" />
+      <mimeMap fileExtension=".java" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".jck" mimeType="application/liquidmotion" />
+      <mimeMap fileExtension=".jcz" mimeType="application/liquidmotion" />
+      <mimeMap fileExtension=".jfif" mimeType="image/pjpeg" />
+      <mimeMap fileExtension=".jpb" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".jpe" mimeType="image/jpeg" />
+      <mimeMap fileExtension=".jpeg" mimeType="image/jpeg" />
+      <mimeMap fileExtension=".jpg" mimeType="image/jpeg" />
+      <mimeMap fileExtension=".js" mimeType="application/javascript" />
+      <mimeMap fileExtension=".json" mimeType="application/json" />
+      <mimeMap fileExtension=".jsonld" mimeType="application/ld+json" />
+      <mimeMap fileExtension=".jsx" mimeType="text/jscript" />
+      <mimeMap fileExtension=".latex" mimeType="application/x-latex" />
+      <mimeMap fileExtension=".less" mimeType="text/css" />
+      <mimeMap fileExtension=".lit" mimeType="application/x-ms-reader" />
+      <mimeMap fileExtension=".lpk" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".lsf" mimeType="video/x-la-asf" />
+      <mimeMap fileExtension=".lsx" mimeType="video/x-la-asf" />
+      <mimeMap fileExtension=".lzh" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".m13" mimeType="application/x-msmediaview" />
+      <mimeMap fileExtension=".m14" mimeType="application/x-msmediaview" />
+      <mimeMap fileExtension=".m1v" mimeType="video/mpeg" />
+      <mimeMap fileExtension=".m2ts" mimeType="video/vnd.dlna.mpeg-tts" />
+      <mimeMap fileExtension=".m3u" mimeType="audio/x-mpegurl" />
+      <mimeMap fileExtension=".m4a" mimeType="audio/mp4" />
+      <mimeMap fileExtension=".m4v" mimeType="video/mp4" />
+      <mimeMap fileExtension=".man" mimeType="application/x-troff-man" />
+      <mimeMap fileExtension=".manifest" mimeType="application/x-ms-manifest" />
+      <mimeMap fileExtension=".map" mimeType="text/plain" />
+      <mimeMap fileExtension=".mdb" mimeType="application/x-msaccess" />
+      <mimeMap fileExtension=".mdp" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".me" mimeType="application/x-troff-me" />
+      <mimeMap fileExtension=".mht" mimeType="message/rfc822" />
+      <mimeMap fileExtension=".mhtml" mimeType="message/rfc822" />
+      <mimeMap fileExtension=".mid" mimeType="audio/mid" />
+      <mimeMap fileExtension=".midi" mimeType="audio/mid" />
+      <mimeMap fileExtension=".mix" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".mmf" mimeType="application/x-smaf" />
+      <mimeMap fileExtension=".mno" mimeType="text/xml" />
+      <mimeMap fileExtension=".mny" mimeType="application/x-msmoney" />
+      <mimeMap fileExtension=".mov" mimeType="video/quicktime" />
+      <mimeMap fileExtension=".movie" mimeType="video/x-sgi-movie" />
+      <mimeMap fileExtension=".mp2" mimeType="video/mpeg" />
+      <mimeMap fileExtension=".mp3" mimeType="audio/mpeg" />
+      <mimeMap fileExtension=".mp4" mimeType="video/mp4" />
+      <mimeMap fileExtension=".mp4v" mimeType="video/mp4" />
+      <mimeMap fileExtension=".mpa" mimeType="video/mpeg" />
+      <mimeMap fileExtension=".mpe" mimeType="video/mpeg" />
+      <mimeMap fileExtension=".mpeg" mimeType="video/mpeg" />
+      <mimeMap fileExtension=".mpg" mimeType="video/mpeg" />
+      <mimeMap fileExtension=".mpp" mimeType="application/vnd.ms-project" />
+      <mimeMap fileExtension=".mpv2" mimeType="video/mpeg" />
+      <mimeMap fileExtension=".ms" mimeType="application/x-troff-ms" />
+      <mimeMap fileExtension=".msi" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".mso" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".mvb" mimeType="application/x-msmediaview" />
+      <mimeMap fileExtension=".mvc" mimeType="application/x-miva-compiled" />
+      <mimeMap fileExtension=".nc" mimeType="application/x-netcdf" />
+      <mimeMap fileExtension=".nsc" mimeType="video/x-ms-asf" />
+      <mimeMap fileExtension=".nws" mimeType="message/rfc822" />
+      <mimeMap fileExtension=".ocx" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".oda" mimeType="application/oda" />
+      <mimeMap fileExtension=".odc" mimeType="text/x-ms-odc" />
+      <mimeMap fileExtension=".ods" mimeType="application/oleobject" />
+      <mimeMap fileExtension=".oga" mimeType="audio/ogg" />
+      <mimeMap fileExtension=".ogg" mimeType="video/ogg" />
+      <mimeMap fileExtension=".ogv" mimeType="video/ogg" />
+      <mimeMap fileExtension=".one" mimeType="application/onenote" />
+      <mimeMap fileExtension=".onea" mimeType="application/onenote" />
+      <mimeMap fileExtension=".onetoc" mimeType="application/onenote" />
+      <mimeMap fileExtension=".onetoc2" mimeType="application/onenote" />
+      <mimeMap fileExtension=".onetmp" mimeType="application/onenote" />
+      <mimeMap fileExtension=".onepkg" mimeType="application/onenote" />
+      <mimeMap fileExtension=".osdx" mimeType="application/opensearchdescription+xml" />
+      <mimeMap fileExtension=".otf" mimeType="font/otf" />
+      <mimeMap fileExtension=".p10" mimeType="application/pkcs10" />
+      <mimeMap fileExtension=".p12" mimeType="application/x-pkcs12" />
+      <mimeMap fileExtension=".p7b" mimeType="application/x-pkcs7-certificates" />
+      <mimeMap fileExtension=".p7c" mimeType="application/pkcs7-mime" />
+      <mimeMap fileExtension=".p7m" mimeType="application/pkcs7-mime" />
+      <mimeMap fileExtension=".p7r" mimeType="application/x-pkcs7-certreqresp" />
+      <mimeMap fileExtension=".p7s" mimeType="application/pkcs7-signature" />
+      <mimeMap fileExtension=".pbm" mimeType="image/x-portable-bitmap" />
+      <mimeMap fileExtension=".pcx" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".pcz" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".pdf" mimeType="application/pdf" />
+      <mimeMap fileExtension=".pfb" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".pfm" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".pfx" mimeType="application/x-pkcs12" />
+      <mimeMap fileExtension=".pgm" mimeType="image/x-portable-graymap" />
+      <mimeMap fileExtension=".pko" mimeType="application/vnd.ms-pki.pko" />
+      <mimeMap fileExtension=".pma" mimeType="application/x-perfmon" />
+      <mimeMap fileExtension=".pmc" mimeType="application/x-perfmon" />
+      <mimeMap fileExtension=".pml" mimeType="application/x-perfmon" />
+      <mimeMap fileExtension=".pmr" mimeType="application/x-perfmon" />
+      <mimeMap fileExtension=".pmw" mimeType="application/x-perfmon" />
+      <mimeMap fileExtension=".png" mimeType="image/png" />
+      <mimeMap fileExtension=".pnm" mimeType="image/x-portable-anymap" />
+      <mimeMap fileExtension=".pnz" mimeType="image/png" />
+      <mimeMap fileExtension=".pot" mimeType="application/vnd.ms-powerpoint" />
+      <mimeMap fileExtension=".potm" mimeType="application/vnd.ms-powerpoint.template.macroEnabled.12" />
+      <mimeMap fileExtension=".potx" mimeType="application/vnd.openxmlformats-officedocument.presentationml.template" />
+      <mimeMap fileExtension=".ppam" mimeType="application/vnd.ms-powerpoint.addin.macroEnabled.12" />
+      <mimeMap fileExtension=".ppm" mimeType="image/x-portable-pixmap" />
+      <mimeMap fileExtension=".pps" mimeType="application/vnd.ms-powerpoint" />
+      <mimeMap fileExtension=".ppsm" mimeType="application/vnd.ms-powerpoint.slideshow.macroEnabled.12" />
+      <mimeMap fileExtension=".ppsx" mimeType="application/vnd.openxmlformats-officedocument.presentationml.slideshow" />
+      <mimeMap fileExtension=".ppt" mimeType="application/vnd.ms-powerpoint" />
+      <mimeMap fileExtension=".pptm" mimeType="application/vnd.ms-powerpoint.presentation.macroEnabled.12" />
+      <mimeMap fileExtension=".pptx" mimeType="application/vnd.openxmlformats-officedocument.presentationml.presentation" />
+      <mimeMap fileExtension=".prf" mimeType="application/pics-rules" />
+      <mimeMap fileExtension=".prm" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".prx" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".ps" mimeType="application/postscript" />
+      <mimeMap fileExtension=".psd" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".psm" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".psp" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".pub" mimeType="application/x-mspublisher" />
+      <mimeMap fileExtension=".qt" mimeType="video/quicktime" />
+      <mimeMap fileExtension=".qtl" mimeType="application/x-quicktimeplayer" />
+      <mimeMap fileExtension=".qxd" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".ra" mimeType="audio/x-pn-realaudio" />
+      <mimeMap fileExtension=".ram" mimeType="audio/x-pn-realaudio" />
+      <mimeMap fileExtension=".rar" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".ras" mimeType="image/x-cmu-raster" />
+      <mimeMap fileExtension=".rf" mimeType="image/vnd.rn-realflash" />
+      <mimeMap fileExtension=".rgb" mimeType="image/x-rgb" />
+      <mimeMap fileExtension=".rm" mimeType="application/vnd.rn-realmedia" />
+      <mimeMap fileExtension=".rmi" mimeType="audio/mid" />
+      <mimeMap fileExtension=".roff" mimeType="application/x-troff" />
+      <mimeMap fileExtension=".rpm" mimeType="audio/x-pn-realaudio-plugin" />
+      <mimeMap fileExtension=".rtf" mimeType="application/rtf" />
+      <mimeMap fileExtension=".rtx" mimeType="text/richtext" />
+      <mimeMap fileExtension=".scd" mimeType="application/x-msschedule" />
+      <mimeMap fileExtension=".sct" mimeType="text/scriptlet" />
+      <mimeMap fileExtension=".sea" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".setpay" mimeType="application/set-payment-initiation" />
+      <mimeMap fileExtension=".setreg" mimeType="application/set-registration-initiation" />
+      <mimeMap fileExtension=".sgml" mimeType="text/sgml" />
+      <mimeMap fileExtension=".sh" mimeType="application/x-sh" />
+      <mimeMap fileExtension=".shar" mimeType="application/x-shar" />
+      <mimeMap fileExtension=".sit" mimeType="application/x-stuffit" />
+      <mimeMap fileExtension=".sldm" mimeType="application/vnd.ms-powerpoint.slide.macroEnabled.12" />
+      <mimeMap fileExtension=".sldx" mimeType="application/vnd.openxmlformats-officedocument.presentationml.slide" />
+      <mimeMap fileExtension=".smd" mimeType="audio/x-smd" />
+      <mimeMap fileExtension=".smi" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".smx" mimeType="audio/x-smd" />
+      <mimeMap fileExtension=".smz" mimeType="audio/x-smd" />
+      <mimeMap fileExtension=".snd" mimeType="audio/basic" />
+      <mimeMap fileExtension=".snp" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".spc" mimeType="application/x-pkcs7-certificates" />
+      <mimeMap fileExtension=".spl" mimeType="application/futuresplash" />
+      <mimeMap fileExtension=".spx" mimeType="audio/ogg" />
+      <mimeMap fileExtension=".src" mimeType="application/x-wais-source" />
+      <mimeMap fileExtension=".ssm" mimeType="application/streamingmedia" />
+      <mimeMap fileExtension=".sst" mimeType="application/vnd.ms-pki.certstore" />
+      <mimeMap fileExtension=".stl" mimeType="application/vnd.ms-pki.stl" />
+      <mimeMap fileExtension=".sv4cpio" mimeType="application/x-sv4cpio" />
+      <mimeMap fileExtension=".sv4crc" mimeType="application/x-sv4crc" />
+      <mimeMap fileExtension=".svg" mimeType="image/svg+xml" />
+      <mimeMap fileExtension=".svgz" mimeType="image/svg+xml" />
+      <mimeMap fileExtension=".swf" mimeType="application/x-shockwave-flash" />
+      <mimeMap fileExtension=".t" mimeType="application/x-troff" />
+      <mimeMap fileExtension=".tar" mimeType="application/x-tar" />
+      <mimeMap fileExtension=".tcl" mimeType="application/x-tcl" />
+      <mimeMap fileExtension=".tex" mimeType="application/x-tex" />
+      <mimeMap fileExtension=".texi" mimeType="application/x-texinfo" />
+      <mimeMap fileExtension=".texinfo" mimeType="application/x-texinfo" />
+      <mimeMap fileExtension=".tgz" mimeType="application/x-compressed" />
+      <mimeMap fileExtension=".thmx" mimeType="application/vnd.ms-officetheme" />
+      <mimeMap fileExtension=".thn" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".tif" mimeType="image/tiff" />
+      <mimeMap fileExtension=".tiff" mimeType="image/tiff" />
+      <mimeMap fileExtension=".toc" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".tr" mimeType="application/x-troff" />
+      <mimeMap fileExtension=".trm" mimeType="application/x-msterminal" />
+      <mimeMap fileExtension=".ts" mimeType="video/vnd.dlna.mpeg-tts" />
+      <mimeMap fileExtension=".tsv" mimeType="text/tab-separated-values" />
+      <mimeMap fileExtension=".ttf" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".tts" mimeType="video/vnd.dlna.mpeg-tts" />
+      <mimeMap fileExtension=".txt" mimeType="text/plain" />
+      <mimeMap fileExtension=".u32" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".uls" mimeType="text/iuls" />
+      <mimeMap fileExtension=".ustar" mimeType="application/x-ustar" />
+      <mimeMap fileExtension=".vbs" mimeType="text/vbscript" />
+      <mimeMap fileExtension=".vcf" mimeType="text/x-vcard" />
+      <mimeMap fileExtension=".vcs" mimeType="text/plain" />
+      <mimeMap fileExtension=".vdx" mimeType="application/vnd.ms-visio.viewer" />
+      <mimeMap fileExtension=".vml" mimeType="text/xml" />
+      <mimeMap fileExtension=".vsd" mimeType="application/vnd.visio" />
+      <mimeMap fileExtension=".vss" mimeType="application/vnd.visio" />
+      <mimeMap fileExtension=".vst" mimeType="application/vnd.visio" />
+      <mimeMap fileExtension=".vsto" mimeType="application/x-ms-vsto" />
+      <mimeMap fileExtension=".vsw" mimeType="application/vnd.visio" />
+      <mimeMap fileExtension=".vsx" mimeType="application/vnd.visio" />
+      <mimeMap fileExtension=".vtx" mimeType="application/vnd.visio" />
+      <mimeMap fileExtension=".wav" mimeType="audio/wav" />
+      <mimeMap fileExtension=".wax" mimeType="audio/x-ms-wax" />
+      <mimeMap fileExtension=".wbmp" mimeType="image/vnd.wap.wbmp" />
+      <mimeMap fileExtension=".wcm" mimeType="application/vnd.ms-works" />
+      <mimeMap fileExtension=".wdb" mimeType="application/vnd.ms-works" />
+      <mimeMap fileExtension=".webm" mimeType="video/webm" />
+      <mimeMap fileExtension=".wks" mimeType="application/vnd.ms-works" />
+      <mimeMap fileExtension=".wm" mimeType="video/x-ms-wm" />
+      <mimeMap fileExtension=".wma" mimeType="audio/x-ms-wma" />
+      <mimeMap fileExtension=".wmd" mimeType="application/x-ms-wmd" />
+      <mimeMap fileExtension=".wmf" mimeType="application/x-msmetafile" />
+      <mimeMap fileExtension=".wml" mimeType="text/vnd.wap.wml" />
+      <mimeMap fileExtension=".wmlc" mimeType="application/vnd.wap.wmlc" />
+      <mimeMap fileExtension=".wmls" mimeType="text/vnd.wap.wmlscript" />
+      <mimeMap fileExtension=".wmlsc" mimeType="application/vnd.wap.wmlscriptc" />
+      <mimeMap fileExtension=".wmp" mimeType="video/x-ms-wmp" />
+      <mimeMap fileExtension=".wmv" mimeType="video/x-ms-wmv" />
+      <mimeMap fileExtension=".wmx" mimeType="video/x-ms-wmx" />
+      <mimeMap fileExtension=".wmz" mimeType="application/x-ms-wmz" />
+      <mimeMap fileExtension=".woff" mimeType="font/x-woff" />
+      <mimeMap fileExtension=".woff2" mimeType="application/font-woff2" />
+      <mimeMap fileExtension=".wps" mimeType="application/vnd.ms-works" />
+      <mimeMap fileExtension=".wri" mimeType="application/x-mswrite" />
+      <mimeMap fileExtension=".wrl" mimeType="x-world/x-vrml" />
+      <mimeMap fileExtension=".wrz" mimeType="x-world/x-vrml" />
+      <mimeMap fileExtension=".wsdl" mimeType="text/xml" />
+      <mimeMap fileExtension=".wtv" mimeType="video/x-ms-wtv" />
+      <mimeMap fileExtension=".wvx" mimeType="video/x-ms-wvx" />
+      <mimeMap fileExtension=".x" mimeType="application/directx" />
+      <mimeMap fileExtension=".xaf" mimeType="x-world/x-vrml" />
+      <mimeMap fileExtension=".xaml" mimeType="application/xaml+xml" />
+      <mimeMap fileExtension=".xap" mimeType="application/x-silverlight-app" />
+      <mimeMap fileExtension=".xbap" mimeType="application/x-ms-xbap" />
+      <mimeMap fileExtension=".xbm" mimeType="image/x-xbitmap" />
+      <mimeMap fileExtension=".xdr" mimeType="text/plain" />
+      <mimeMap fileExtension=".xht" mimeType="application/xhtml+xml" />
+      <mimeMap fileExtension=".xhtml" mimeType="application/xhtml+xml" />
+      <mimeMap fileExtension=".xla" mimeType="application/vnd.ms-excel" />
+      <mimeMap fileExtension=".xlam" mimeType="application/vnd.ms-excel.addin.macroEnabled.12" />
+      <mimeMap fileExtension=".xlc" mimeType="application/vnd.ms-excel" />
+      <mimeMap fileExtension=".xlm" mimeType="application/vnd.ms-excel" />
+      <mimeMap fileExtension=".xls" mimeType="application/vnd.ms-excel" />
+      <mimeMap fileExtension=".xlsb" mimeType="application/vnd.ms-excel.sheet.binary.macroEnabled.12" />
+      <mimeMap fileExtension=".xlsm" mimeType="application/vnd.ms-excel.sheet.macroEnabled.12" />
+      <mimeMap fileExtension=".xlsx" mimeType="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" />
+      <mimeMap fileExtension=".xlt" mimeType="application/vnd.ms-excel" />
+      <mimeMap fileExtension=".xltm" mimeType="application/vnd.ms-excel.template.macroEnabled.12" />
+      <mimeMap fileExtension=".xltx" mimeType="application/vnd.openxmlformats-officedocument.spreadsheetml.template" />
+      <mimeMap fileExtension=".xlw" mimeType="application/vnd.ms-excel" />
+      <mimeMap fileExtension=".xml" mimeType="text/xml" />
+      <mimeMap fileExtension=".xof" mimeType="x-world/x-vrml" />
+      <mimeMap fileExtension=".xpm" mimeType="image/x-xpixmap" />
+      <mimeMap fileExtension=".xps" mimeType="application/vnd.ms-xpsdocument" />
+      <mimeMap fileExtension=".xsd" mimeType="text/xml" />
+      <mimeMap fileExtension=".xsf" mimeType="text/xml" />
+      <mimeMap fileExtension=".xsl" mimeType="text/xml" />
+      <mimeMap fileExtension=".xslt" mimeType="text/xml" />
+      <mimeMap fileExtension=".xsn" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".xtp" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".xwd" mimeType="image/x-xwindowdump" />
+      <mimeMap fileExtension=".z" mimeType="application/x-compress" />
+      <mimeMap fileExtension=".zip" mimeType="application/x-zip-compressed" />
+    </staticContent>
+
+    <tracing>
+
+      <traceFailedRequests />
+
+      <traceProviderDefinitions />
+
+    </tracing>
+
+    <urlCompression />
+
+    <validation />
+
+  </system.webServer>
+
+</configuration>
diff --git a/src/IISIntegration/build/build.msbuild b/src/IISIntegration/build/build.msbuild
new file mode 100644
index 0000000000000000000000000000000000000000..117ed59becf77d33f762827209b59e1d3fe49d60
--- /dev/null
+++ b/src/IISIntegration/build/build.msbuild
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?> 
+<Project ToolsVersion="12.0" DefaultTargets="Test" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> 
+   <Import Project="$(MSBuildThisFileDirectory)\Build.Settings" /> 
+   <ItemGroup> 
+     <Projects Include="$(SolutionDir)\src\AspNetCoreModuleV1\AspNetCore\AspNetCore.vcxproj" /> 
+     <Projects Include="$(SolutionDir)\src\AspNetCoreModuleV2\AspNetCore\AspNetCore.vcxproj" /> 
+     <Projects Include="$(SolutionDir)\src\AspNetCoreModuleV2\RequestHandler\RequestHandler.vcxproj" /> 
+   </ItemGroup> 
+ 
+   <Target Name="Build"> 
+     <MSBuild Targets="$(BuildTargets)" 
+       Projects="@(Projects)" 
+       Properties="Configuration=$(Configuration);Platform=$(Platform);PlatformToolset=$(PlatformToolset)" /> 
+   </Target> 
+
+   <Target Name="Clean"> 
+     <MSBuild Targets="Clean" 
+       Projects="@(Projects)" /> 
+   </Target> 
+ 
+   <Target Name="Rebuild"> 
+     <MSBuild Targets="Clean;Build" 
+       Projects="$(MSBuildProjectFile)" 
+       Properties="BuildTargets=Rebuild;Configuration=$(Configuration);Platform=$(Platform);PlatformToolset=$(PlatformToolset)"/> 
+   </Target> 
+
+   <Target Name="Test" DependsOnTargets="Build"> 
+     <!-- once we have test project ready, we should add executions to run the test post build-->
+   </Target> 
+   <Import Project="Config.Definitions.Props" /> 
+ </Project> 
diff --git a/src/IISIntegration/build/dependencies.props b/src/IISIntegration/build/dependencies.props
new file mode 100644
index 0000000000000000000000000000000000000000..c90801a57326ada7b0c0feb8d88092c6c508b4a8
--- /dev/null
+++ b/src/IISIntegration/build/dependencies.props
@@ -0,0 +1,55 @@
+<Project>
+  <PropertyGroup>
+    <MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
+  </PropertyGroup>
+
+  <!-- These package versions may be overridden or updated by automation. -->
+  <PropertyGroup Label="Package Versions: Auto">
+    <InternalAspNetCoreSdkPackageVersion>2.1.3-rtm-15802</InternalAspNetCoreSdkPackageVersion>
+    <MicrosoftBuildFrameworkPackageVersion>15.6.82</MicrosoftBuildFrameworkPackageVersion>
+    <MicrosoftBuildUtilitiesCorePackageVersion>15.6.82</MicrosoftBuildUtilitiesCorePackageVersion>
+    <MicrosoftNETCoreApp20PackageVersion>2.0.0</MicrosoftNETCoreApp20PackageVersion>
+    <MicrosoftNETCoreApp21PackageVersion>2.1.2</MicrosoftNETCoreApp21PackageVersion>
+    <MicrosoftNETTestSdkPackageVersion>15.6.1</MicrosoftNETTestSdkPackageVersion>
+    <NETStandardLibrary20PackageVersion>2.0.3</NETStandardLibrary20PackageVersion>
+    <SystemBuffersPackageVersion>4.5.0</SystemBuffersPackageVersion>
+    <SystemIOPipelinesPackageVersion>4.5.0</SystemIOPipelinesPackageVersion>
+    <SystemMemoryPackageVersion>4.5.1</SystemMemoryPackageVersion>
+    <SystemNetWebSocketsWebSocketProtocolPackageVersion>4.5.1</SystemNetWebSocketsWebSocketProtocolPackageVersion>
+    <SystemNumericsVectorsPackageVersion>4.5.0</SystemNumericsVectorsPackageVersion>
+    <SystemRuntimeCompilerServicesUnsafePackageVersion>4.5.1</SystemRuntimeCompilerServicesUnsafePackageVersion>
+    <SystemSecurityPrincipalWindowsPackageVersion>4.5.0</SystemSecurityPrincipalWindowsPackageVersion>
+    <Tooling_NewtonsoftJsonPackageVersion>9.0.1</Tooling_NewtonsoftJsonPackageVersion>
+    <XunitPackageVersion>2.3.1</XunitPackageVersion>
+    <XunitRunnerVisualStudioPackageVersion>2.4.0-beta.1.build3945</XunitRunnerVisualStudioPackageVersion>
+  </PropertyGroup>
+
+  <!-- This may import a generated file which may override the variables above. -->
+  <Import Project="$(DotNetPackageVersionPropsPath)" Condition=" '$(DotNetPackageVersionPropsPath)' != '' " />
+
+  <!-- These are package versions that should not be overridden or updated by automation. -->
+  <PropertyGroup Label="Package Versions: Pinned">
+    <MicrosoftAspNetCoreAllPackageVersion>2.1.2</MicrosoftAspNetCoreAllPackageVersion>
+    <MicrosoftAspNetCoreAuthenticationCorePackageVersion>2.1.1</MicrosoftAspNetCoreAuthenticationCorePackageVersion>
+    <MicrosoftAspNetCoreHostingAbstractionsPackageVersion>2.1.1</MicrosoftAspNetCoreHostingAbstractionsPackageVersion>
+    <MicrosoftAspNetCoreHostingPackageVersion>2.1.1</MicrosoftAspNetCoreHostingPackageVersion>
+    <MicrosoftAspNetCoreHttpExtensionsPackageVersion>2.1.1</MicrosoftAspNetCoreHttpExtensionsPackageVersion>
+    <MicrosoftAspNetCoreHttpOverridesPackageVersion>2.1.1</MicrosoftAspNetCoreHttpOverridesPackageVersion>
+    <MicrosoftAspNetCoreHttpPackageVersion>2.1.1</MicrosoftAspNetCoreHttpPackageVersion>
+    <MicrosoftAspNetCoreHttpSysSourcesPackageVersion>2.1.1</MicrosoftAspNetCoreHttpSysSourcesPackageVersion>
+    <MicrosoftAspNetCoreServerIntegrationTestingPackageVersion>0.5.1</MicrosoftAspNetCoreServerIntegrationTestingPackageVersion>
+    <MicrosoftAspNetCoreServerKestrelPackageVersion>2.1.2</MicrosoftAspNetCoreServerKestrelPackageVersion>
+    <MicrosoftAspNetCoreTestHostPackageVersion>2.1.1</MicrosoftAspNetCoreTestHostPackageVersion>
+    <MicrosoftAspNetCoreTestingPackageVersion>2.1.0</MicrosoftAspNetCoreTestingPackageVersion>
+    <MicrosoftAspNetCoreWebUtilitiesPackageVersion>2.1.1</MicrosoftAspNetCoreWebUtilitiesPackageVersion>
+    <MicrosoftExtensionsConfigurationEnvironmentVariablesPackageVersion>2.1.1</MicrosoftExtensionsConfigurationEnvironmentVariablesPackageVersion>
+    <MicrosoftExtensionsConfigurationJsonPackageVersion>2.1.1</MicrosoftExtensionsConfigurationJsonPackageVersion>
+    <MicrosoftExtensionsLoggingAbstractionsPackageVersion>2.1.1</MicrosoftExtensionsLoggingAbstractionsPackageVersion>
+    <MicrosoftExtensionsLoggingConsolePackageVersion>2.1.1</MicrosoftExtensionsLoggingConsolePackageVersion>
+    <MicrosoftExtensionsLoggingDebugPackageVersion>2.1.1</MicrosoftExtensionsLoggingDebugPackageVersion>
+    <MicrosoftExtensionsLoggingPackageVersion>2.1.1</MicrosoftExtensionsLoggingPackageVersion>
+    <MicrosoftExtensionsLoggingTestingPackageVersion>2.1.1</MicrosoftExtensionsLoggingTestingPackageVersion>
+    <MicrosoftExtensionsOptionsPackageVersion>2.1.1</MicrosoftExtensionsOptionsPackageVersion>
+    <MicrosoftNetHttpHeadersPackageVersion>2.1.1</MicrosoftNetHttpHeadersPackageVersion>
+  </PropertyGroup>
+</Project>
diff --git a/src/IISIntegration/build/launchSettings.json b/src/IISIntegration/build/launchSettings.json
new file mode 100644
index 0000000000000000000000000000000000000000..6d5ce43f737ab71fa52d0d89e97557c31e99bdc3
--- /dev/null
+++ b/src/IISIntegration/build/launchSettings.json
@@ -0,0 +1,37 @@
+{
+  "iisSettings": {
+    "windowsAuthentication": true,
+    "anonymousAuthentication": true,
+    "iisExpress": {
+      "applicationUrl": "http://localhost:5762/",
+      "sslPort": 0
+    }
+  },
+  "profiles": {
+    "ANCM IIS Express": {
+      "commandName": "Executable",
+      "executablePath": "$(IISExpressPath)",
+      "commandLineArgs": "$(IISExpressArguments)",
+      "nativeDebugging": true,
+      "environmentVariables": {
+        "IIS_SITE_PATH": "$(MSBuildThisFileDirectory)",
+        "ANCM_PATH": "$(TargetDir)$(AncmPath)",
+        "LAUNCHER_ARGS": "$(TargetPath)",
+        "ASPNETCORE_ENVIRONMENT": "Development",
+        "LAUNCHER_PATH": "$(DotNetPath)"
+      }
+    },
+    "ANCM IIS": {
+      "commandName": "Executable",
+      "executablePath": "$(IISPath)",
+      "commandLineArgs": "$(IISArguments)",
+      "environmentVariables": {
+        "IIS_SITE_PATH": "$(MSBuildThisFileDirectory)",
+        "ANCM_PATH": "$(TargetDir)$(AncmPath)",
+        "LAUNCHER_ARGS": "$(TargetPath)",
+        "ASPNETCORE_ENVIRONMENT": "Development",
+        "LAUNCHER_PATH": "$(DotNetPath)"
+      }
+    }
+  }
+}
diff --git a/src/IISIntegration/build/native.targets b/src/IISIntegration/build/native.targets
new file mode 100644
index 0000000000000000000000000000000000000000..1c5a9816913373ce8548d759c3e5e84803430131
--- /dev/null
+++ b/src/IISIntegration/build/native.targets
@@ -0,0 +1,25 @@
+<Project>
+
+  <Target Name="CreateVersionHeader" BeforeTargets="PrepareForBuild">
+    <ItemGroup>
+      <VersionHeaderContents Include="// Copyright (c) .NET Foundation. All rights reserved." />
+      <VersionHeaderContents Include="// Licensed under the MIT License. See LICENSE.txt in the project root for license information." />
+      <VersionHeaderContents Include="%0a" />
+      <VersionHeaderContents Include="// This file is auto-generated" />
+      <VersionHeaderContents Include="%0a" />
+      <VersionHeaderContents Include="#define FileVersion $(AspNetCoreModuleVersionMajor),$(AspNetCoreModuleVersionMinor),$(AssemblyBuild),$(AspNetCoreModuleVersionRevision)" />
+      <VersionHeaderContents Include="#define FileVersionStr &quot;$(AspNetCoreModuleVersionMajor).$(AspNetCoreModuleVersionMinor).$(AssemblyBuild).$(AspNetCoreModuleVersionRevision)\0&quot;" />
+      <VersionHeaderContents Include="#define ProductVersion $(AspNetCoreModuleVersionMajor),$(AspNetCoreModuleVersionMinor),$(AssemblyBuild),$(AspNetCoreModuleVersionRevision)" />
+      <VersionHeaderContents Include="#define ProductVersionStr &quot;$(AspNetCoreModuleVersionMajor).$(AspNetCoreModuleVersionMinor).$(AssemblyBuild).$(AspNetCoreModuleVersionRevision)\0&quot;" />
+      <VersionHeaderContents Include="#define PlatformToolset &quot;$(PlatformToolset)\0&quot;" />
+      <VersionHeaderContents Include="#define CommitHash &quot;$(CommitHash)\0&quot;" />
+    </ItemGroup>
+
+    <ItemGroup>
+      <FileWrites Include="version.h" />
+    </ItemGroup>
+
+    <WriteLinesToFile File="version.h" Lines="@(VersionHeaderContents)" OverWrite="true" WriteOnlyWhenDifferent="True" />
+  </Target>
+
+</Project>
diff --git a/src/IISIntegration/build/repo.props b/src/IISIntegration/build/repo.props
new file mode 100644
index 0000000000000000000000000000000000000000..c3e3c1c2275b0b4175a474a942b1e43ab4174c2c
--- /dev/null
+++ b/src/IISIntegration/build/repo.props
@@ -0,0 +1,33 @@
+<Project>
+  <Import Project="dependencies.props" />
+
+  <PropertyGroup>
+    <AssemblySigningCertName>Microsoft</AssemblySigningCertName>
+    <AncmZipOutputPath>$(BuildDir)AspNetCoreModule.zip</AncmZipOutputPath>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <ExcludeFromTest Include="$(RepositoryRoot)test\TestSites\*.csproj" />
+    <ExcludeFromTest Include="$(RepositoryRoot)test\IISTestSite\*.csproj" />
+    <ExcludeFromTest Include="$(RepositoryRoot)test\IISIntegration.FunctionalTests\*.csproj" Condition="'$(OS)' != 'Windows_NT'" />
+    <ExcludeFromTest Include="$(RepositoryRoot)test\IISIntegration.IISServerFunctionalTests\*.csproj" Condition="'$(OS)' != 'Windows_NT'" />
+    <ExcludeFromTest Include="$(RepositoryRoot)test\AspNetCoreModule.TestSites.Standard\*.csproj" />
+    <ExcludeFromTest Include="$(RepositoryRoot)test\WebSocketClientEXE\*.csproj" />
+    <ExcludeFromTest Include="$(RepositoryRoot)test\AspNetCoreModule.Test\*.csproj" Condition="'$(OS)' != 'Windows_NT'" />
+  </ItemGroup>
+
+  <PropertyGroup>
+    <!-- These properties are use by the automation that updates dependencies.props -->
+    <LineupPackageId>Internal.AspNetCore.Universe.Lineup</LineupPackageId>
+    <LineupPackageVersion>2.1.0-rc1-*</LineupPackageVersion>
+    <LineupPackageRestoreSource>https://dotnet.myget.org/F/aspnetcore-dev/api/v3/index.json</LineupPackageRestoreSource>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <DotNetCoreRuntime Include="$(MicrosoftNETCoreApp20PackageVersion)" />
+    <DotNetCoreRuntime Include="$(MicrosoftNETCoreApp21PackageVersion)" />
+    <!-- These are for functional test projects that are only runable on windows -->
+    <DotNetCoreRuntime Condition="'$(OS)' == 'Windows_NT'" Include="$(MicrosoftNETCoreApp20PackageVersion)" Arch="x86" />
+    <DotNetCoreRuntime Condition="'$(OS)' == 'Windows_NT'" Include="$(MicrosoftNETCoreApp21PackageVersion)" Arch="x86" />
+  </ItemGroup>
+</Project>
diff --git a/src/IISIntegration/build/repo.targets b/src/IISIntegration/build/repo.targets
new file mode 100644
index 0000000000000000000000000000000000000000..c39d7367c51de2e50aed3b9c28145961c5519e3f
--- /dev/null
+++ b/src/IISIntegration/build/repo.targets
@@ -0,0 +1,102 @@
+<Project>
+
+  <PropertyGroup>
+    <CompileDependsOn Condition="'$(OS)'=='Windows_NT'">BuildNativeAssets;$(CompileDependsOn)</CompileDependsOn>
+    <PackageDependsOn Condition="'$(OS)'=='Windows_NT'">$(PackageDependsOn);PackageNativeProjects</PackageDependsOn>
+    <NuGetVerifierRuleFile Condition="'$(OS)' != 'Windows_NT'">$(RepositoryRoot)NuGetPackageVerifier.xplat.json</NuGetVerifierRuleFile>
+  </PropertyGroup>
+
+  <Target Name="BuildNativeAssets" DependsOnTargets="Prepare;GetToolsets" >
+    <PropertyGroup>
+      <BuildArgs>-p:Configuration=$(Configuration) -v:m -nologo -clp:NoSummary -p:CommitHash=$(CommitHash)</BuildArgs>
+    </PropertyGroup>
+
+    <ItemGroup>
+      <Platforms Include="Win32;x64" />
+    </ItemGroup>
+
+    <Error
+      Text="Could not find an installation of Visual Studio with the C++ development tools."
+      Condition="'$(VisualStudioMSBuildx86Path)' == ''" />
+
+    <Exec Command="&quot;$(VisualStudioMSBuildx86Path)&quot; &quot;$(RepositoryRoot)src\AspNetCoreModuleV1\AspNetCore\AspNetCore.vcxproj&quot; $(BuildArgs) -p:Platform=%(Platforms.Identity) -bl:$(LogOutputDir)native.%(Platforms.Identity).binlog"
+      Condition="'$(VisualStudioMSBuildx86Path)' != ''" />
+    <Exec Command="&quot;$(VisualStudioMSBuildx86Path)&quot; &quot;$(RepositoryRoot)src\AspNetCoreModuleV2\AspNetCore\AspNetCore.vcxproj&quot; $(BuildArgs) -p:Platform=%(Platforms.Identity) -bl:$(LogOutputDir)native.%(Platforms.Identity).binlog"
+      Condition="'$(VisualStudioMSBuildx86Path)' != ''" />
+    <Exec Command="&quot;$(VisualStudioMSBuildx86Path)&quot; &quot;$(RepositoryRoot)src\AspNetCoreModuleV2\RequestHandler\RequestHandler.vcxproj&quot; $(BuildArgs) -p:Platform=%(Platforms.Identity) -bl:$(LogOutputDir)native.%(Platforms.Identity).binlog"
+      Condition="'$(VisualStudioMSBuildx86Path)' != ''" />
+  </Target>
+
+  <ItemGroup Condition=" '$(OS)' == 'Windows_NT' ">
+    <ArtifactInfo Include="$(BuildDir)Microsoft.AspNetCore.AspNetCoreModule.$(PackageVersion).nupkg">
+      <ArtifactType>NuGetPackage</ArtifactType>
+      <PackageId>Microsoft.AspNetCore.AspNetCoreModule</PackageId>
+      <Version>$(PackageVersion)</Version>
+      <RepositoryRoot>$(RepositoryRoot)</RepositoryRoot>
+    </ArtifactInfo>
+    <FilesToExcludeFromSigning Include="$(BuildDir)Microsoft.AspNetCore.AspNetCoreModule.$(PackageVersion).nupkg" />
+
+    <ArtifactInfo Include="$(BuildDir)Microsoft.AspNetCore.AspNetCoreModuleV1.$(PackageVersion).nupkg">
+      <ArtifactType>NuGetPackage</ArtifactType>
+      <PackageId>Microsoft.AspNetCore.AspNetCoreModuleV1</PackageId>
+      <Version>$(PackageVersion)</Version>
+      <RepositoryRoot>$(RepositoryRoot)</RepositoryRoot>
+    </ArtifactInfo>
+    <FilesToExcludeFromSigning Include="$(BuildDir)Microsoft.AspNetCore.AspNetCoreModuleV1.$(PackageVersion).nupkg" />
+
+    <ArtifactInfo Include="$(AncmZipOutputPath)">
+      <ArtifactType>ZipArchive</ArtifactType>
+      <RepositoryRoot>$(RepositoryRoot)</RepositoryRoot>
+      <Category>shipoob</Category>
+    </ArtifactInfo>
+
+    <FilesToSign Include="$(AncmZipOutputPath)" IsContainer="true" />
+    <FilesToSign Include="AspNetCoreModuleV1/x64/aspnetcore.dll" Container="$(AncmZipOutputPath)" Certificate="$(AssemblySigningCertName)" />
+    <FilesToSign Include="AspNetCoreModuleV1/x86/aspnetcore.dll" Container="$(AncmZipOutputPath)" Certificate="$(AssemblySigningCertName)" />
+    <FilesToSign Include="AspNetCoreModuleV2/x64/aspnetcore.dll" Container="$(AncmZipOutputPath)" Certificate="$(AssemblySigningCertName)" />
+    <FilesToSign Include="AspNetCoreModuleV2/x86/aspnetcore.dll" Container="$(AncmZipOutputPath)" Certificate="$(AssemblySigningCertName)" />
+    <FilesToSign Include="AspNetCoreModuleV2/x64/aspnetcorerh.dll" Container="$(AncmZipOutputPath)" Certificate="$(AssemblySigningCertName)" />
+    <FilesToSign Include="AspNetCoreModuleV2/x86/aspnetcorerh.dll" Container="$(AncmZipOutputPath)" Certificate="$(AssemblySigningCertName)" />
+  </ItemGroup>
+
+  <Target Name="PackageNativeProjects">
+    <PackNuspec NuspecPath="$(MSBuildThisFileDirectory)..\nuget\AspNetCoreV1.nuspec"
+      DestinationFolder="$(BuildDir)"
+      Properties="version=$(PackageVersion);Configuration=$(Configuration)"
+      Overwrite="true"
+      BasePath="$(RepositoryRoot)" />
+
+    <PackNuspec NuspecPath="$(MSBuildThisFileDirectory)..\nuget\AspNetCoreV2.nuspec"
+      DestinationFolder="$(BuildDir)"
+      Properties="version=$(PackageVersion);Configuration=$(Configuration)"
+      Overwrite="true"
+      BasePath="$(RepositoryRoot)" />
+
+    <ItemGroup>
+      <!-- x64 -->
+      <AncmFiles Include="$(RepositoryRoot)src\AspNetCoreModuleV1\AspNetCore\bin\$(Configuration)\x64\aspnetcore.dll" Link="AspNetCoreModuleV1\x64\aspnetcore.dll" />
+      <AncmFiles Include="$(RepositoryRoot)src\AspNetCoreModuleV1\AspNetCore\bin\$(Configuration)\x64\aspnetcore.pdb" Link="AspNetCoreModuleV1\x64\aspnetcore.pdb" />
+      <AncmFiles Include="$(RepositoryRoot)src\AspNetCoreModuleV2\AspNetCore\bin\$(Configuration)\x64\aspnetcore.dll" Link="AspNetCoreModuleV2\x64\aspnetcore.dll" />
+      <AncmFiles Include="$(RepositoryRoot)src\AspNetCoreModuleV2\AspNetCore\bin\$(Configuration)\x64\aspnetcore.pdb" Link="AspNetCoreModuleV2\x64\aspnetcore.pdb" />
+      <AncmFiles Include="$(RepositoryRoot)src\AspNetCoreModuleV2\RequestHandler\bin\$(Configuration)\x64\aspnetcorerh.dll" Link="AspNetCoreModuleV2\x64\aspnetcorerh.dll" />
+      <AncmFiles Include="$(RepositoryRoot)src\AspNetCoreModuleV2\RequestHandler\bin\$(Configuration)\x64\aspnetcorerh.pdb" Link="AspNetCoreModuleV2\x64\aspnetcorerh.pdb" />
+      <!-- x86 -->
+      <AncmFiles Include="$(RepositoryRoot)src\AspNetCoreModuleV1\AspNetCore\bin\$(Configuration)\Win32\aspnetcore.dll" Link="AspNetCoreModuleV1\x86\aspnetcore.dll" />
+      <AncmFiles Include="$(RepositoryRoot)src\AspNetCoreModuleV1\AspNetCore\bin\$(Configuration)\Win32\aspnetcore.pdb" Link="AspNetCoreModuleV1\x86\aspnetcore.pdb" />
+      <AncmFiles Include="$(RepositoryRoot)src\AspNetCoreModuleV2\AspNetCore\bin\$(Configuration)\Win32\aspnetcore.dll" Link="AspNetCoreModuleV2\x86\aspnetcore.dll" />
+      <AncmFiles Include="$(RepositoryRoot)src\AspNetCoreModuleV2\AspNetCore\bin\$(Configuration)\Win32\aspnetcore.pdb" Link="AspNetCoreModuleV2\x86\aspnetcore.pdb" />
+      <AncmFiles Include="$(RepositoryRoot)src\AspNetCoreModuleV2\RequestHandler\bin\$(Configuration)\Win32\aspnetcorerh.dll" Link="AspNetCoreModuleV2\x86\aspnetcorerh.dll" />
+      <AncmFiles Include="$(RepositoryRoot)src\AspNetCoreModuleV2\RequestHandler\bin\$(Configuration)\Win32\aspnetcorerh.pdb" Link="AspNetCoreModuleV2\x86\aspnetcorerh.pdb" />
+      <!-- Schema-->
+      <AncmFiles Include="$(RepositoryRoot)src\AspNetCoreModuleV1\AspNetCore\bin\$(Configuration)\x64\aspnetcore_schema.xml" Link="AspNetCoreModuleV1\aspnetcore_schema.xml" />
+      <AncmFiles Include="$(RepositoryRoot)src\AspNetCoreModuleV2\AspNetCore\bin\$(Configuration)\x64\aspnetcore_schema.xml" Link="AspNetCoreModuleV2\aspnetcore_schema.xml" />
+      <AncmFiles Include="$(RepositoryRoot)src\AspNetCoreModuleV2\AspNetCore\bin\$(Configuration)\x64\ancm.mof" Link="AspNetCoreModuleV2\ancm.mof" />
+    </ItemGroup>
+
+    <ZipArchive File="$(AncmZipOutputPath)"
+      Overwrite="true"
+      SourceFiles="@(AncmFiles)"
+      WorkingDirectory="$(RepositoryRoot)" />
+  </Target>
+
+</Project>
diff --git a/src/IISIntegration/build/sources.props b/src/IISIntegration/build/sources.props
new file mode 100644
index 0000000000000000000000000000000000000000..9215df9751b4623d725e930464480ecb9a62065d
--- /dev/null
+++ b/src/IISIntegration/build/sources.props
@@ -0,0 +1,17 @@
+<Project>
+  <Import Project="$(DotNetRestoreSourcePropsPath)" Condition="'$(DotNetRestoreSourcePropsPath)' != ''"/>
+
+  <PropertyGroup Label="RestoreSources">
+    <RestoreSources>$(DotNetRestoreSources)</RestoreSources>
+    <RestoreSources Condition="'$(DotNetBuildOffline)' != 'true' AND '$(AspNetUniverseBuildOffline)' != 'true' ">
+      $(RestoreSources);
+      https://dotnet.myget.org/F/dotnet-core/api/v3/index.json;
+      https://dotnet.myget.org/F/aspnetcore-dev/api/v3/index.json;
+      https://dotnet.myget.org/F/aspnetcore-tools/api/v3/index.json;
+    </RestoreSources>
+    <RestoreSources Condition="'$(DotNetBuildOffline)' != 'true'">
+      $(RestoreSources);
+      https://api.nuget.org/v3/index.json;
+    </RestoreSources>
+  </PropertyGroup>
+</Project>
diff --git a/src/IISIntegration/build/testsite.props b/src/IISIntegration/build/testsite.props
new file mode 100644
index 0000000000000000000000000000000000000000..d2f6acea7e817cfa7abf266c0b8f9879aa6bcd9e
--- /dev/null
+++ b/src/IISIntegration/build/testsite.props
@@ -0,0 +1,92 @@
+<Project>
+
+  <PropertyGroup>
+    <RuntimeIdentifiers>win7-x64;win7-x86</RuntimeIdentifiers>
+    <Platforms>x64;x86</Platforms>
+    <IISExpressAppHostConfig>$(MSBuildThisFileDirectory)applicationhost.config</IISExpressAppHostConfig>
+    <IISAppHostConfig>$(MSBuildThisFileDirectory)applicationhost.iis.config</IISAppHostConfig>
+    <NativePlatform Condition="'$(Platform)' == 'AnyCPU'">x64</NativePlatform>
+    <NativePlatform Condition="'$(NativePlatform)' == ''">$(Platform)</NativePlatform>
+  </PropertyGroup>
+  
+  <PropertyGroup Condition="'$(NativePlatform)' == 'x86'">
+    <IISExpressPath>$(MSBuildProgramFiles32)\IIS Express\iisexpress.exe</IISExpressPath>
+    <IISPath>$(SystemRoot)\SysWOW64\inetsrv\w3wp.exe</IISPath>
+    <NativeFolder>Win32</NativeFolder>
+  </PropertyGroup>
+
+  <PropertyGroup Condition="'$(NativePlatform)' == 'x64'">
+    <IISExpressPath>$(ProgramW6432)\IIS Express\iisexpress.exe</IISExpressPath>
+    <IISPath>$(SystemRoot)\System32\inetsrv\w3wp.exe</IISPath>
+    <NativeFolder>x64</NativeFolder>
+  </PropertyGroup>
+
+  <PropertyGroup>
+    <!-- For standalone publish, all dlls are flattened to the same folder. 
+         Set the base path to the request handler 
+    -->
+    <BasePathForRequestHandler Condition="'$(RuntimeIdentifier)' == ''">$(NativePlatform)\</BasePathForRequestHandler>
+    
+  </PropertyGroup>
+  <ItemGroup Condition="'$(OS)' == 'Windows_NT' AND ('$(ANCMVersion)' == 'V2' Or '$(ANCMVersion)' == '')">
+    <None Include="$(MSBuildThisFileDirectory)..\src\AspNetCoreModuleV2\RequestHandler\bin\$(Configuration)\$(NativeFolder)\aspnetcorerh.dll" CopyToOutputDirectory="PreserveNewest" Visible="true" Link="$(BasePathForRequestHandler)%(FileName)%(Extension)" />
+    <None Include="$(MSBuildThisFileDirectory)..\src\AspNetCoreModuleV2\RequestHandler\bin\$(Configuration)\$(NativeFolder)\aspnetcorerh.pdb" CopyToOutputDirectory="PreserveNewest" Visible="true" Link="$(BasePathForRequestHandler)%(FileName)%(Extension)" />
+    <None Include="$(MSBuildThisFileDirectory)..\src\AspNetCoreModuleV2\AspNetCore\bin\$(Configuration)\$(NativeFolder)\aspnetcore.dll" CopyToOutputDirectory="PreserveNewest" Visible="true" Link="$(NativePlatform)\%(FileName)%(Extension)" />
+    <None Include="$(MSBuildThisFileDirectory)..\src\AspNetCoreModuleV2\AspNetCore\bin\$(Configuration)\$(NativeFolder)\aspnetcore.pdb" CopyToOutputDirectory="PreserveNewest" Visible="true" Link="$(NativePlatform)\%(FileName)%(Extension)" />
+  </ItemGroup>
+  <ItemGroup Condition="'$(OS)' == 'Windows_NT' AND '$(ANCMVersion)' == 'V1'">
+    <None Include="$(MSBuildThisFileDirectory)..\src\AspNetCoreModuleV1\AspNetCore\bin\$(Configuration)\$(NativeFolder)\aspnetcore.dll" CopyToOutputDirectory="PreserveNewest" Visible="true" Link="$(NativePlatform)\%(FileName)%(Extension)" />
+    <None Include="$(MSBuildThisFileDirectory)..\src\AspNetCoreModuleV1\AspNetCore\bin\$(Configuration)\$(NativeFolder)\aspnetcore.pdb" CopyToOutputDirectory="PreserveNewest" Visible="true" Link="$(NativePlatform)\%(FileName)%(Extension)" />
+  </ItemGroup>
+   
+  <PropertyGroup>
+    <IISExpressArguments>/config:"$(IISExpressAppHostConfig)"</IISExpressArguments>
+    <IISArguments>-h "$(IISAppHostConfig)"</IISArguments>
+
+    <AncmPath>$(NativePlatform)\aspnetcore.dll</AncmPath>
+    <AncmRHPath>$(NativePlatform)\aspnetcorerh.dll</AncmRHPath>
+    <DotNetPath>$(userprofile)\.dotnet\$(NativePlatform)\dotnet.exe</DotNetPath>
+  </PropertyGroup>
+
+  <Target Name="CopyLaunchSettings" AfterTargets="CoreBuild">
+    <!-- This would always override launch settings files in test projects by the default one -->
+    <Copy SourceFiles="$(MSBuildThisFileDirectory)launchSettings.json" DestinationFolder="$(MSBuildProjectDirectory)\Properties" />
+  </Target>
+
+  <!-- Deps file injection-->
+  <ItemGroup>
+    <ProjectReference Include="$(MSBuildThisFileDirectory)..\test\TestTasks\TestTasks.csproj">
+      <ReferenceOutputAssembly>False</ReferenceOutputAssembly>
+    </ProjectReference>
+  </ItemGroup>
+
+  
+  <Target Name="PrepareInjectionApp" Condition="'$(ANCMVersion)' == 'V2' Or '$(ANCMVersion)' == ''">
+    <PropertyGroup>
+      <InjectDepsAssembly>$(MSBuildThisFileDirectory)..\test\TestTasks\bin\$(Configuration)\$(TargetFramework)\TestTasks</InjectDepsAssembly>
+
+      <InjectDepsApp Condition="'$(TargetFramework)' == 'net461'">$(InjectDepsAssembly)</InjectDepsApp>
+      <InjectDepsArguments>"win7-$(NativePlatform)" "$(AncmRHPath)"</InjectDepsArguments>
+    </PropertyGroup>
+
+    <PropertyGroup Condition="'$(TargetFramework)' == 'net461'">
+      <InjectDepsAssembly>$(InjectDepsAssembly).exe</InjectDepsAssembly>
+      <InjectDepsApp>$(InjectDepsAssembly)</InjectDepsApp>
+    </PropertyGroup>
+
+    <PropertyGroup Condition="'$(TargetFramework)' != 'net461'">
+      <InjectDepsAssembly>$(InjectDepsAssembly).dll</InjectDepsAssembly>
+      <InjectDepsApp>dotnet</InjectDepsApp>
+      <InjectDepsArguments>$(InjectDepsAssembly) $(InjectDepsArguments)</InjectDepsArguments>
+    </PropertyGroup>
+  </Target>
+
+  <Target Name="InjectRequestHandler" AfterTargets="GenerateBuildDependencyFile" DependsOnTargets="PrepareInjectionApp" Condition="'$(ANCMVersion)' == 'V2' Or '$(ANCMVersion)' == ''">
+    <Exec Command="$(InjectDepsApp) $(InjectDepsArguments) &quot;$(ProjectDepsFilePath)&quot;" />
+  </Target>
+
+  <Target Name="InjectRequestHandlerOnPublish" AfterTargets="GeneratePublishDependencyFile" DependsOnTargets="PrepareInjectionApp" Condition="'$(ANCMVersion)' == 'V2' Or '$(ANCMVersion)' == ''">
+    <Exec Command="$(InjectDepsApp) $(InjectDepsArguments) &quot;$(PublishDepsFilePath)&quot;" />
+  </Target>
+
+</Project>
diff --git a/src/IISIntegration/korebuild.json b/src/IISIntegration/korebuild.json
new file mode 100644
index 0000000000000000000000000000000000000000..663f87823359b51b18296e8855dae2d67c1c31b1
--- /dev/null
+++ b/src/IISIntegration/korebuild.json
@@ -0,0 +1,17 @@
+{
+    "$schema": "https://raw.githubusercontent.com/aspnet/BuildTools/release/2.1/tools/korebuild.schema.json",
+    "channel": "release/2.1",
+    "toolsets": {
+      "visualstudio": {
+        "required": ["Windows"],
+        "includePrerelease": true,
+        "minVersion": "15.0.26730.03",
+        "requiredWorkloads": [
+          "Microsoft.VisualStudio.Component.VC.Tools.x86.x64",
+          "Microsoft.VisualStudio.ComponentGroup.NativeDesktop.Win81",
+          "Microsoft.VisualStudio.Component.VC.ATL",
+          "Microsoft.VisualStudio.Component.Windows10SDK.15063.Desktop"
+        ]
+      }
+    }
+  }
\ No newline at end of file
diff --git a/src/IISIntegration/nuget/AspNetCoreV1.nuspec b/src/IISIntegration/nuget/AspNetCoreV1.nuspec
new file mode 100644
index 0000000000000000000000000000000000000000..f89b7ff754cf1fb64ecd585fdbc00c9548335217
--- /dev/null
+++ b/src/IISIntegration/nuget/AspNetCoreV1.nuspec
@@ -0,0 +1,29 @@
+<?xml version="1.0"?>
+<package xmlns="http://schemas.microsoft.com/packaging/2013/05/nuspec.xsd">
+  <metadata>
+    <id>Microsoft.AspNetCore.AspNetCoreModuleV1</id>
+    <title>Microsoft ASP.NET Core Module</title>
+    <version>$VERSION$</version>
+    <authors>Microsoft</authors>
+    <owners>Microsoft</owners>
+    <licenseUrl>https://www.microsoft.com/web/webpi/eula/net_library_eula_ENU.htm</licenseUrl>
+    <copyright>© .NET Foundation. All rights reserved.</copyright>
+    <projectUrl>https://www.asp.net/</projectUrl>
+    <iconUrl>https://go.microsoft.com/fwlink/?LinkID=288859</iconUrl>
+    <requireLicenseAcceptance>true</requireLicenseAcceptance>
+    <description>ASP.NET Core Module</description>
+    <language>en-US</language>
+    <tags>Microsoft.AspNetCore.AspNetCoreModuleV1</tags>
+    <contentFiles>
+      <files include="any/any/*/*.dll" buildAction="None" copyToOutput="true" flatten="false" />
+    </contentFiles>
+  </metadata>
+  <files>
+    <file src="src\AspNetCoreModuleV1\AspNetCore\bin\$Configuration$\Win32\aspnetcore.dll" target="contentFiles\any\any\x86\aspnetcore.dll" />
+    <file src="src\AspNetCoreModuleV1\AspNetCore\bin\$Configuration$\x64\aspnetcore.dll" target="contentFiles\any\any\x64\aspnetcore.dll" />
+    <file src="src\AspNetCoreModuleV1\AspNetCore\bin\$Configuration$\x64\*.xml"/>
+    <file src="tools\installancm.ps1"/>
+    <file src="LICENSE.txt"/>
+    <file src="nuget\Microsoft.AspNetCore.AspNetCoreModule.props" target="build\" />
+  </files>
+</package>
diff --git a/src/IISIntegration/nuget/AspNetCoreV2.nuspec b/src/IISIntegration/nuget/AspNetCoreV2.nuspec
new file mode 100644
index 0000000000000000000000000000000000000000..10745f52c46e2ae982363b652e8842d71911385a
--- /dev/null
+++ b/src/IISIntegration/nuget/AspNetCoreV2.nuspec
@@ -0,0 +1,31 @@
+<?xml version="1.0"?>
+<package xmlns="http://schemas.microsoft.com/packaging/2013/05/nuspec.xsd">
+  <metadata>
+    <id>Microsoft.AspNetCore.AspNetCoreModule</id> <!--TODO make this package version V2 when possible -->
+    <title>Microsoft ASP.NET Core Module</title>
+    <version>$VERSION$</version>
+    <authors>Microsoft</authors>
+    <owners>Microsoft</owners>
+    <licenseUrl>https://www.microsoft.com/web/webpi/eula/net_library_eula_ENU.htm</licenseUrl>
+    <copyright>© .NET Foundation. All rights reserved.</copyright>
+    <projectUrl>https://www.asp.net/</projectUrl>
+    <iconUrl>https://go.microsoft.com/fwlink/?LinkID=288859</iconUrl>
+    <requireLicenseAcceptance>true</requireLicenseAcceptance>
+    <description>ASP.NET Core Module</description>
+    <language>en-US</language>
+    <tags>Microsoft.AspNetCore.AspNetCoreModule</tags>
+    <contentFiles>
+      <files include="any/any/*/*.dll" buildAction="None" copyToOutput="true" flatten="false" />
+    </contentFiles>
+  </metadata>
+  <files>
+    <file src="src\AspNetCoreModuleV2\AspNetCore\bin\$Configuration$\Win32\aspnetcore.dll" target="contentFiles\any\any\x86\aspnetcore.dll" />
+    <file src="src\AspNetCoreModuleV2\AspNetCore\bin\$Configuration$\x64\aspnetcore.dll" target="contentFiles\any\any\x64\aspnetcore.dll" />
+    <file src="src\AspNetCoreModuleV2\RequestHandler\bin\$Configuration$\Win32\aspnetcorerh.dll" target="contentFiles\any\any\x86\aspnetcorerh.dll" />
+    <file src="src\AspNetCoreModuleV2\RequestHandler\bin\$Configuration$\x64\aspnetcorerh.dll" target="contentFiles\any\any\x64\aspnetcorerh.dll" />
+    <file src="src\AspNetCoreModuleV2\AspNetCore\bin\$Configuration$\x64\*.xml"/>
+    <file src="tools\installancm.ps1"/>
+    <file src="LICENSE.txt"/>
+    <file src="nuget\Microsoft.AspNetCore.AspNetCoreModule.props" target="build\" />
+  </files>
+</package>
diff --git a/src/IISIntegration/nuget/Microsoft.AspNetCore.AspNetCoreModule.props b/src/IISIntegration/nuget/Microsoft.AspNetCore.AspNetCoreModule.props
new file mode 100644
index 0000000000000000000000000000000000000000..5b01ee63a4de32b667018fc8ad5714ce19bf93c1
--- /dev/null
+++ b/src/IISIntegration/nuget/Microsoft.AspNetCore.AspNetCoreModule.props
@@ -0,0 +1,10 @@
+<Project>
+
+  <PropertyGroup>
+    <AspNetCoreModuleX64Location>$(MSBuildThisFileDirectory)..\contentFiles\any\any\x64\aspnetcore.dll</AspNetCoreModuleX64Location>
+    <AspNetCoreModuleX86Location>$(MSBuildThisFileDirectory)..\contentFiles\any\any\x86\aspnetcore.dll</AspNetCoreModuleX86Location>
+    <RequestHandlerX64Location>$(MSBuildThisFileDirectory)..\contentFiles\any\any\x64\aspnetcorerh.dll</RequestHandlerX64Location>
+    <RequestHandlerX86Location>$(MSBuildThisFileDirectory)..\contentFiles\any\any\x86\aspnetcorerh.dll</RequestHandlerX86Location>
+  </PropertyGroup>
+
+</Project>
diff --git a/src/IISIntegration/samples/IISSample/IISSample.csproj b/src/IISIntegration/samples/IISSample/IISSample.csproj
new file mode 100644
index 0000000000000000000000000000000000000000..f8dafd69ef2c361aba766e71bd70bc4853fbfc21
--- /dev/null
+++ b/src/IISIntegration/samples/IISSample/IISSample.csproj
@@ -0,0 +1,15 @@
+<Project Sdk="Microsoft.NET.Sdk.Web">
+
+  <PropertyGroup>
+    <TargetFrameworks>netcoreapp2.1;net461</TargetFrameworks>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <ProjectReference Include="..\..\src\Microsoft.AspNetCore.Server.IISIntegration\Microsoft.AspNetCore.Server.IISIntegration.csproj" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="$(MicrosoftAspNetCoreServerKestrelPackageVersion)" />
+    <PackageReference Include="Microsoft.Extensions.Logging.Console" Version="$(MicrosoftExtensionsLoggingConsolePackageVersion)" />
+  </ItemGroup>
+</Project>
diff --git a/src/IISIntegration/samples/IISSample/Properties/launchSettings.json b/src/IISIntegration/samples/IISSample/Properties/launchSettings.json
new file mode 100644
index 0000000000000000000000000000000000000000..009aa9ab8902903c47cd7eb5eeef0cc289757c7b
--- /dev/null
+++ b/src/IISIntegration/samples/IISSample/Properties/launchSettings.json
@@ -0,0 +1,28 @@
+{
+  "iisSettings": {
+    "windowsAuthentication": false,
+    "anonymousAuthentication": true,
+    "iisExpress": {
+      "applicationUrl": "http://localhost:25334/",
+      "sslPort": 0
+    }
+  },
+  "profiles": {
+    "IIS Express": {
+      "commandName": "IISExpress",
+      "launchBrowser": true,
+      "environmentVariables": {
+        "ASPNETCORE_ENVIRONMENT": "Development",
+        "ASPNETCORE_HOSTINGSTARTUPASSEMBLIES": "Microsoft.AspNetCore.Server.IISIntegration"
+      }
+    },
+    "IISSample": {
+      "commandName": "Project",
+      "launchBrowser": true,
+      "launchUrl": "http://localhost:5000",
+      "environmentVariables": {
+        "ASPNETCORE_ENVIRONMENT": "Development"
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/src/IISIntegration/samples/IISSample/Startup.cs b/src/IISIntegration/samples/IISSample/Startup.cs
new file mode 100644
index 0000000000000000000000000000000000000000..138f993d9e612ce10a35020630b81818f21a1f8a
--- /dev/null
+++ b/src/IISIntegration/samples/IISSample/Startup.cs
@@ -0,0 +1,104 @@
+using System;
+using System.Linq;
+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;
+
+namespace IISSample
+{
+    public class Startup
+    {
+        public void ConfigureServices(IServiceCollection services)
+        {
+            // These two middleware are registered via an IStartupFilter in UseIISIntegration but you can configure them here.
+            services.Configure<IISOptions>(options =>
+            {
+                options.AuthenticationDisplayName = "Windows Auth";
+            });
+            services.Configure<ForwardedHeadersOptions>(options =>
+            {
+            });
+        }
+
+        public void Configure(IApplicationBuilder app, ILoggerFactory loggerfactory, IAuthenticationSchemeProvider authSchemeProvider)
+        {
+            var logger = loggerfactory.CreateLogger("Requests");
+
+            app.Run(async (context) =>
+            {
+                logger.LogDebug("Received request: " + context.Request.Method + " " + context.Request.Path);
+
+                context.Response.ContentType = "text/plain";
+                await context.Response.WriteAsync("Hello World - " + DateTimeOffset.Now + Environment.NewLine);
+                await context.Response.WriteAsync(Environment.NewLine);
+
+                await context.Response.WriteAsync("Address:" + Environment.NewLine);
+                await context.Response.WriteAsync("Scheme: " + context.Request.Scheme + Environment.NewLine);
+                await context.Response.WriteAsync("Host: " + context.Request.Headers["Host"] + Environment.NewLine);
+                await context.Response.WriteAsync("PathBase: " + context.Request.PathBase.Value + Environment.NewLine);
+                await context.Response.WriteAsync("Path: " + context.Request.Path.Value + Environment.NewLine);
+                await context.Response.WriteAsync("Query: " + context.Request.QueryString.Value + Environment.NewLine);
+                await context.Response.WriteAsync(Environment.NewLine);
+
+                await context.Response.WriteAsync("Connection:" + Environment.NewLine);
+                await context.Response.WriteAsync("RemoteIp: " + context.Connection.RemoteIpAddress + Environment.NewLine);
+                await context.Response.WriteAsync("RemotePort: " + context.Connection.RemotePort + Environment.NewLine);
+                await context.Response.WriteAsync("LocalIp: " + context.Connection.LocalIpAddress + Environment.NewLine);
+                await context.Response.WriteAsync("LocalPort: " + context.Connection.LocalPort + Environment.NewLine);
+                await context.Response.WriteAsync("ClientCert: " + context.Connection.ClientCertificate + Environment.NewLine);
+                await context.Response.WriteAsync(Environment.NewLine);
+
+                await context.Response.WriteAsync("User: " + context.User.Identity.Name + Environment.NewLine);
+                var scheme = await authSchemeProvider.GetSchemeAsync(IISDefaults.AuthenticationScheme);
+                await context.Response.WriteAsync("DisplayName: " + scheme?.DisplayName + Environment.NewLine);
+                await context.Response.WriteAsync(Environment.NewLine);
+
+                await context.Response.WriteAsync("Headers:" + Environment.NewLine);
+                foreach (var header in context.Request.Headers)
+                {
+                    await context.Response.WriteAsync(header.Key + ": " + header.Value + Environment.NewLine);
+                }
+                await context.Response.WriteAsync(Environment.NewLine);
+
+                await context.Response.WriteAsync("Environment Variables:" + Environment.NewLine);
+                var vars = Environment.GetEnvironmentVariables();
+                foreach (var key in vars.Keys.Cast<string>().OrderBy(key => key, StringComparer.OrdinalIgnoreCase))
+                {
+                    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.");
+                }
+            });
+        }
+
+        public static void Main(string[] args)
+        {
+            var host = new WebHostBuilder()
+                .ConfigureLogging((_, factory) =>
+                {
+                    factory.AddConsole();
+                    factory.AddFilter("Console", level => level >= LogLevel.Debug);
+                })
+                .UseKestrel()
+                .UseStartup<Startup>()
+                .Build();
+
+            host.Run();
+        }
+    }
+}
+
diff --git a/src/IISIntegration/samples/IISSample/web.config b/src/IISIntegration/samples/IISSample/web.config
new file mode 100644
index 0000000000000000000000000000000000000000..1ee540eb0f76c05ae1db4b2755abeb67ac2421fd
--- /dev/null
+++ b/src/IISIntegration/samples/IISSample/web.config
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<configuration>
+
+  <!-- Configure your application settings in appsettings.json. Learn more at http://go.microsoft.com/fwlink/?LinkId=786380 -->
+
+  <system.webServer>
+    <handlers>
+      <add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModule" resourceType="Unspecified"/>
+    </handlers>
+    <!-- This set of attributes are used for launching the sample using IISExpress via Visual Studio tooling -->
+    <aspNetCore processPath="%LAUNCHER_PATH%" arguments="%LAUNCHER_ARGS%" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" forwardWindowsAuthToken="false"/>
+    
+    <!-- This set of attributes are used for launching the sample for full CLR (net46) without Visual Studio tooling
+    <aspNetCore processPath=".\IISSample.exe" arguments="" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" forwardWindowsAuthToken="false"/>
+    -->
+    
+    <!-- This set of attributes are used for launching the sample for Core CLR (netcoreapp2.0) without Visual Studio tooling
+    <aspNetCore processPath="dotnet" arguments=".\IISSample.dll" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" forwardWindowsAuthToken="false"/>
+    -->
+  </system.webServer>
+</configuration>
diff --git a/src/IISIntegration/samples/NativeIISSample/NativeIISSample.csproj b/src/IISIntegration/samples/NativeIISSample/NativeIISSample.csproj
new file mode 100644
index 0000000000000000000000000000000000000000..d9bf22ba1640d12c4922169761afc9c94bf385e3
--- /dev/null
+++ b/src/IISIntegration/samples/NativeIISSample/NativeIISSample.csproj
@@ -0,0 +1,20 @@
+<Project Sdk="Microsoft.NET.Sdk.Web">
+
+  <Import Project="..\..\build\testsite.props" />
+
+  <PropertyGroup>
+    <TargetFramework>netcoreapp2.1</TargetFramework>
+  </PropertyGroup>
+  
+  <ItemGroup>
+    <ProjectReference Include="..\..\src\Microsoft.AspNetCore.Server.IISIntegration\Microsoft.AspNetCore.Server.IISIntegration.csproj" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <PackageReference Include="Microsoft.AspNetCore.Hosting" Version="$(MicrosoftAspNetCoreHostingPackageVersion)" />
+  </ItemGroup>
+
+  <PropertyGroup>
+    <AspNetCoreModuleHostingModel>inprocess</AspNetCoreModuleHostingModel>
+  </PropertyGroup>
+</Project>
diff --git a/src/IISIntegration/samples/NativeIISSample/Properties/launchSettings.json b/src/IISIntegration/samples/NativeIISSample/Properties/launchSettings.json
new file mode 100644
index 0000000000000000000000000000000000000000..6d5ce43f737ab71fa52d0d89e97557c31e99bdc3
--- /dev/null
+++ b/src/IISIntegration/samples/NativeIISSample/Properties/launchSettings.json
@@ -0,0 +1,37 @@
+{
+  "iisSettings": {
+    "windowsAuthentication": true,
+    "anonymousAuthentication": true,
+    "iisExpress": {
+      "applicationUrl": "http://localhost:5762/",
+      "sslPort": 0
+    }
+  },
+  "profiles": {
+    "ANCM IIS Express": {
+      "commandName": "Executable",
+      "executablePath": "$(IISExpressPath)",
+      "commandLineArgs": "$(IISExpressArguments)",
+      "nativeDebugging": true,
+      "environmentVariables": {
+        "IIS_SITE_PATH": "$(MSBuildThisFileDirectory)",
+        "ANCM_PATH": "$(TargetDir)$(AncmPath)",
+        "LAUNCHER_ARGS": "$(TargetPath)",
+        "ASPNETCORE_ENVIRONMENT": "Development",
+        "LAUNCHER_PATH": "$(DotNetPath)"
+      }
+    },
+    "ANCM IIS": {
+      "commandName": "Executable",
+      "executablePath": "$(IISPath)",
+      "commandLineArgs": "$(IISArguments)",
+      "environmentVariables": {
+        "IIS_SITE_PATH": "$(MSBuildThisFileDirectory)",
+        "ANCM_PATH": "$(TargetDir)$(AncmPath)",
+        "LAUNCHER_ARGS": "$(TargetPath)",
+        "ASPNETCORE_ENVIRONMENT": "Development",
+        "LAUNCHER_PATH": "$(DotNetPath)"
+      }
+    }
+  }
+}
diff --git a/src/IISIntegration/samples/NativeIISSample/Startup.cs b/src/IISIntegration/samples/NativeIISSample/Startup.cs
new file mode 100644
index 0000000000000000000000000000000000000000..d36f26908dfe664f28c68fc0f1b3061757696be1
--- /dev/null
+++ b/src/IISIntegration/samples/NativeIISSample/Startup.cs
@@ -0,0 +1,88 @@
+// 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.Hosting;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Http.Features;
+using Microsoft.AspNetCore.Server.IISIntegration;
+
+namespace NativeIISSample
+{
+    public class Startup
+    {
+        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
+        public void Configure(IApplicationBuilder app, IHostingEnvironment env, IAuthenticationSchemeProvider authSchemeProvider)
+        {
+            app.Run(async (context) =>
+            {
+                context.Response.ContentType = "text/plain";
+
+                await context.Response.WriteAsync("Hello World - " + DateTimeOffset.Now + Environment.NewLine);
+                await context.Response.WriteAsync(Environment.NewLine);
+
+                await context.Response.WriteAsync("Address:" + Environment.NewLine);
+                await context.Response.WriteAsync("Scheme: " + context.Request.Scheme + Environment.NewLine);
+                await context.Response.WriteAsync("Host: " + context.Request.Headers["Host"] + Environment.NewLine);
+                await context.Response.WriteAsync("PathBase: " + context.Request.PathBase.Value + Environment.NewLine);
+                await context.Response.WriteAsync("Path: " + context.Request.Path.Value + Environment.NewLine);
+                await context.Response.WriteAsync("Query: " + context.Request.QueryString.Value + Environment.NewLine);
+                await context.Response.WriteAsync(Environment.NewLine);
+
+                await context.Response.WriteAsync("Connection:" + Environment.NewLine);
+                await context.Response.WriteAsync("RemoteIp: " + context.Connection.RemoteIpAddress + Environment.NewLine);
+                await context.Response.WriteAsync("RemotePort: " + context.Connection.RemotePort + Environment.NewLine);
+                await context.Response.WriteAsync("LocalIp: " + context.Connection.LocalIpAddress + Environment.NewLine);
+                await context.Response.WriteAsync("LocalPort: " + context.Connection.LocalPort + Environment.NewLine);
+                await context.Response.WriteAsync("ClientCert: " + context.Connection.ClientCertificate + Environment.NewLine);
+                await context.Response.WriteAsync(Environment.NewLine);
+
+                await context.Response.WriteAsync("User: " + context.User.Identity.Name + Environment.NewLine);
+                var scheme = await authSchemeProvider.GetSchemeAsync(IISDefaults.AuthenticationScheme);
+                await context.Response.WriteAsync("DisplayName: " + scheme?.DisplayName + Environment.NewLine);
+
+                await context.Response.WriteAsync(Environment.NewLine);
+
+                await context.Response.WriteAsync("Headers:" + Environment.NewLine);
+                foreach (var header in context.Request.Headers)
+                {
+                    await context.Response.WriteAsync(header.Key + ": " + header.Value + Environment.NewLine);
+                }
+                await context.Response.WriteAsync(Environment.NewLine);
+
+                await context.Response.WriteAsync("Environment Variables:" + Environment.NewLine);
+                var vars = Environment.GetEnvironmentVariables();
+                foreach (var key in vars.Keys.Cast<string>().OrderBy(key => key, StringComparer.OrdinalIgnoreCase))
+                {
+                    var value = vars[key];
+                    await context.Response.WriteAsync(key + ": " + value + Environment.NewLine);
+                }
+                await context.Response.WriteAsync(Environment.NewLine);
+
+                // accessing IIS server variables
+                await context.Response.WriteAsync("Server Variables:" + 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.");
+                }
+            });
+        }
+        public static void Main(string[] args)
+        {
+            var host = new WebHostBuilder()
+                .UseIISIntegration()
+                .UseStartup<Startup>()
+                .Build();
+
+            host.Run();
+        }
+    }
+}
diff --git a/src/IISIntegration/samples/NativeIISSample/web.config b/src/IISIntegration/samples/NativeIISSample/web.config
new file mode 100644
index 0000000000000000000000000000000000000000..08baab0922e3c554d7506abc3f976d35d23595eb
--- /dev/null
+++ b/src/IISIntegration/samples/NativeIISSample/web.config
@@ -0,0 +1,9 @@
+<?xml version="1.0"?>
+<configuration>
+  <system.webServer>
+    <handlers>
+      <add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModule" resourceType="Unspecified" />
+    </handlers>
+    <aspNetCore processPath="%LAUNCHER_PATH%" arguments="%LAUNCHER_ARGS%" forwardWindowsAuthToken="false" stdoutLogEnabled="false" hostingModel="inprocess"/>
+  </system.webServer>
+</configuration>
diff --git a/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/AspNetCore.vcxproj b/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/AspNetCore.vcxproj
new file mode 100644
index 0000000000000000000000000000000000000000..e1c11dddb63473e170775e76cc2b1fdb081da78d
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/AspNetCore.vcxproj
@@ -0,0 +1,284 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="..\..\..\Build\Build.Settings" />
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|Win32">
+      <Configuration>Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Debug|x64">
+      <Configuration>Debug</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|x64">
+      <Configuration>Release</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{439824F9-1455-4CC4-BD79-B44FA0A16552}</ProjectGuid>
+    <Keyword>Win32Proj</Keyword>
+    <RootNamespace>AspNetCoreModule</RootNamespace>
+    <ProjectName>AspNetCore</ProjectName>
+    <TargetName>aspnetcore</TargetName>
+    <LinkIncremental>false</LinkIncremental>
+    <WindowsTargetPlatformVersion>10.0.15063.0</WindowsTargetPlatformVersion>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+    <ConfigurationType>DynamicLibrary</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <PlatformToolset>v141</PlatformToolset>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+    <ConfigurationType>DynamicLibrary</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <PlatformToolset>v141</PlatformToolset>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+    <ConfigurationType>DynamicLibrary</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <PlatformToolset>v141</PlatformToolset>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+    <ConfigurationType>DynamicLibrary</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <PlatformToolset>v141</PlatformToolset>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup>
+    <OutDir>$(MSBuildProjectDirectory)\bin\$(Configuration)\$(Platform)\</OutDir>
+  </PropertyGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level4</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;ASPNETCOREMODULE_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <PrecompiledHeaderFile>precomp.hxx</PrecompiledHeaderFile>
+      <PrecompiledHeaderOutputFile>$(IntDir)$(TargetName).pch</PrecompiledHeaderOutputFile>
+      <AdditionalIncludeDirectories>..\IISLib;inc\</AdditionalIncludeDirectories>
+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <SDLCheck>true</SDLCheck>
+      <WholeProgramOptimization>true</WholeProgramOptimization>
+      <PreprocessKeepComments>false</PreprocessKeepComments>
+      <ExceptionHandling>SyncCThrow</ExceptionHandling>
+      <StructMemberAlignment>8Bytes</StructMemberAlignment>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <RuntimeTypeInfo>false</RuntimeTypeInfo>
+      <OmitDefaultLibName>true</OmitDefaultLibName>
+      <CompileAs>CompileAsCpp</CompileAs>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <AdditionalDependencies>kernel32.lib;user32.lib;advapi32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;ahadmin.lib;rpcrt4.lib;winhttp.lib;pdh.lib;ws2_32.lib;wbemuuid.lib;iphlpapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
+      <ModuleDefinitionFile>Source.def</ModuleDefinitionFile>
+    </Link>
+    <ResourceCompile>
+      <AdditionalIncludeDirectories>..\Commonlib</AdditionalIncludeDirectories>
+    </ResourceCompile>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level4</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;ASPNETCOREMODULE_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <PrecompiledHeaderFile>precomp.hxx</PrecompiledHeaderFile>
+      <PrecompiledHeaderOutputFile>$(IntDir)$(TargetName).pch</PrecompiledHeaderOutputFile>
+      <AdditionalIncludeDirectories>..\IISLib;inc\</AdditionalIncludeDirectories>
+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <SDLCheck>true</SDLCheck>
+      <WholeProgramOptimization>true</WholeProgramOptimization>
+      <PreprocessKeepComments>false</PreprocessKeepComments>
+      <ExceptionHandling>SyncCThrow</ExceptionHandling>
+      <StructMemberAlignment>8Bytes</StructMemberAlignment>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <RuntimeTypeInfo>false</RuntimeTypeInfo>
+      <OmitDefaultLibName>true</OmitDefaultLibName>
+      <CompileAs>CompileAsCpp</CompileAs>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <AdditionalDependencies>kernel32.lib;user32.lib;advapi32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;ahadmin.lib;rpcrt4.lib;winhttp.lib;pdh.lib;ws2_32.lib;wbemuuid.lib;iphlpapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
+      <ModuleDefinitionFile>Source.def</ModuleDefinitionFile>
+    </Link>
+    <ResourceCompile>
+      <AdditionalIncludeDirectories>..\Commonlib</AdditionalIncludeDirectories>
+    </ResourceCompile>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <ClCompile>
+      <WarningLevel>Level4</WarningLevel>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <Optimization>MaxSpeed</Optimization>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;ASPNETCOREMODULE_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <AdditionalIncludeDirectories>..\IISLib;inc\</AdditionalIncludeDirectories>
+      <PrecompiledHeaderFile>precomp.hxx</PrecompiledHeaderFile>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <SDLCheck>true</SDLCheck>
+      <WholeProgramOptimization>true</WholeProgramOptimization>
+      <PreprocessKeepComments>false</PreprocessKeepComments>
+      <ExceptionHandling>SyncCThrow</ExceptionHandling>
+      <StructMemberAlignment>8Bytes</StructMemberAlignment>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <RuntimeTypeInfo>false</RuntimeTypeInfo>
+      <OmitDefaultLibName>true</OmitDefaultLibName>
+      <CompileAs>CompileAsCpp</CompileAs>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation>false</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+      <ModuleDefinitionFile>Source.def</ModuleDefinitionFile>
+      <AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;ahadmin.lib;winhttp.lib;odbc32.lib;ws2_32.lib;odbccp32.lib;wbemuuid.lib;iphlpapi.lib;pdh.lib;rpcrt4.lib;%(AdditionalDependencies)</AdditionalDependencies>
+    </Link>
+    <ResourceCompile>
+      <AdditionalIncludeDirectories>..\Commonlib</AdditionalIncludeDirectories>
+    </ResourceCompile>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <ClCompile>
+      <WarningLevel>Level4</WarningLevel>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <Optimization>MaxSpeed</Optimization>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;ASPNETCOREMODULE_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <PrecompiledHeaderFile>precomp.hxx</PrecompiledHeaderFile>
+      <AdditionalIncludeDirectories>..\IISLib;inc\</AdditionalIncludeDirectories>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <SDLCheck>true</SDLCheck>
+      <WholeProgramOptimization>true</WholeProgramOptimization>
+      <PreprocessKeepComments>false</PreprocessKeepComments>
+      <ExceptionHandling>SyncCThrow</ExceptionHandling>
+      <StructMemberAlignment>8Bytes</StructMemberAlignment>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <RuntimeTypeInfo>false</RuntimeTypeInfo>
+      <OmitDefaultLibName>true</OmitDefaultLibName>
+      <CompileAs>CompileAsCpp</CompileAs>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation>false</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+      <ModuleDefinitionFile>Source.def</ModuleDefinitionFile>
+      <AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;ahadmin.lib;rpcrt4.lib;winhttp.lib;pdh.lib;ws2_32.lib;wbemuuid.lib;iphlpapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
+    </Link>
+    <ResourceCompile>
+      <AdditionalIncludeDirectories>..\Commonlib</AdditionalIncludeDirectories>
+    </ResourceCompile>
+  </ItemDefinitionGroup>
+  <ItemGroup>
+    <None Include="Source.def" />
+  </ItemGroup>
+  <ItemGroup>
+    <Content Include="aspnetcore_schema.xml">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+  </ItemGroup>
+  <ItemGroup>
+    <Xml Include="aspnetcore_schema.xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="src\application.cxx" />
+    <ClCompile Include="src\applicationmanager.cxx" />
+    <ClCompile Include="src\aspnetcoreconfig.cxx" />
+    <ClCompile Include="src\filewatcher.cxx" />
+    <ClCompile Include="src\forwarderconnection.cxx" />
+    <ClCompile Include="src\forwardinghandler.cxx" />
+    <ClCompile Include="src\main.cxx" />
+    <ClCompile Include="src\path.cxx" />
+    <ClCompile Include="src\processmanager.cxx" />
+    <ClCompile Include="src\protocolconfig.cxx" />
+    <ClCompile Include="src\proxymodule.cxx" />
+    <ClCompile Include="src\responseheaderhash.cxx" />
+    <ClCompile Include="src\serverprocess.cxx" />
+    <ClCompile Include="src\websockethandler.cxx" />
+    <ClCompile Include="src\winhttphelper.cxx" />
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="Inc\application.h" />
+    <ClInclude Include="Inc\applicationmanager.h" />
+    <ClInclude Include="Inc\aspnetcoreconfig.h" />
+    <ClInclude Include="Inc\debugutil.h" />
+    <ClInclude Include="Inc\environmentvariablehash.h" />
+    <ClInclude Include="Inc\filewatcher.h" />
+    <ClInclude Include="Inc\forwarderconnection.h" />
+    <ClInclude Include="Inc\forwardinghandler.h" />
+    <ClInclude Include="Inc\path.h" />
+    <ClInclude Include="Inc\processmanager.h" />
+    <ClInclude Include="Inc\protocolconfig.h" />
+    <ClInclude Include="Inc\proxymodule.h" />
+    <ClInclude Include="Inc\resource.h" />
+    <ClInclude Include="Inc\responseheaderhash.h" />
+    <ClInclude Include="Inc\serverprocess.h" />
+    <ClInclude Include="Inc\sttimer.h" />
+    <ClInclude Include="Inc\websockethandler.h" />
+    <ClInclude Include="Inc\winhttphelper.h" />
+    <ClInclude Include="resource.h" />
+    <ClInclude Include="src\precomp.hxx" />
+  </ItemGroup>
+  <ItemGroup>
+    <ResourceCompile Include="aspnetcoremodule.rc" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\IISLib\IISLib.vcxproj">
+      <Project>{4787a64f-9a3e-4867-a55a-70cb4b2b2ffe}</Project>
+    </ProjectReference>
+  </ItemGroup>
+  <Import Project="..\..\..\build\native.targets" />
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  </ImportGroup>
+
+  <ItemGroup>
+    <CustomBuild Include="aspnetcore_msg.mc">
+      <FileType>Document</FileType>
+      <Command>mc %(FullPath)</Command>
+      <Message>Compiling Event Messages ...</Message>
+      <Outputs>%(Filename).rc;%(Filename).h;MSG0409.bin</Outputs>
+    </CustomBuild>
+  </ItemGroup>
+</Project>
\ No newline at end of file
diff --git a/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/Inc/application.h b/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/Inc/application.h
new file mode 100644
index 0000000000000000000000000000000000000000..e0ef14ec9cffe9b93583410fd478cdae739ddfd5
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/Inc/application.h
@@ -0,0 +1,293 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#pragma once
+
+//
+// The key used for hash-table lookups, consists of the port on which the http process is created.
+//
+class APPLICATION_KEY
+{
+public:
+
+    APPLICATION_KEY(
+        VOID
+    ) : INLINE_STRU_INIT(m_struKey)
+    {
+    }
+
+    HRESULT
+    Initialize(
+        _In_ LPCWSTR pszKey
+    )
+    {
+        return m_struKey.Copy(pszKey);
+    }
+
+    BOOL
+    GetIsEqual(
+        const APPLICATION_KEY * key2
+    ) const
+    {
+        return m_struKey.Equals(key2->m_struKey);
+    }
+
+    DWORD CalcKeyHash() const
+    {
+        return Hash(m_struKey.QueryStr());
+    }
+
+private:
+
+    INLINE_STRU(m_struKey, 1024);
+};
+
+class APP_OFFLINE_HTM
+{
+public:
+    APP_OFFLINE_HTM(LPCWSTR pszPath) : m_cRefs(1)
+    {
+        m_Path.Copy( pszPath );
+    }
+
+    VOID
+    ReferenceAppOfflineHtm() const
+    {
+        InterlockedIncrement(&m_cRefs);
+    }
+
+    VOID
+    DereferenceAppOfflineHtm() const
+    {
+        if (InterlockedDecrement(&m_cRefs) == 0)
+        {
+            delete this;
+        }
+    }
+
+    BOOL 
+    Load(
+        VOID
+    )
+    {
+        BOOL            fResult = TRUE;
+        LARGE_INTEGER   li = {0};
+        CHAR           *pszBuff = NULL;
+        HANDLE         handle = INVALID_HANDLE_VALUE;
+
+        handle = CreateFile( m_Path.QueryStr(),
+                                     GENERIC_READ,
+                                     FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+                                     NULL,
+                                     OPEN_EXISTING,
+                                     FILE_ATTRIBUTE_NORMAL,
+                                     NULL );
+
+        if( handle == INVALID_HANDLE_VALUE )
+        {
+            if ( GetLastError() == ERROR_FILE_NOT_FOUND )
+            {
+                fResult = FALSE;
+            }
+
+            // This Load() member function is supposed be called only when the change notification event of file creation or file modification happens.
+            // If file is currenlty locked exclusively by other processes, we might get INVALID_HANDLE_VALUE even though the file exists. In that case, we should return TRUE here.
+            goto Finished;
+        }
+    
+        if(!GetFileSizeEx( handle, &li ))
+        {
+            goto Finished;
+        }
+        
+        if( li.HighPart != 0 )
+        {
+            // > 4gb file size not supported
+            // todo: log a warning at event log
+            goto Finished;
+        }
+
+        DWORD bytesRead = 0;
+
+        if(li.LowPart > 0)
+        {
+            pszBuff = new CHAR[ li.LowPart + 1 ];
+
+            if( ReadFile( handle, pszBuff, li.LowPart, &bytesRead, NULL ) )
+            {
+                m_Contents.Copy( pszBuff, bytesRead );
+            }
+        }
+
+Finished:
+        if( handle != INVALID_HANDLE_VALUE )
+        {
+            CloseHandle(handle);
+            handle = INVALID_HANDLE_VALUE;
+        }
+
+        if( pszBuff != NULL )
+        {
+            delete[] pszBuff;
+            pszBuff = NULL;
+        }
+
+        return fResult;
+    }
+
+    mutable LONG        m_cRefs;
+    STRA                m_Contents;
+    STRU                m_Path;
+};
+
+class APPLICATION_MANAGER;
+
+class APPLICATION
+{
+public:
+
+    APPLICATION() : m_pProcessManager(NULL), m_pApplicationManager(NULL), m_cRefs(1), 
+        m_fAppOfflineFound(FALSE), m_pAppOfflineHtm(NULL), m_pFileWatcherEntry(NULL)
+    {
+    }
+
+    APPLICATION_KEY *
+    QueryApplicationKey()
+    {
+        return &m_applicationKey;
+    }
+
+    VOID
+    SetAppOfflineFound(
+        BOOL found
+    )
+    {
+        m_fAppOfflineFound = found;
+    }
+
+    BOOL
+    AppOfflineFound()
+    {
+        return m_fAppOfflineFound;
+    }
+
+    HRESULT
+    GetProcess(
+        _In_    IHttpContext          *context,
+        _In_    ASPNETCORE_CONFIG     *pConfig,
+        _Out_   SERVER_PROCESS       **ppServerProcess
+    )
+    {
+        return m_pProcessManager->GetProcess( context, pConfig, ppServerProcess );
+    }
+
+    HRESULT
+    Recycle()
+    {
+        HRESULT hr = S_OK;
+        m_pProcessManager->ShutdownAllProcesses();
+        return hr;
+    }
+
+    VOID
+    ReferenceApplication() const
+    {
+        InterlockedIncrement(&m_cRefs);
+    }
+
+    VOID
+    DereferenceApplication() const
+    {
+        if (InterlockedDecrement(&m_cRefs) == 0)
+        {
+            delete this;
+        }
+    }
+
+    APP_OFFLINE_HTM* QueryAppOfflineHtm()
+    {
+        return m_pAppOfflineHtm;
+    }
+
+    ~APPLICATION();
+
+    HRESULT
+    Initialize(
+        _In_ APPLICATION_MANAGER *pApplicationManager,
+        _In_ LPCWSTR  pszApplication,
+        _In_ LPCWSTR  pszPhysicalPath
+    );
+
+    VOID
+    UpdateAppOfflineFileHandle();
+
+    HRESULT
+    StartMonitoringAppOffline();
+
+private:
+
+    STRU                 m_strAppPhysicalPath;
+    mutable LONG         m_cRefs;
+    APPLICATION_KEY      m_applicationKey;
+    PROCESS_MANAGER*     m_pProcessManager;
+    APPLICATION_MANAGER *m_pApplicationManager;
+    BOOL                 m_fAppOfflineFound;
+    APP_OFFLINE_HTM     *m_pAppOfflineHtm;
+    FILE_WATCHER_ENTRY  *m_pFileWatcherEntry;
+};
+
+class APPLICATION_HASH :
+    public HASH_TABLE<APPLICATION, APPLICATION_KEY *>
+{
+
+public:
+
+    APPLICATION_HASH()
+    {}
+
+    APPLICATION_KEY *
+    ExtractKey(
+        APPLICATION *pApplication
+    )
+    {
+        return pApplication->QueryApplicationKey();
+    }
+
+    DWORD
+    CalcKeyHash(
+        APPLICATION_KEY *key
+    )
+    {
+        return key->CalcKeyHash();
+    }
+
+    BOOL
+    EqualKeys(
+        APPLICATION_KEY *key1,
+        APPLICATION_KEY *key2
+    )
+    {
+        return key1->GetIsEqual(key2);
+    }
+
+    VOID
+    ReferenceRecord(
+        APPLICATION *pApplication
+    )
+    {
+        pApplication->ReferenceApplication();
+    }
+
+    VOID
+    DereferenceRecord(
+        APPLICATION *pApplication
+    )
+    {
+        pApplication->DereferenceApplication();
+    }
+
+private:
+
+    APPLICATION_HASH(const APPLICATION_HASH &);
+    void operator=(const APPLICATION_HASH &);
+};
\ No newline at end of file
diff --git a/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/Inc/applicationmanager.h b/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/Inc/applicationmanager.h
new file mode 100644
index 0000000000000000000000000000000000000000..d9e626262d861322e78e5dae37e6bbee681444e1
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/Inc/applicationmanager.h
@@ -0,0 +1,158 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#pragma once
+
+#define DEFAULT_HASH_BUCKETS 293
+
+class APPLICATION_MANAGER
+{
+public:
+
+    static 
+    APPLICATION_MANAGER*
+    GetInstance(
+        VOID
+    )
+    {
+        if( sm_pApplicationManager == NULL )
+        {
+            sm_pApplicationManager = new APPLICATION_MANAGER();
+        }
+
+        return  sm_pApplicationManager;
+    }
+
+    static
+    VOID
+    Cleanup(
+        VOID
+    )
+    {
+        if(sm_pApplicationManager != NULL)
+        {
+            delete sm_pApplicationManager;
+            sm_pApplicationManager = NULL;
+        }
+    }
+
+    HRESULT
+    GetApplication(
+        _In_ IHttpContext*         pContext,
+        _Out_ APPLICATION **       ppApplication
+    );
+
+    HRESULT
+    RecycleApplication( 
+        _In_ LPCWSTR pszApplication 
+    );
+
+    HRESULT
+    Get502ErrorPage(
+        _Out_ HTTP_DATA_CHUNK**     ppErrorPage
+    );
+
+    ~APPLICATION_MANAGER()
+    {
+        if(m_pApplicationHash != NULL)
+        {
+            m_pApplicationHash->Clear();
+            delete m_pApplicationHash;
+            m_pApplicationHash = NULL;
+        }
+
+        if( m_pFileWatcher!= NULL )
+        {
+            delete m_pFileWatcher;
+            m_pFileWatcher = NULL;
+        }
+
+        if(m_pHttp502ErrorPage != NULL)
+        {
+            delete m_pHttp502ErrorPage;
+            m_pHttp502ErrorPage = NULL;
+        }
+
+    }
+
+    FILE_WATCHER*
+    GetFileWatcher()
+    {
+        return m_pFileWatcher;
+    }
+
+    HRESULT Initialize()
+    {
+        HRESULT hr = S_OK;
+
+        if(m_pApplicationHash == NULL)
+        {
+            m_pApplicationHash = new APPLICATION_HASH();
+            if(m_pApplicationHash == NULL)
+            {
+                hr = E_OUTOFMEMORY;
+                goto Finished;
+            }
+
+            hr = m_pApplicationHash->Initialize(DEFAULT_HASH_BUCKETS);
+            if(FAILED(hr))
+            {
+                goto Finished;
+            }
+        }
+
+        if( m_pFileWatcher == NULL )
+        {
+            m_pFileWatcher = new FILE_WATCHER;
+            if(m_pFileWatcher == NULL)
+            {
+                hr = HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
+                goto Finished;
+            }
+
+            m_pFileWatcher->Create();
+        }
+
+    Finished:
+        return hr;
+    }
+
+private:
+    //
+    // we currently limit the size of m_pstrErrorInfo to 5000, be careful if you want to change its payload
+    // 
+    APPLICATION_MANAGER() : m_pApplicationHash(NULL), m_pFileWatcher(NULL), m_pHttp502ErrorPage(NULL), m_pstrErrorInfo(
+        "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\"> \
+        <html xmlns=\"http://www.w3.org/1999/xhtml\"> \
+        <head> \
+        <meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\" /> \
+        <title> IIS 502.5 Error </title><style type=\"text/css\"></style></head> \
+        <body> <div id = \"content\"> \
+          <div class = \"content-container\"><h3> HTTP Error 502.5 - Process Failure </h3></div>  \
+          <div class = \"content-container\"> \
+           <fieldset> <h4> Common causes of this issue: </h4> \
+            <ul><li> The application process failed to start </li> \
+             <li> The application process started but then stopped </li> \
+             <li> The application process started but failed to listen on the configured port </li></ul></fieldset> \
+          </div> \
+          <div class = \"content-container\"> \
+            <fieldset><h4> Troubleshooting steps: </h4> \
+             <ul><li> Check the system event log for error messages </li> \
+             <li> Enable logging the application process' stdout messages </li> \
+             <li> Attach a debugger to the application process and inspect </li></ul></fieldset> \
+             <fieldset><h4> For more information visit: \
+             <a href=\"https://go.microsoft.com/fwlink/?linkid=808681\"> <cite> https://go.microsoft.com/fwlink/?LinkID=808681 </cite></a></h4> \
+             </fieldset> \
+          </div> \
+       </div></body></html>")
+    {
+        InitializeSRWLock(&m_srwLock);
+    }
+
+    FILE_WATCHER               *m_pFileWatcher;
+    APPLICATION_HASH           *m_pApplicationHash;
+    static APPLICATION_MANAGER *sm_pApplicationManager;
+    SRWLOCK                     m_srwLock;
+    HTTP_DATA_CHUNK            *m_pHttp502ErrorPage;
+    LPSTR                      m_pstrErrorInfo;
+};
diff --git a/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/Inc/aspnetcoreconfig.h b/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/Inc/aspnetcoreconfig.h
new file mode 100644
index 0000000000000000000000000000000000000000..95b4303cee6fd20bb4d6da109abbf07771e72858
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/Inc/aspnetcoreconfig.h
@@ -0,0 +1,207 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#pragma once
+#define CS_ROOTWEB_CONFIG                                L"MACHINE/WEBROOT/APPHOST/"
+#define CS_ROOTWEB_CONFIG_LEN                            _countof(CS_ROOTWEB_CONFIG)-1
+#define CS_ASPNETCORE_SECTION                            L"system.webServer/aspNetCore"
+#define CS_WINDOWS_AUTHENTICATION_SECTION                L"system.webServer/security/authentication/windowsAuthentication"
+#define CS_BASIC_AUTHENTICATION_SECTION                  L"system.webServer/security/authentication/basicAuthentication"
+#define CS_ANONYMOUS_AUTHENTICATION_SECTION              L"system.webServer/security/authentication/anonymousAuthentication"
+#define CS_AUTHENTICATION_ENABLED                        L"enabled"
+#define CS_ASPNETCORE_PROCESS_EXE_PATH                   L"processPath"
+#define CS_ASPNETCORE_PROCESS_ARGUMENTS                  L"arguments"
+#define CS_ASPNETCORE_PROCESS_STARTUP_TIME_LIMIT         L"startupTimeLimit"
+#define CS_ASPNETCORE_PROCESS_SHUTDOWN_TIME_LIMIT        L"shutdownTimeLimit"
+#define CS_ASPNETCORE_WINHTTP_REQUEST_TIMEOUT            L"requestTimeout"
+#define CS_ASPNETCORE_RAPID_FAILS_PER_MINUTE             L"rapidFailsPerMinute"
+#define CS_ASPNETCORE_STDOUT_LOG_ENABLED                 L"stdoutLogEnabled"
+#define CS_ASPNETCORE_STDOUT_LOG_FILE                    L"stdoutLogFile"
+#define CS_ASPNETCORE_ENVIRONMENT_VARIABLES              L"environmentVariables"
+#define CS_ASPNETCORE_ENVIRONMENT_VARIABLE               L"environmentVariable"
+#define CS_ASPNETCORE_ENVIRONMENT_VARIABLE_NAME          L"name"
+#define CS_ASPNETCORE_ENVIRONMENT_VARIABLE_VALUE         L"value"
+#define CS_ASPNETCORE_PROCESSES_PER_APPLICATION          L"processesPerApplication"
+#define CS_ASPNETCORE_FORWARD_WINDOWS_AUTH_TOKEN         L"forwardWindowsAuthToken"
+#define CS_ASPNETCORE_DISABLE_START_UP_ERROR_PAGE        L"disableStartUpErrorPage"
+#define CS_ASPNETCORE_RECYCLE_ON_FILE_CHANGE             L"recycleOnFileChange"
+#define CS_ASPNETCORE_RECYCLE_ON_FILE_CHANGE_FILE        L"file"
+#define CS_ASPNETCORE_RECYCLE_ON_FILE_CHANGE_FILE_PATH   L"path"
+
+#define MAX_RAPID_FAILS_PER_MINUTE 100
+#define MILLISECONDS_IN_ONE_SECOND 1000
+#define MIN_PORT                   1025
+#define MAX_PORT                   48000
+
+#define HEX_TO_ASCII(c) ((CHAR)(((c) < 10) ? ((c) + '0') : ((c) + 'a' - 10)))
+
+extern HTTP_MODULE_ID   g_pModuleId;
+extern IHttpServer *    g_pHttpServer;
+
+class ASPNETCORE_CONFIG : IHttpStoredContext
+{
+public:
+
+    virtual
+    ~ASPNETCORE_CONFIG();
+
+    VOID
+    CleanupStoredContext()
+    {
+        delete this;
+    }
+
+    static
+    HRESULT
+    GetConfig(
+        _In_  IHttpContext           *pHttpContext,
+        _Out_ ASPNETCORE_CONFIG  **ppAspNetCoreConfig
+    );
+    
+    ENVIRONMENT_VAR_HASH*
+    QueryEnvironmentVariables(
+        VOID
+    )
+    {
+        return m_pEnvironmentVariables;
+    }
+
+    DWORD
+    QueryRapidFailsPerMinute(
+        VOID
+    )
+    {
+        return m_dwRapidFailsPerMinute;
+    }
+
+    DWORD
+    QueryStartupTimeLimitInMS(
+        VOID
+    )
+    {
+        return m_dwStartupTimeLimitInMS;
+    }
+
+    DWORD
+    QueryShutdownTimeLimitInMS(
+        VOID
+    )
+    {
+        return m_dwShutdownTimeLimitInMS;
+    }
+
+    DWORD
+    QueryProcessesPerApplication(
+        VOID
+    )
+    {
+        return m_dwProcessesPerApplication;
+    }
+
+    DWORD
+    QueryRequestTimeoutInMS(
+        VOID
+    )
+    {
+        return m_dwRequestTimeoutInMS;
+    }
+
+    STRU*
+    QueryArguments(
+        VOID
+    )
+    {
+        return &m_struArguments;
+    }
+
+    STRU*
+    QueryApplicationPath(
+        VOID
+        )
+    {
+        return &m_struApplication;
+    }
+
+    STRU*
+    QueryProcessPath(
+        VOID
+    )
+    {
+        return &m_struProcessPath;
+    }
+
+    BOOL
+    QueryStdoutLogEnabled()
+    {
+        return m_fStdoutLogEnabled;
+    }
+
+    BOOL
+    QueryForwardWindowsAuthToken()
+    {
+        return m_fForwardWindowsAuthToken;
+    }
+
+    BOOL
+    QueryWindowsAuthEnabled()
+    {
+        return m_fWindowsAuthEnabled;
+    }
+
+    BOOL
+    QueryBasicAuthEnabled()
+    {
+        return m_fBasicAuthEnabled;
+    }
+
+    BOOL
+    QueryAnonymousAuthEnabled()
+    {
+        return m_fAnonymousAuthEnabled;
+    }
+
+    BOOL
+    QueryDisableStartUpErrorPage()
+    {
+        return m_fDisableStartUpErrorPage;
+    }
+
+    STRU*
+    QueryStdoutLogFile()
+    {
+        return &m_struStdoutLogFile;
+    }
+
+private:
+
+    //
+    // private constructor
+    //    
+    ASPNETCORE_CONFIG():
+        m_fStdoutLogEnabled( FALSE ),
+        m_pEnvironmentVariables( NULL )
+    {
+    }
+
+    HRESULT
+    Populate(
+        IHttpContext *pHttpContext
+    );
+
+    DWORD                  m_dwRequestTimeoutInMS;
+    DWORD                  m_dwStartupTimeLimitInMS;
+    DWORD                  m_dwShutdownTimeLimitInMS;
+    DWORD                  m_dwRapidFailsPerMinute;
+    DWORD                  m_dwProcessesPerApplication;
+    STRU                   m_struApplication;
+    STRU                   m_struArguments;
+    STRU                   m_struProcessPath;
+    STRU                   m_struStdoutLogFile;
+    BOOL                   m_fStdoutLogEnabled;
+    BOOL                   m_fForwardWindowsAuthToken;
+    BOOL                   m_fDisableStartUpErrorPage;
+    BOOL                   m_fWindowsAuthEnabled;
+    BOOL                   m_fBasicAuthEnabled;
+    BOOL                   m_fAnonymousAuthEnabled;
+    ENVIRONMENT_VAR_HASH*  m_pEnvironmentVariables;
+};
diff --git a/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/Inc/debugutil.h b/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/Inc/debugutil.h
new file mode 100644
index 0000000000000000000000000000000000000000..7378462efb5b6a066c2f3c8e07ac6e3b75ecbf01
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/Inc/debugutil.h
@@ -0,0 +1,82 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#pragma once
+
+#define ASPNETCORE_DEBUG_FLAG_INFO          0x00000001
+#define ASPNETCORE_DEBUG_FLAG_WARNING       0x00000002
+#define ASPNETCORE_DEBUG_FLAG_ERROR         0x00000004
+
+extern DWORD g_dwAspNetCoreDebugFlags;
+
+static
+BOOL
+IfDebug(
+    DWORD   dwFlag
+    )
+{
+    return ( dwFlag & g_dwAspNetCoreDebugFlags );
+}
+
+static
+VOID
+DebugPrint(
+    DWORD   dwFlag,
+    LPCSTR  szString
+    )
+{
+    STACK_STRA (strOutput, 256);
+    HRESULT  hr = S_OK;
+
+    if ( IfDebug( dwFlag ) )
+    {
+        hr = strOutput.SafeSnprintf( 
+            "[aspnetcore.dll] %s\r\n",
+            szString );
+
+        if (FAILED (hr))
+        {
+            goto Finished;
+        }
+
+        OutputDebugStringA( strOutput.QueryStr() );
+    }
+
+Finished:
+
+    return;
+}
+
+static
+VOID
+DebugPrintf(
+DWORD   dwFlag,
+LPCSTR  szFormat,
+...
+)
+{
+    STACK_STRA (strCooked,256);
+
+    va_list  args;
+    HRESULT hr = S_OK;
+
+    if ( IfDebug( dwFlag ) )
+    {
+        va_start( args, szFormat );
+
+        hr = strCooked.SafeVsnprintf(szFormat, args );
+
+        va_end( args );
+
+        if (FAILED (hr))
+        {
+            goto Finished;
+        }
+
+        DebugPrint( dwFlag, strCooked.QueryStr() );
+    }
+
+Finished:
+    return;
+}
+
diff --git a/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/Inc/environmentvariablehash.h b/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/Inc/environmentvariablehash.h
new file mode 100644
index 0000000000000000000000000000000000000000..062090ac17239206c48ab68162275d693c95ada2
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/Inc/environmentvariablehash.h
@@ -0,0 +1,155 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#pragma once
+
+//
+// The key used for hash-table lookups, consists of the port on which the http process is created.
+//
+
+class ENVIRONMENT_VAR_ENTRY
+{
+public:
+    ENVIRONMENT_VAR_ENTRY():
+        _cRefs(1)
+    {
+    }
+
+    HRESULT
+    Initialize(
+        PCWSTR      pszName,
+        PCWSTR      pszValue
+    )
+    {
+        HRESULT hr = S_OK;
+        if (FAILED(hr = _strName.Copy(pszName)) ||
+            FAILED(hr = _strValue.Copy(pszValue))) 
+        {
+        }
+        return hr;
+    }
+
+    VOID 
+    Reference() const
+    {
+        InterlockedIncrement(&_cRefs);
+    }
+
+    VOID
+    Dereference() const
+    {
+        if (InterlockedDecrement(&_cRefs) == 0)
+        {
+            delete this;
+        }
+    }
+
+    PWSTR  const
+    QueryName()
+    {
+        return _strName.QueryStr();
+    }
+
+    PWSTR const
+    QueryValue()
+    {
+        return _strValue.QueryStr();
+    }
+
+private:
+    ~ENVIRONMENT_VAR_ENTRY()
+    {
+    }
+
+    STRU                _strName;
+    STRU                _strValue;
+    mutable LONG        _cRefs;
+};
+
+class ENVIRONMENT_VAR_HASH : public HASH_TABLE<ENVIRONMENT_VAR_ENTRY, PWSTR>
+{
+public:
+    ENVIRONMENT_VAR_HASH() 
+    {}
+
+    PWSTR
+    ExtractKey(
+        ENVIRONMENT_VAR_ENTRY *   pEntry
+        )
+    {
+        return pEntry->QueryName();
+    }
+
+    DWORD
+    CalcKeyHash(
+        PWSTR   pszName
+    )
+    {
+        return HashStringNoCase(pszName);
+    }
+
+    BOOL
+    EqualKeys(
+        PWSTR   pszName1,
+        PWSTR   pszName2
+    )
+    {
+        return (_wcsicmp(pszName1, pszName2) == 0);
+    }
+
+    VOID
+    ReferenceRecord(
+        ENVIRONMENT_VAR_ENTRY *   pEntry
+    )
+    {
+        pEntry->Reference();
+    }
+
+    VOID
+    DereferenceRecord(
+        ENVIRONMENT_VAR_ENTRY *   pEntry
+    )
+    {
+        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();
+        }
+    }
+
+private:
+    ENVIRONMENT_VAR_HASH(const ENVIRONMENT_VAR_HASH &);
+    void operator=(const ENVIRONMENT_VAR_HASH &);
+};
diff --git a/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/Inc/filewatcher.h b/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/Inc/filewatcher.h
new file mode 100644
index 0000000000000000000000000000000000000000..16d3942a2f2f013a8c4c4acf67371e3aa239f425
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/Inc/filewatcher.h
@@ -0,0 +1,126 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#pragma once
+
+#define FILE_WATCHER_SHUTDOWN_KEY           (ULONG_PTR)(-1)
+#define FILE_WATCHER_ENTRY_BUFFER_SIZE      4096
+#ifndef CONTAINING_RECORD
+//
+// Calculate the address of the base of the structure given its type, and an
+// address of a field within the structure.
+//
+
+#define CONTAINING_RECORD(address, type, field) \
+    ((type *)((PCHAR)(address)-(ULONG_PTR)(&((type *)0)->field)))
+
+#endif // !CONTAINING_RECORD
+#define FILE_NOTIFY_VALID_MASK          0x00000fff
+#define FILE_WATCHER_ENTRY_SIGNATURE       ((DWORD) 'FWES')
+#define FILE_WATCHER_ENTRY_SIGNATURE_FREE  ((DWORD) 'sewf')
+
+class APPLICATION;
+
+class FILE_WATCHER{
+public:
+
+    FILE_WATCHER();
+
+    ~FILE_WATCHER();
+
+    HRESULT Create();
+
+    HANDLE
+    QueryCompletionPort(
+        VOID
+    ) const
+    {
+        return m_hCompletionPort;
+    }
+
+    static
+    DWORD
+    WINAPI ChangeNotificationThread(LPVOID);
+
+    static
+    void
+    WINAPI FileWatcherCompletionRoutine
+    (
+        DWORD                   dwCompletionStatus,
+        DWORD                   cbCompletion,
+        OVERLAPPED *            pOverlapped
+    );
+
+private:
+    HANDLE               m_hCompletionPort;
+    HANDLE               m_hChangeNotificationThread;
+};
+
+class FILE_WATCHER_ENTRY
+{
+public:
+    FILE_WATCHER_ENTRY(FILE_WATCHER *   pFileMonitor);
+
+    OVERLAPPED    _overlapped;
+
+    HRESULT
+    Create(
+        _In_ PCWSTR                  pszDirectoryToMonitor,
+        _In_ PCWSTR                  pszFileNameToMonitor,
+        _In_ APPLICATION*            pApplication,
+        _In_ HANDLE                  hImpersonationToken
+        );
+
+    VOID
+    ReferenceFileWatcherEntry() const
+    {
+        InterlockedIncrement(&_cRefs);
+    }
+
+    VOID
+    DereferenceFileWatcherEntry() const
+    {
+        if (InterlockedDecrement(&_cRefs) == 0)
+        {
+            delete this;
+        }
+    }
+
+    BOOL
+    QueryIsValid() const
+    {
+        return _fIsValid;
+    }
+
+    VOID
+    MarkEntryInValid()
+    {
+        _fIsValid = FALSE;
+    }
+
+    HRESULT Monitor();
+
+    VOID StopMonitor();
+
+    HRESULT
+    HandleChangeCompletion(
+        _In_ DWORD          dwCompletionStatus,
+        _In_ DWORD          cbCompletion
+        );
+
+private:
+    virtual ~FILE_WATCHER_ENTRY();
+
+    DWORD                   _dwSignature;
+    BUFFER                  _buffDirectoryChanges;
+    HANDLE                  _hImpersonationToken;
+    HANDLE                  _hDirectory;
+    FILE_WATCHER*           _pFileMonitor;
+    APPLICATION*            _pApplication;
+    STRU                    _strFileName;
+    STRU                    _strDirectoryName;
+    LONG                    _lStopMonitorCalled;
+    mutable LONG            _cRefs;
+    BOOL                    _fIsValid;
+    SRWLOCK                 _srwLock;
+};
diff --git a/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/Inc/forwarderconnection.h b/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/Inc/forwarderconnection.h
new file mode 100644
index 0000000000000000000000000000000000000000..a3f5dfdabe91c000e3c7df183c13785e69f49097
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/Inc/forwarderconnection.h
@@ -0,0 +1,157 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#pragma once
+
+//
+// The key used for hash-table lookups, consists of the port on which the http process is created.
+//
+class FORWARDER_CONNECTION_KEY
+{
+public:
+
+    FORWARDER_CONNECTION_KEY(
+        VOID
+    )
+    {
+    }
+
+    HRESULT
+    Initialize(
+        _In_ DWORD  dwPort
+    )
+    {
+        m_dwPort = dwPort;
+        return S_OK;
+    }
+
+    BOOL
+    GetIsEqual(
+        const FORWARDER_CONNECTION_KEY * key2
+    ) const
+    {
+        return m_dwPort == key2->m_dwPort;
+    }
+
+    DWORD CalcKeyHash() const
+    {
+        // TODO: Review hash distribution.
+        return Hash(m_dwPort);
+    }
+
+private:
+
+    DWORD      m_dwPort;
+};
+
+class FORWARDER_CONNECTION
+{
+public:
+
+    FORWARDER_CONNECTION(
+        VOID
+    );
+
+    HRESULT
+    Initialize(
+        DWORD   dwPort
+    );
+
+    HINTERNET
+    QueryHandle() const
+    {
+        return m_hConnection;
+    }
+
+    VOID
+    ReferenceForwarderConnection() const
+    {
+        InterlockedIncrement(&m_cRefs);
+    }
+
+    VOID
+    DereferenceForwarderConnection() const
+    {
+        if (InterlockedDecrement(&m_cRefs) == 0)
+        {
+            delete this;
+        }
+    }
+
+    FORWARDER_CONNECTION_KEY *
+    QueryConnectionKey()
+    {
+        return &m_ConnectionKey;
+    }
+
+private:
+
+    ~FORWARDER_CONNECTION()
+    {
+        if (m_hConnection != NULL)
+        {
+            WinHttpCloseHandle(m_hConnection);
+            m_hConnection = NULL;
+        }
+    }
+
+    mutable LONG                m_cRefs;
+    FORWARDER_CONNECTION_KEY    m_ConnectionKey;
+    HINTERNET                   m_hConnection;
+};
+
+class FORWARDER_CONNECTION_HASH :
+    public HASH_TABLE<FORWARDER_CONNECTION, FORWARDER_CONNECTION_KEY *>
+{
+
+public:
+
+    FORWARDER_CONNECTION_HASH()
+    {}
+
+    FORWARDER_CONNECTION_KEY *
+    ExtractKey(
+        FORWARDER_CONNECTION *pConnection
+    )
+    {
+        return pConnection->QueryConnectionKey();
+    }
+
+    DWORD
+    CalcKeyHash(
+        FORWARDER_CONNECTION_KEY *key
+    )
+    {
+        return key->CalcKeyHash();
+    }
+
+    BOOL
+    EqualKeys(
+        FORWARDER_CONNECTION_KEY *key1,
+        FORWARDER_CONNECTION_KEY *key2
+    )
+    {
+        return key1->GetIsEqual(key2);
+    }
+
+    VOID
+    ReferenceRecord(
+        FORWARDER_CONNECTION *pConnection
+    )
+    {
+        pConnection->ReferenceForwarderConnection();
+    }
+
+    VOID
+    DereferenceRecord(
+        FORWARDER_CONNECTION *pConnection
+    )
+    {
+        pConnection->DereferenceForwarderConnection();
+    }
+
+private:
+
+    FORWARDER_CONNECTION_HASH(const FORWARDER_CONNECTION_HASH &);
+    void operator=(const FORWARDER_CONNECTION_HASH &);
+};
\ No newline at end of file
diff --git a/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/Inc/forwardinghandler.h b/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/Inc/forwardinghandler.h
new file mode 100644
index 0000000000000000000000000000000000000000..dcd8531dac04065924620983ce7aa027b2d084cb
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/Inc/forwardinghandler.h
@@ -0,0 +1,468 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#pragma once
+
+#include "forwarderconnection.h"
+#include "protocolconfig.h"
+#include "serverprocess.h"
+#include "application.h"
+#include "tracelog.h"
+#include "websockethandler.h"
+
+#define ASPNETCORE_DEBUG_STRU_BUFFER_SIZE    100
+#define ASPNETCORE_DEBUG_STRU_ARRAY_SIZE     100
+
+enum FORWARDING_REQUEST_STATUS
+{
+    FORWARDER_START,
+    FORWARDER_SENDING_REQUEST,
+    FORWARDER_RECEIVING_RESPONSE,
+    FORWARDER_RECEIVED_WEBSOCKET_RESPONSE,
+    FORWARDER_RESET_CONNECTION,
+    FORWARDER_DONE
+};
+
+extern HTTP_MODULE_ID   g_pModuleId;
+extern IHttpServer *    g_pHttpServer;
+extern BOOL             g_fAsyncDisconnectAvailable;
+extern PCWSTR           g_pszModuleName;
+extern HMODULE          g_hModule;
+extern HMODULE          g_hWinHttpModule;
+extern DWORD            g_dwTlsIndex;
+extern DWORD            g_OptionalWinHttpFlags;
+
+#ifdef DEBUG
+extern STRA             g_strLogs[ASPNETCORE_DEBUG_STRU_ARRAY_SIZE];
+extern DWORD            g_dwLogCounter;
+#endif // DEBUG
+
+enum MULTI_PART_POSITION
+{
+    MULTI_PART_IN_BOUNDARY,
+    MULTI_PART_IN_HEADER,
+    MULTI_PART_IN_CHUNK,
+    MULTI_PART_IN_CHUNK_END
+};
+
+class ASYNC_DISCONNECT_CONTEXT;
+
+#define FORWARDING_HANDLER_SIGNATURE        ((DWORD)'FHLR')
+#define FORWARDING_HANDLER_SIGNATURE_FREE   ((DWORD)'fhlr')
+
+class FORWARDING_HANDLER
+{
+public:
+    
+    FORWARDING_HANDLER(
+        __in IHttpContext * pW3Context
+    );
+
+    static void * operator new(size_t size);
+
+    static void operator delete(void * pMemory);
+
+    VOID
+    ReferenceForwardingHandler(
+        VOID
+    ) const;
+
+    VOID
+    DereferenceForwardingHandler(
+        VOID
+    ) const;
+
+    REQUEST_NOTIFICATION_STATUS
+    OnExecuteRequestHandler();
+
+    REQUEST_NOTIFICATION_STATUS
+    OnAsyncCompletion(
+        DWORD                   cbCompletion,
+        HRESULT                 hrCompletionStatus
+    );
+
+    IHttpTraceContext *
+    QueryTraceContext()
+    {
+        return m_pW3Context->GetTraceContext();
+    }
+    
+    IHttpContext *
+    QueryHttpContext(
+        VOID
+        )
+    {
+        return m_pW3Context;
+    }
+
+    static
+    VOID
+    CALLBACK
+    OnWinHttpCompletion(
+        HINTERNET   hRequest,
+        DWORD_PTR   dwContext,
+        DWORD       dwInternetStatus,
+        LPVOID      lpvStatusInformation,
+        DWORD       dwStatusInformationLength
+    )
+    {
+
+        FORWARDING_HANDLER * pThis = static_cast<FORWARDING_HANDLER *>(reinterpret_cast<PVOID>(dwContext));
+        if (pThis == NULL)
+        {
+            //error happened, nothing can be done here
+            return;
+        }
+        DBG_ASSERT(pThis->m_Signature == FORWARDING_HANDLER_SIGNATURE);
+        pThis->OnWinHttpCompletionInternal(hRequest,
+                                           dwInternetStatus,
+                                           lpvStatusInformation,
+                                           dwStatusInformationLength);
+    }
+
+    static
+    HRESULT
+    StaticInitialize(
+        BOOL fEnableReferenceCountTracing 
+    );
+
+    static
+    VOID
+    StaticTerminate();
+
+    static
+    PCWSTR
+    QueryErrorFormat()
+    {
+        return sm_strErrorFormat.QueryStr();
+    }
+
+    static
+    HANDLE
+    QueryEventLog()
+    {
+        return sm_hEventLog;
+    }
+
+    VOID
+    TerminateRequest(
+        BOOL    fClientInitiated
+    );
+
+    static HINTERNET                    sm_hSession;
+
+    HRESULT
+    SetStatusAndHeaders(
+        PCSTR               pszHeaders,
+        DWORD               cchHeaders
+    );
+
+    HRESULT
+    OnSharedRequestEntity(
+        ULONGLONG   ulOffset,
+        LPCBYTE     pvBuffer,
+        DWORD       cbBuffer
+    );
+
+    VOID
+    SetStatus(
+        FORWARDING_REQUEST_STATUS status
+        )
+    {
+        m_RequestStatus = status;
+    }
+
+    virtual
+    ~FORWARDING_HANDLER(
+        VOID
+    );
+
+private:
+
+    //
+    // Begin OnMapRequestHandler phases.
+    //
+
+    HRESULT
+    CreateWinHttpRequest(
+        __in const IHttpRequest *       pRequest,
+        __in const PROTOCOL_CONFIG *    pProtocol,
+        __in HINTERNET                  hConnect,
+        __inout STRU *                  pstrUrl,
+        ASPNETCORE_CONFIG*              pAspNetCoreConfig,
+        SERVER_PROCESS*                 pServerProcess
+    );
+
+    //
+    // End OnMapRequestHandler phases.
+    //
+
+    VOID
+    RemoveRequest();
+
+    HRESULT
+    GetHeaders(
+        const PROTOCOL_CONFIG * pProtocol,
+        PCWSTR *                ppszHeaders,
+        DWORD *                 pcchHeaders,
+        ASPNETCORE_CONFIG*      pAspNetCoreConfig,
+        SERVER_PROCESS*         pServerProcess
+    );
+
+    HRESULT
+    DoReverseRewrite(
+        __in IHttpResponse *pResponse
+    );
+
+    BYTE *
+    GetNewResponseBuffer(
+        DWORD   dwBufferSize
+    );
+
+    VOID
+    FreeResponseBuffers();
+
+    VOID
+    OnWinHttpCompletionInternal(
+        HINTERNET   hRequest,
+        DWORD       dwInternetStatus,
+        LPVOID      lpvStatusInformation,
+        DWORD       dwStatusInformationLength
+    );
+
+    HRESULT
+    OnWinHttpCompletionSendRequestOrWriteComplete(
+        HINTERNET                   hRequest,
+        DWORD                       dwInternetStatus,
+        __out BOOL *                pfClientError,
+        __out BOOL *                pfAnotherCompletionExpected
+    );
+
+    HRESULT
+    OnWinHttpCompletionStatusHeadersAvailable(
+        HINTERNET                   hRequest,
+        __out BOOL *                pfAnotherCompletionExpected
+    );
+
+    HRESULT
+    OnWinHttpCompletionStatusDataAvailable(
+        HINTERNET                   hRequest,
+        DWORD                       dwBytes,
+        __out BOOL *                pfAnotherCompletionExpected
+    );
+
+    HRESULT
+    OnWinHttpCompletionStatusReadComplete(
+        __in IHttpResponse *        pResponse,
+        DWORD                       dwStatusInformationLength,
+        __out BOOL *                pfAnotherCompletionExpected
+    );
+
+    HRESULT
+    OnSendingRequest(
+        DWORD                       cbCompletion,
+        HRESULT                     hrCompletionStatus,
+        __out BOOL *                pfClientError
+    );
+
+    HRESULT
+    OnReceivingResponse();
+
+    HRESULT
+    OnWebSocketWinHttpSendComplete(
+        HINTERNET   hRequest,
+        LPVOID      pvStatus,
+        DWORD       hrCompletion,
+        DWORD       cbCompletion,
+        BOOL *      pfAnotherCompletionExpected
+    );
+
+    HRESULT
+    OnWebSocketWinHttpReceiveComplete(
+        HINTERNET   hRequest,
+        LPVOID      pvStatus,
+        DWORD       hrCompletion,
+        DWORD       cbCompletion,
+        BOOL *      pfAnotherCompletionExpected
+    );
+
+    HRESULT
+    OnWebSocketIisSendComplete(
+        DWORD hrCompletion,
+        DWORD cbCompletion
+    );
+
+    HRESULT
+    OnWebSocketIisReceiveComplete(
+        DWORD hrCompletion,
+        DWORD cbCompletion
+    );
+
+    HRESULT
+    DoIisWebSocketReceive(
+        VOID
+    );
+
+    VOID
+    TerminateWebsocket(
+        VOID
+    );
+
+    DWORD                               m_Signature;
+    mutable LONG                        m_cRefs;
+
+    IHttpContext *                      m_pW3Context;
+
+    //
+    // WinHTTP request handle is protected using a read-write lock.
+    //
+    SRWLOCK                             m_RequestLock;
+    HINTERNET                           m_hRequest;
+
+    APP_OFFLINE_HTM                    *m_pAppOfflineHtm;
+    APPLICATION                        *m_pApplication;
+
+    BOOL                                m_fResponseHeadersReceivedAndSet;
+    volatile  BOOL                      m_fClientDisconnected;
+    //
+    // A safety guard flag indicating no more IIS PostCompletion is allowed
+    //
+    volatile  BOOL                      m_fFinishRequest;
+    //
+    // A safety guard flag to prevent from unexpect callback which may signal IIS pipeline
+    // more than once with non-pending status
+    //
+    volatile  BOOL                      m_fDoneAsyncCompletion;
+    volatile  BOOL                      m_fHasError;
+    //
+    // WinHttp may hit AV under race if handle got closed more than once simultaneously 
+    // Use two bool variables to guard
+    //
+    volatile  BOOL                      m_fHttpHandleInClose;
+    volatile  BOOL                      m_fWebSocketHandleInClose;
+    //
+    // Record the number of winhttp handles in use
+    // release IIS pipeline only after all handles got closed
+    //
+    volatile  LONG                      m_dwHandlers;
+
+    BOOL                                m_fDoReverseRewriteHeaders;
+    BOOL                                m_fServerResetConn;
+    DWORD                               m_msStartTime;
+    DWORD                               m_BytesToReceive;
+    DWORD                               m_BytesToSend;
+
+    BYTE *                              m_pEntityBuffer;
+    DWORD                               m_cchLastSend;
+
+    static const SIZE_T                 INLINE_ENTITY_BUFFERS = 8;
+    DWORD                               m_cEntityBuffers;
+    BUFFER_T<BYTE*,INLINE_ENTITY_BUFFERS> m_buffEntityBuffers;
+
+    DWORD                               m_cBytesBuffered;
+    DWORD                               m_cMinBufferLimit;
+
+    PCSTR                               m_pszOriginalHostHeader;
+
+    volatile FORWARDING_REQUEST_STATUS  m_RequestStatus;
+
+    ASYNC_DISCONNECT_CONTEXT *          m_pDisconnect;
+
+    PCWSTR                              m_pszHeaders;
+    DWORD                               m_cchHeaders;
+
+    BOOL                                m_fWebSocketEnabled;
+
+    STRU                                m_strFullUri;
+
+    ULONGLONG                           m_cContentLength;
+
+    WEBSOCKET_HANDLER *                 m_pWebSocket;
+
+    static PROTOCOL_CONFIG              sm_ProtocolConfig;
+
+    static STRU                         sm_strErrorFormat;
+
+    static HANDLE                       sm_hEventLog;
+
+    static ALLOC_CACHE_HANDLER *        sm_pAlloc;
+
+    //
+    // Reference cout tracing for debugging purposes.
+    //
+    static TRACE_LOG *                  sm_pTraceLog;
+};
+
+class ASYNC_DISCONNECT_CONTEXT : public IHttpConnectionStoredContext
+{
+ public:
+    ASYNC_DISCONNECT_CONTEXT()
+    {
+        m_pHandler = NULL;
+    }
+
+    VOID
+    CleanupStoredContext()
+    {
+        DBG_ASSERT(m_pHandler == NULL);
+        delete this;
+    }
+
+    VOID
+    NotifyDisconnect()
+    {
+        FORWARDING_HANDLER *pInitialValue = (FORWARDING_HANDLER*)
+            InterlockedExchangePointer((PVOID*) &m_pHandler, NULL);
+
+        if (pInitialValue != NULL)
+        {
+            pInitialValue->TerminateRequest(TRUE);
+            pInitialValue->DereferenceForwardingHandler();
+        }
+    }
+
+    VOID
+    SetHandler(
+        FORWARDING_HANDLER *pHandler
+    )
+    {
+        //
+        // Take a reference on the forwarding handler.
+        // This reference will be released on either of two conditions:
+        //
+        // 1. When the request processing ends, in which case a ResetHandler()
+        // is called.
+        // 
+        // 2. When a disconnect notification arrives.
+        //
+        // We need to make sure that only one of them ends up dereferencing
+        // the object.
+        //
+
+        DBG_ASSERT (pHandler != NULL);
+        DBG_ASSERT (m_pHandler == NULL);
+
+        pHandler->ReferenceForwardingHandler();
+        InterlockedExchangePointer((PVOID*)&m_pHandler, pHandler);
+    }
+
+    VOID
+    ResetHandler(
+        VOID
+    )
+    {
+        FORWARDING_HANDLER *pInitialValue = (FORWARDING_HANDLER*) 
+            InterlockedExchangePointer( (PVOID*)&m_pHandler, NULL);
+
+        if (pInitialValue != NULL)
+        {
+            pInitialValue->DereferenceForwardingHandler();
+        }
+    }
+
+ private:
+    ~ASYNC_DISCONNECT_CONTEXT()
+    {}
+
+    FORWARDING_HANDLER *     m_pHandler;
+};
\ No newline at end of file
diff --git a/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/Inc/path.h b/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/Inc/path.h
new file mode 100644
index 0000000000000000000000000000000000000000..05545acfd5c3d6ad13102c4fbcc10e03d9ae7068
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/Inc/path.h
@@ -0,0 +1,95 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#pragma once
+
+class PATH
+{
+public:
+
+    static
+    HRESULT
+    SplitUrl(
+        PCWSTR pszDestinationUrl,
+        BOOL *pfSecure,
+        STRU *pstrDestination,
+        STRU *pstrUrl
+    );
+
+    static
+    HRESULT
+    UnEscapeUrl(
+        PCWSTR      pszUrl,
+        DWORD       cchUrl,
+        bool        fCopyQuery,
+        STRA *      pstrResult
+    );
+
+    static
+    HRESULT
+    UnEscapeUrl(
+        PCWSTR      pszUrl,
+        DWORD       cchUrl,
+        STRU *      pstrResult
+    );
+
+    static HRESULT
+    EscapeAbsPath(
+        IHttpRequest * pRequest,
+        STRU * strEscapedUrl
+    );
+
+    static
+    bool
+    IsValidAttributeNameChar(
+        WCHAR ch
+    );
+
+    static
+    bool
+    IsValidQueryStringName(
+        PCWSTR  pszName
+    );
+
+    static
+    bool
+    IsValidHeaderName(
+        PCWSTR  pszName
+    );
+
+    static
+    bool
+    FindInMultiString(
+        PCWSTR      pszMultiString,
+        PCWSTR      pszStringToFind
+    );
+
+    static
+    HRESULT
+    IsPathUnc(
+        __in  LPCWSTR       pszPath, 
+        __out BOOL *        pfIsUnc 
+    );
+
+    static
+    HRESULT
+    ConvertPathToFullPath(
+        _In_  LPCWSTR   pszPath,
+        _In_  LPCWSTR   pszRootPath,
+        _Out_ STRU*     pStrFullPath
+    );
+
+private:
+
+    PATH() {}
+    ~PATH() {}
+
+    static
+    CHAR 
+    ToHexDigit(
+        UINT nDigit
+    )
+    {
+        return static_cast<CHAR>(nDigit > 9 ? nDigit - 10 + 'A' : nDigit + '0');
+    }
+};
\ No newline at end of file
diff --git a/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/Inc/processmanager.h b/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/Inc/processmanager.h
new file mode 100644
index 0000000000000000000000000000000000000000..b91e8e6bfb5a5b94090bb44eb10a4b624396621a
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/Inc/processmanager.h
@@ -0,0 +1,193 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#pragma once
+
+#define ONE_MINUTE_IN_MILLISECONDS 60000
+
+class PROCESS_MANAGER
+{
+public:
+
+    virtual 
+    ~PROCESS_MANAGER();
+
+    VOID
+    ReferenceProcessManager() const
+    {
+        InterlockedIncrement(&m_cRefs);
+    }
+
+    VOID
+    DereferenceProcessManager() const
+    {
+        if (InterlockedDecrement(&m_cRefs) == 0)
+        {
+            delete this;
+        }
+    }
+
+    HRESULT 
+    GetProcess(
+        _In_    IHttpContext           *context,
+        _In_    ASPNETCORE_CONFIG      *pConfig,
+        _Out_   SERVER_PROCESS        **ppServerProcess
+    );
+
+    HANDLE
+    QueryNULHandle()
+    {
+        return m_hNULHandle;
+    }
+
+    HRESULT
+    Initialize(
+        VOID
+    );
+
+    VOID
+    SendShutdownSignal()
+    {
+        AcquireSRWLockExclusive( &m_srwLock );
+
+        for(DWORD i = 0; i < m_dwProcessesPerApplication; ++i )
+        {
+            if( m_ppServerProcessList != NULL && 
+                m_ppServerProcessList[i] != NULL )
+            {
+                m_ppServerProcessList[i]->SendSignal();
+                m_ppServerProcessList[i]->DereferenceServerProcess();
+                m_ppServerProcessList[i] = NULL;
+            }
+        }
+
+        ReleaseSRWLockExclusive( &m_srwLock );
+    }
+
+    VOID 
+    ShutdownProcess(
+        SERVER_PROCESS* pServerProcess
+    )
+    {
+        AcquireSRWLockExclusive( &m_srwLock );
+
+        ShutdownProcessNoLock( pServerProcess );
+
+        ReleaseSRWLockExclusive( &m_srwLock );
+    }
+
+    VOID 
+    ShutdownAllProcesses(
+    )
+    {
+        AcquireSRWLockExclusive( &m_srwLock );
+
+        ShutdownAllProcessesNoLock();
+
+        ReleaseSRWLockExclusive( &m_srwLock );
+    }
+
+    VOID 
+    IncrementRapidFailCount(
+        VOID
+    )
+    {
+        InterlockedIncrement(&m_cRapidFailCount);
+    }
+
+    PROCESS_MANAGER() : 
+        m_ppServerProcessList( NULL ),
+        m_hNULHandle( NULL ),
+        m_cRapidFailCount( 0 ),
+        m_dwProcessesPerApplication( 1 ),
+        m_dwRouteToProcessIndex( 0 ),
+        m_fServerProcessListReady(FALSE),
+        m_cRefs( 1 )
+    {
+        InitializeSRWLock( &m_srwLock );
+    }
+
+private:
+
+    BOOL 
+    RapidFailsPerMinuteExceeded(
+        LONG dwRapidFailsPerMinute
+    )
+    {
+        DWORD dwCurrentTickCount = GetTickCount();
+
+        if( (dwCurrentTickCount - m_dwRapidFailTickStart)
+             >= ONE_MINUTE_IN_MILLISECONDS )
+        {
+            //
+            // reset counters every minute.
+            //
+
+            InterlockedExchange(&m_cRapidFailCount, 0);
+            m_dwRapidFailTickStart = dwCurrentTickCount;
+        }
+
+        return m_cRapidFailCount > dwRapidFailsPerMinute;
+    }
+
+    VOID 
+    ShutdownProcessNoLock(
+        SERVER_PROCESS* pServerProcess
+    )
+    {
+        for(DWORD i = 0; i < m_dwProcessesPerApplication; ++i )
+        {
+            if( m_ppServerProcessList != NULL && 
+                m_ppServerProcessList[i] != NULL && 
+                m_ppServerProcessList[i]->GetPort() == pServerProcess->GetPort() )
+            {
+                // shutdown pServerProcess if not already shutdown.
+                m_ppServerProcessList[i]->StopProcess();
+                m_ppServerProcessList[i]->DereferenceServerProcess();
+                m_ppServerProcessList[i] = NULL;
+            }
+        }
+    }
+
+    VOID 
+    ShutdownAllProcessesNoLock(
+        VOID
+    )
+    {
+        for(DWORD i = 0; i < m_dwProcessesPerApplication; ++i )
+        {
+            if( m_ppServerProcessList != NULL &&
+                m_ppServerProcessList[i] != NULL )
+            {
+                // shutdown pServerProcess if not already shutdown.
+                m_ppServerProcessList[i]->SendSignal();
+                m_ppServerProcessList[i]->DereferenceServerProcess();
+                m_ppServerProcessList[i] = NULL;
+            }
+        }
+    }
+
+    volatile LONG                     m_cRapidFailCount;
+    DWORD                             m_dwRapidFailTickStart;
+    DWORD                             m_dwProcessesPerApplication;
+    volatile DWORD                    m_dwRouteToProcessIndex;
+
+    SRWLOCK                           m_srwLock;
+    SERVER_PROCESS                  **m_ppServerProcessList;
+
+    //
+    // m_hNULHandle is used to redirect stdout/stderr to NUL.
+    // If Createprocess is called to launch a batch file for example,
+    // it tries to write to the console buffer by default. It fails to 
+    // start if the console buffer is owned by the parent process i.e 
+    // in our case w3wp.exe. So we have to redirect the stdout/stderr
+    // of the child process to NUL or to a file (anything other than
+    // the console buffer of the parent process).
+    //
+
+    HANDLE                            m_hNULHandle;
+    mutable LONG                      m_cRefs;
+
+    volatile static BOOL              sm_fWSAStartupDone;
+    volatile BOOL                     m_fServerProcessListReady;
+};
\ No newline at end of file
diff --git a/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/Inc/protocolconfig.h b/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/Inc/protocolconfig.h
new file mode 100644
index 0000000000000000000000000000000000000000..d9d730c544691ad2b2cb6ecc1aa4ea3cfe60b772
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/Inc/protocolconfig.h
@@ -0,0 +1,105 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#pragma once
+
+#include "aspnetcoreconfig.h"
+
+class PROTOCOL_CONFIG
+{
+ public:
+
+    PROTOCOL_CONFIG()
+    {
+    }
+
+    HRESULT
+    Initialize();
+
+    VOID
+    OverrideConfig(
+        ASPNETCORE_CONFIG *pAspNetCoreConfig
+    );
+
+    BOOL
+    QueryDoKeepAlive() const
+    {
+        return m_fKeepAlive;
+    }
+
+    DWORD
+    QueryTimeout() const
+    {
+        return m_msTimeout;
+    }
+
+    BOOL
+    QueryPreserveHostHeader() const
+    {
+        return m_fPreserveHostHeader;
+    }
+
+    BOOL
+    QueryReverseRewriteHeaders() const
+    {
+        return m_fReverseRewriteHeaders;
+    }
+
+    const STRA *
+    QueryXForwardedForName() const
+    {
+        return &m_strXForwardedForName;
+    }
+
+    BOOL
+    QueryIncludePortInXForwardedFor() const
+    {
+        return m_fIncludePortInXForwardedFor;
+    }
+
+    DWORD
+    QueryMinResponseBuffer() const
+    {
+        return m_dwMinResponseBuffer;
+    }
+
+    DWORD
+    QueryResponseBufferLimit() const
+    {
+        return m_dwResponseBufferLimit;
+    }
+
+    DWORD
+    QueryMaxResponseHeaderSize() const
+    {
+        return m_dwMaxResponseHeaderSize;
+    }
+
+    const STRA*
+    QuerySslHeaderName() const
+    {
+        return &m_strSslHeaderName;
+    }
+
+    const STRA *
+    QueryClientCertName() const
+    {
+        return &m_strClientCertName;
+    }
+
+ private:
+    
+    BOOL            m_fKeepAlive;
+    BOOL            m_fPreserveHostHeader;
+    BOOL            m_fReverseRewriteHeaders;
+    BOOL            m_fIncludePortInXForwardedFor;
+
+    DWORD           m_msTimeout;
+    DWORD           m_dwMinResponseBuffer;
+    DWORD           m_dwResponseBufferLimit;
+    DWORD           m_dwMaxResponseHeaderSize;
+
+    STRA            m_strXForwardedForName;
+    STRA            m_strSslHeaderName;
+    STRA            m_strClientCertName;
+};
diff --git a/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/Inc/proxymodule.h b/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/Inc/proxymodule.h
new file mode 100644
index 0000000000000000000000000000000000000000..1adbcffae873eb3de697b5290d4ff1d54e9270ad
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/Inc/proxymodule.h
@@ -0,0 +1,61 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#pragma once
+
+#include "forwardinghandler.h"
+
+class CProxyModule : public CHttpModule
+{
+public:
+
+    CProxyModule();
+
+    ~CProxyModule();
+
+    void * operator new(size_t size, IModuleAllocator * pPlacement)
+    {
+        return pPlacement->AllocateMemory(static_cast<DWORD>(size));
+    }
+
+    VOID
+        operator delete(
+            void *
+            )
+    {
+    }
+
+    __override
+        REQUEST_NOTIFICATION_STATUS
+        OnExecuteRequestHandler(
+            IHttpContext *          pHttpContext,
+            IHttpEventProvider *    pProvider
+        );
+
+    __override
+        REQUEST_NOTIFICATION_STATUS
+        OnAsyncCompletion(
+            IHttpContext *          pHttpContext,
+            DWORD                   dwNotification,
+            BOOL                    fPostNotification,
+            IHttpEventProvider *    pProvider,
+            IHttpCompletionInfo *   pCompletionInfo
+        );
+
+private:
+
+    FORWARDING_HANDLER * m_pHandler;
+};
+
+class CProxyModuleFactory : public IHttpModuleFactory
+{
+public:
+    HRESULT
+        GetHttpModule(
+            CHttpModule **      ppModule,
+            IModuleAllocator *  pAllocator
+        );
+
+    VOID
+        Terminate();
+};
\ No newline at end of file
diff --git a/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/Inc/resource.h b/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/Inc/resource.h
new file mode 100644
index 0000000000000000000000000000000000000000..64dde656b0092da630c30a2a74a4b4452d05cdc6
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/Inc/resource.h
@@ -0,0 +1,20 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#pragma once
+
+#define IDS_INVALID_PROPERTY        1000
+#define IDS_SERVER_ERROR            1001
+
+#define ASPNETCORE_EVENT_MSG_BUFFER_SIZE 256
+#define ASPNETCORE_EVENT_PROCESS_START_SUCCESS_MSG           L"Application '%s' started process '%d' successfully and is listening on port '%d'."
+#define ASPNETCORE_EVENT_RAPID_FAIL_COUNT_EXCEEDED_MSG       L"Maximum rapid fail count per minute of '%d' exceeded."
+#define ASPNETCORE_EVENT_PROCESS_START_INTERNAL_ERROR_MSG    L"Application '%s' failed to parse processPath and arguments due to internal error, ErrorCode = '0x%x'."
+#define ASPNETCORE_EVENT_PROCESS_START_POSTCREATE_ERROR_MSG  L"Application '%s' with physical root '%s' created process with commandline '%s'but failed to get its status, ErrorCode = '0x%x'."
+#define ASPNETCORE_EVENT_PROCESS_START_ERROR_MSG             L"Application '%s' with physical root '%s' failed to start process with commandline '%s', ErrorCode = '0x%x : %x."
+#define ASPNETCORE_EVENT_PROCESS_START_WRONGPORT_ERROR_MSG   L"Application '%s' with physical root '%s' created process with commandline '%s' but failed to listen on the given port '%d'"
+#define ASPNETCORE_EVENT_PROCESS_START_NOTREADY_ERROR_MSG    L"Application '%s' with physical root '%s' created process with commandline '%s' but either crashed or did not reponse or did not listen on the given port '%d', ErrorCode = '0x%x'"
+#define ASPNETCORE_EVENT_INVALID_STDOUT_LOG_FILE_MSG         L"Warning: Could not create stdoutLogFile %s, ErrorCode = %d."
+#define ASPNETCORE_EVENT_GRACEFUL_SHUTDOWN_FAILURE_MSG       L"Failed to gracefully shutdown process '%d'."
+#define ASPNETCORE_EVENT_SENT_SHUTDOWN_HTTP_REQUEST_MSG      L"Sent shutdown HTTP message to process '%d' and received http status '%d'."
+#define ASPNETCORE_EVENT_RECYCLE_APPOFFLINE_MSG              L"App_offline file '%s' was detected."
diff --git a/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/Inc/responseheaderhash.h b/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/Inc/responseheaderhash.h
new file mode 100644
index 0000000000000000000000000000000000000000..7ef127366b642462e99dfc288e8fe676fe1d784f
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/Inc/responseheaderhash.h
@@ -0,0 +1,110 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#pragma once
+
+//
+// *_HEADER_HASH maps strings to UlHeader* values
+//
+
+#define UNKNOWN_INDEX           (0xFFFFFFFF)
+
+struct HEADER_RECORD
+{
+    PCSTR   _pszName;
+    ULONG   _ulHeaderIndex;
+};
+
+class RESPONSE_HEADER_HASH: public HASH_TABLE<HEADER_RECORD, PCSTR>
+{
+public:
+    RESPONSE_HEADER_HASH() 
+    {}
+    
+    VOID
+    ReferenceRecord(
+        HEADER_RECORD *
+    )
+    {}
+
+    VOID
+    DereferenceRecord(
+        HEADER_RECORD *
+    )
+    {}
+
+    PCSTR
+    ExtractKey(
+        HEADER_RECORD * pRecord
+    )
+    {
+        return pRecord->_pszName;
+    }
+
+    DWORD
+    CalcKeyHash(
+        PCSTR   key
+    )
+    {
+        return HashStringNoCase(key);
+    }
+
+    BOOL
+    EqualKeys(
+        PCSTR   key1,
+        PCSTR   key2
+    )
+    {
+        return (_stricmp(key1, key2) == 0);
+    }
+
+    HRESULT
+    Initialize(
+        VOID
+    );
+    
+    VOID
+    Terminate(
+        VOID
+    );
+    
+    DWORD
+    GetIndex(
+        PCSTR             pszName
+    )
+    {
+        HEADER_RECORD *       pRecord = NULL;
+
+        FindKey(pszName, &pRecord);
+        if (pRecord != NULL)
+        {
+            return pRecord->_ulHeaderIndex;
+        }
+
+        return UNKNOWN_INDEX;
+    }
+    
+    static
+    PCSTR
+    GetString(
+        ULONG               ulIndex
+    )
+    {
+        if (ulIndex < HttpHeaderResponseMaximum)
+        {
+            DBG_ASSERT(sm_rgHeaders[ulIndex]._ulHeaderIndex == ulIndex);
+            return sm_rgHeaders[ulIndex]._pszName;
+        }
+
+        return NULL;
+    }
+    
+private:
+
+    static HEADER_RECORD         sm_rgHeaders[];
+
+    RESPONSE_HEADER_HASH(const RESPONSE_HEADER_HASH &);
+    void operator=(const RESPONSE_HEADER_HASH &);
+};
+
+extern RESPONSE_HEADER_HASH *   g_pResponseHeaderHash;
\ No newline at end of file
diff --git a/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/Inc/serverprocess.h b/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/Inc/serverprocess.h
new file mode 100644
index 0000000000000000000000000000000000000000..0eebdb9d692db08cb8ee4988b6c2e3e28dcba7d3
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/Inc/serverprocess.h
@@ -0,0 +1,329 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#pragma once
+
+#include <random>
+
+#define MIN_PORT                                    1025
+#define MAX_PORT                                    48000
+#define MAX_RETRY                                   10
+#define MAX_ACTIVE_CHILD_PROCESSES                  16
+#define LOCALHOST                                   "127.0.0.1"
+#define ASPNETCORE_PORT_STR                         L"ASPNETCORE_PORT"
+#define ASPNETCORE_PORT_ENV_STR                     L"ASPNETCORE_PORT="
+#define ASPNETCORE_APP_PATH_ENV_STR                 L"ASPNETCORE_APPL_PATH="
+#define ASPNETCORE_APP_TOKEN_ENV_STR                L"ASPNETCORE_TOKEN="
+#define ASPNETCORE_APP_PATH_ENV_STR                 L"ASPNETCORE_APPL_PATH="
+#define HOSTING_STARTUP_ASSEMBLIES_ENV_STR          L"ASPNETCORE_HOSTINGSTARTUPASSEMBLIES"
+#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_AUTH_WINDOWS                 L"windows;"
+#define ASPNETCORE_IIS_AUTH_BASIC                   L"basic;"
+#define ASPNETCORE_IIS_AUTH_ANONYMOUS               L"anonymous;"
+#define ASPNETCORE_IIS_AUTH_NONE                    L"none"
+
+class PROCESS_MANAGER;
+class FORWARDER_CONNECTION;
+
+class SERVER_PROCESS
+{
+public:
+    SERVER_PROCESS();
+
+    HRESULT
+        Initialize(
+        _In_ PROCESS_MANAGER      *pProcessManager,
+        _In_ STRU                 *pszProcessExePath,
+        _In_ STRU                 *pszArguments,
+        _In_ DWORD                 dwStartupTimeLimitInMS,
+        _In_ DWORD                 dwShtudownTimeLimitInMS,
+        _In_ BOOL                  fWindowsAuthEnabled,
+        _In_ BOOL                  fBasicAuthEnabled,
+        _In_ BOOL                  fAnonymousAuthEnabled,
+        _In_ ENVIRONMENT_VAR_HASH* pEnvironmentVariables,
+        _In_ BOOL                  fStdoutLogEnabled,
+        _In_ STRU                 *pstruStdoutLogFile
+        );
+
+
+    HRESULT
+    StartProcess(
+        _In_ IHttpContext *context
+    );
+
+    HRESULT
+    SetWindowsAuthToken(
+        _In_ HANDLE hToken,
+        _Out_ LPHANDLE pTargeTokenHandle
+    );
+
+    BOOL
+    IsReady(
+        VOID
+    )
+    {
+        return m_fReady;
+    }
+
+    VOID
+    StopProcess(
+        VOID
+    );
+
+    DWORD 
+    GetPort()
+    {
+        return m_dwPort;
+    }
+
+    VOID
+    ReferenceServerProcess(
+        VOID
+    )
+    {
+        InterlockedIncrement(&m_cRefs);
+    }
+
+    VOID
+    DereferenceServerProcess(
+        VOID
+    )
+    {
+        _ASSERT(m_cRefs != 0 );
+        
+        if (InterlockedDecrement(&m_cRefs) == 0)
+        {
+            delete this;
+        }
+    }
+
+    virtual 
+    ~SERVER_PROCESS();
+
+    HRESULT 
+    HandleProcessExit(
+        VOID
+    );
+
+    FORWARDER_CONNECTION*
+    QueryWinHttpConnection(
+        VOID
+    )
+    {
+        return m_pForwarderConnection;
+    }
+
+    static
+    VOID
+    CALLBACK
+    TimerCallback(
+        _In_ PTP_CALLBACK_INSTANCE Instance,
+        _In_ PVOID Context,
+        _In_ PTP_TIMER Timer
+    );
+
+    LPCWSTR
+    QueryPortStr()
+    {
+        return m_struPort.QueryStr();
+    }
+
+    LPCWSTR
+    QueryFullLogPath()
+    {
+        return m_struFullLogFile.QueryStr();
+    }
+
+    LPCSTR
+    QueryGuid()
+    {
+        return m_straGuid.QueryStr();
+    }
+
+    DWORD
+    QueryProcessGroupId()
+    {
+        return m_dwProcessId;
+    }
+
+    VOID
+    SendSignal( 
+        VOID
+    );
+
+private:
+
+    BOOL 
+    IsDebuggerIsAttached(
+        VOID
+    );
+
+    HRESULT
+    StopAllProcessesInJobObject(
+        VOID
+    );
+
+    HRESULT
+    SetupStdHandles(
+        _In_ IHttpContext *context,
+        _In_ LPSTARTUPINFOW pStartupInfo
+    );
+
+    HRESULT
+    CheckIfServerIsUp(
+        _In_  DWORD       dwPort,
+        _Out_ DWORD     * pdwProcessId,
+        _Out_ BOOL      * pfReady
+    );
+
+    HRESULT 
+    RegisterProcessWait(
+        _In_ PHANDLE phWaitHandle,
+        _In_ HANDLE  hProcessToWaitOn
+    );
+
+    HRESULT 
+    GetChildProcessHandles(
+    );
+
+    HRESULT
+    SetupListenPort(
+        ENVIRONMENT_VAR_HASH    *pEnvironmentVarTable
+    );
+
+    HRESULT
+    SetupAppPath(
+        IHttpContext*           pContext,
+        ENVIRONMENT_VAR_HASH*   pEnvironmentVarTable
+    );
+
+    HRESULT
+    SetupAppToken(
+        ENVIRONMENT_VAR_HASH*   pEnvironmentVarTable
+    );
+
+    HRESULT
+    InitEnvironmentVariablesTable(
+        ENVIRONMENT_VAR_HASH**   pEnvironmentVarTable
+    );
+
+    HRESULT
+    OutputEnvironmentVariables(
+        MULTISZ*                pmszOutput,
+        ENVIRONMENT_VAR_HASH*   pEnvironmentVarTable
+    );
+
+    HRESULT
+    SetupCommandLine(
+        STRU*    pstrCommandLine
+    );
+
+    HRESULT
+    PostStartCheck(
+        const STRU* const pStruCommandline,
+        STRU*             pStruErrorMessage
+    );
+
+    HRESULT
+    GetRandomPort(
+        DWORD*    pdwPickedPort,
+        DWORD     dwExcludedPort
+    );
+
+    DWORD
+    GetNumberOfDigits( 
+        _In_ DWORD dwNumber 
+    )
+    {
+        DWORD digits = 0;
+        
+        if( dwNumber == 0 )
+        {
+            digits = 1;
+            goto Finished;
+        }
+
+        while( dwNumber > 0)
+        {
+            dwNumber = dwNumber / 10;
+            digits ++;
+        }
+    Finished:
+        return digits;
+    }
+
+    static
+    VOID
+    SendShutDownSignal(
+        LPVOID lpParam
+    );
+
+    VOID
+    SendShutDownSignalInternal(
+        VOID
+    );
+
+    HRESULT
+    SendShutdownHttpMessage(
+        VOID
+    );
+
+    VOID
+    TerminateBackendProcess(
+        VOID
+    );
+
+    FORWARDER_CONNECTION   *m_pForwarderConnection;
+    BOOL                    m_fStdoutLogEnabled;
+    BOOL                    m_fWindowsAuthEnabled;
+    BOOL                    m_fBasicAuthEnabled;
+    BOOL                    m_fAnonymousAuthEnabled;
+
+    STTIMER                 m_Timer;
+    SOCKET                  m_socket;
+
+    STRU                    m_struLogFile;
+    STRU                    m_struFullLogFile;
+    STRU                    m_ProcessPath;
+    STRU                    m_Arguments;
+    STRU                    m_struAppPath;
+    STRU                    m_struAppFullPath;
+    STRU                    m_struPort;
+    STRU                    m_pszRootApplicationPath;
+    volatile LONG           m_lStopping;
+    volatile BOOL           m_fReady;
+    mutable LONG            m_cRefs;
+
+    std::mt19937            m_randomGenerator;
+
+    DWORD                   m_dwPort;
+    DWORD                   m_dwStartupTimeLimitInMS;
+    DWORD                   m_dwShutdownTimeLimitInMS;
+    DWORD                   m_cChildProcess;
+    DWORD                   m_dwChildProcessIds[MAX_ACTIVE_CHILD_PROCESSES];
+    DWORD                   m_dwProcessId;
+    DWORD                   m_dwListeningProcessId;
+
+    STRA                    m_straGuid;
+
+    HANDLE                  m_hJobObject;
+    HANDLE                  m_hStdoutHandle;
+    //
+    // m_hProcessHandle is the handle to process this object creates.
+    //
+    HANDLE                  m_hProcessHandle;
+    HANDLE                  m_hListeningProcessHandle;
+    HANDLE                  m_hProcessWaitHandle;
+    HANDLE                  m_hShutdownHandle;
+    //
+    // m_hChildProcessHandle is the handle to process created by 
+    // m_hProcessHandle process if it does.
+    //
+    HANDLE                  m_hChildProcessHandles[MAX_ACTIVE_CHILD_PROCESSES];
+    HANDLE                  m_hChildProcessWaitHandles[MAX_ACTIVE_CHILD_PROCESSES];
+
+    PROCESS_MANAGER         *m_pProcessManager;
+    ENVIRONMENT_VAR_HASH    *m_pEnvironmentVarTable ;
+};
diff --git a/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/Inc/sttimer.h b/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/Inc/sttimer.h
new file mode 100644
index 0000000000000000000000000000000000000000..dfb79e7a6a8adb638db5333b1978f13c69d55e91
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/Inc/sttimer.h
@@ -0,0 +1,279 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#pragma once
+
+#ifndef _STTIMER_H
+#define _STTIMER_H
+
+class STTIMER
+{
+public:
+
+    STTIMER()
+        : _pTimer( NULL )
+    {
+        fInCanel = FALSE;
+    }
+
+    virtual
+    ~STTIMER()
+    {
+        if ( _pTimer )
+        {
+            CancelTimer();
+            CloseThreadpoolTimer( _pTimer );
+            _pTimer = NULL;
+        }
+    }
+
+    HRESULT
+    InitializeTimer(
+        PTP_TIMER_CALLBACK   pfnCallback,
+        VOID               * pContext,
+        DWORD                dwInitialWait = 0,
+        DWORD                dwPeriod = 0
+        )
+    {
+        _pTimer = CreateThreadpoolTimer( pfnCallback,
+                                         pContext,
+                                         NULL );
+
+        if ( !_pTimer )
+        {
+            return HRESULT_FROM_WIN32( GetLastError() );
+        }
+
+        if ( dwInitialWait )
+        {
+            SetTimer( dwInitialWait,
+                      dwPeriod );
+        }
+
+        return S_OK;
+    }
+
+    VOID
+    SetTimer(
+        DWORD dwInitialWait,
+        DWORD dwPeriod = 0
+        )
+    {
+        FILETIME ftInitialWait;
+
+        if ( dwInitialWait == 0 && dwPeriod == 0 )
+        {
+            //
+            // Special case.  We are preventing new callbacks
+            // from being queued.  Any existing callbacks in the
+            // queue will still run.
+            //
+            // This effectively disables the timer.  It can be
+            // re-enabled by setting non-zero initial wait or
+            // period values.
+            //
+            if (_pTimer != NULL)
+            {
+                SetThreadpoolTimer(_pTimer, NULL, 0, 0);
+            }
+
+            return;
+        }
+
+        InitializeRelativeFileTime( &ftInitialWait, dwInitialWait );
+
+        SetThreadpoolTimer( _pTimer,
+                            &ftInitialWait,
+                            dwPeriod,
+                            0 );
+    }
+
+    VOID
+    CancelTimer()
+    {
+        //
+        // Disable the timer
+        //
+        if (fInCanel)
+            return;
+
+        fInCanel = TRUE;
+        SetTimer( 0 );
+
+        //
+        // Wait until any callbacks queued prior to disabling
+        // have completed.
+        //
+        if (_pTimer != NULL)
+        {
+            WaitForThreadpoolTimerCallbacks(_pTimer, TRUE);
+        }
+
+        fInCanel = FALSE;
+    }
+
+    static
+    VOID
+    CALLBACK
+    TimerCallback(
+        _In_ PTP_CALLBACK_INSTANCE Instance,
+        _In_ PVOID Context,
+        _In_ PTP_TIMER Timer
+    )
+    {
+        Instance;
+        Timer;
+        STRU*                   pstruLogFilePath = (STRU*)Context;
+        HANDLE                  hStdoutHandle = NULL;
+        SECURITY_ATTRIBUTES     saAttr = { 0 };
+        HRESULT                 hr = S_OK;
+
+        saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
+        saAttr.bInheritHandle = TRUE;
+        saAttr.lpSecurityDescriptor = NULL;
+
+        hStdoutHandle = CreateFileW(pstruLogFilePath->QueryStr(),
+                                    FILE_READ_DATA,
+                                    FILE_SHARE_WRITE,
+                                    &saAttr,
+                                    OPEN_ALWAYS,
+                                    FILE_ATTRIBUTE_NORMAL,
+                                    NULL);
+        if (hStdoutHandle == INVALID_HANDLE_VALUE)
+        {
+            hr = HRESULT_FROM_WIN32(GetLastError());
+        }
+
+        CloseHandle(hStdoutHandle);
+    }
+
+private:
+
+    VOID
+    InitializeRelativeFileTime(
+        FILETIME * pft,
+        DWORD      dwMilliseconds
+        )
+    {
+        LARGE_INTEGER li;
+
+        //
+        // The pftDueTime parameter expects the time to be
+        // expressed as the number of 100 nanosecond intervals
+        // times -1.
+        //
+        // To convert from milliseconds, we'll multiply by
+        // -10000
+        //
+
+        li.QuadPart = (LONGLONG)dwMilliseconds * -10000;
+
+        pft->dwHighDateTime = li.HighPart;
+        pft->dwLowDateTime = li.LowPart;
+    };
+
+    TP_TIMER * _pTimer;
+    BOOL       fInCanel;
+};
+
+class STELAPSED
+{
+public:
+
+    STELAPSED()
+        : _dwInitTime( 0 ),
+          _dwInitTickCount( 0 ),
+          _dwPerfCountsPerMillisecond( 0 ),
+          _fUsingHighResolution( FALSE )
+    {
+        LARGE_INTEGER li;
+        BOOL          fResult;
+
+        _dwInitTickCount = GetTickCount64();
+
+        fResult = QueryPerformanceFrequency( &li );
+
+        if ( !fResult )
+        {
+            goto Finished;
+        }
+
+        _dwPerfCountsPerMillisecond = li.QuadPart / 1000;
+
+        fResult = QueryPerformanceCounter( &li );
+
+        if ( !fResult )
+        {
+            goto Finished;
+        }
+
+        _dwInitTime = li.QuadPart / _dwPerfCountsPerMillisecond;
+
+        _fUsingHighResolution = TRUE;
+
+Finished:
+
+        return;
+    }
+
+    virtual
+    ~STELAPSED()
+    {
+    }
+
+    LONGLONG
+    QueryElapsedTime()
+    {
+        LARGE_INTEGER li;
+
+        if ( _fUsingHighResolution && QueryPerformanceCounter( &li ) )
+        {
+            DWORD64 dwCurrentTime = li.QuadPart / _dwPerfCountsPerMillisecond;
+
+            if ( dwCurrentTime < _dwInitTime )
+            {
+                //
+                // It's theoretically possible that QueryPerformanceCounter
+                // may return slightly different values on different CPUs.
+                // In this case, we don't want to return an unexpected value
+                // so we'll return zero.  This is acceptable because
+                // presumably such a case would only happen for a very short
+                // time window.
+                //
+                // It would be possible to prevent this by ensuring processor
+                // affinity for all calls to QueryPerformanceCounter, but that
+                // would be undesirable in the general case because it could
+                // introduce unnecessary context switches and potentially a
+                // CPU bottleneck.
+                //
+                // Note that this issue also applies to callers doing rapid
+                // calls to this function.  If a caller wants to mitigate
+                // that, they could enforce the affinitization, or they
+                // could implement a similar sanity check when comparing
+                // returned values from this function.
+                //
+
+                return 0;
+            }
+
+            return dwCurrentTime - _dwInitTime;
+        }
+
+        return GetTickCount64() - _dwInitTickCount;
+    }
+
+    BOOL
+    QueryUsingHighResolution()
+    {
+        return _fUsingHighResolution;
+    }
+
+private:
+
+    DWORD64 _dwInitTime;
+    DWORD64 _dwInitTickCount;
+    DWORD64 _dwPerfCountsPerMillisecond;
+    BOOL    _fUsingHighResolution;
+};
+
+#endif // _STTIMER_H
\ No newline at end of file
diff --git a/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/Inc/websockethandler.h b/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/Inc/websockethandler.h
new file mode 100644
index 0000000000000000000000000000000000000000..aadfcb6884f51f4896cc96928b49b3e3b9b2b08e
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/Inc/websockethandler.h
@@ -0,0 +1,221 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#pragma once
+
+class FORWARDING_HANDLER;
+
+class WEBSOCKET_HANDLER
+{
+public:
+    WEBSOCKET_HANDLER();
+
+    virtual
+    ~WEBSOCKET_HANDLER();
+
+    static
+    HRESULT
+    StaticInitialize(
+        BOOL fEnableReferenceTraceLogging
+        );
+
+    static
+    VOID
+    StaticTerminate(
+        VOID
+        );
+
+    VOID
+    Terminate(
+        VOID
+    );
+
+    VOID
+    TerminateRequest(
+        VOID
+        )
+    {
+        Cleanup(ServerStateUnavailable);
+    }
+
+    HRESULT
+    ProcessRequest(
+        FORWARDING_HANDLER *pHandler,
+        IHttpContext * pHttpContext,
+        HINTERNET      hRequest,
+        BOOL*          fHandleCreated
+        );
+
+    REQUEST_NOTIFICATION_STATUS
+    OnAsyncCompletion(
+        VOID
+        );
+
+    HRESULT
+    OnWinHttpSendComplete(
+        WINHTTP_WEB_SOCKET_STATUS * pCompletionStatus
+    );
+
+    HRESULT
+    OnWinHttpShutdownComplete(
+        VOID
+    );
+
+    HRESULT
+    OnWinHttpReceiveComplete(
+        WINHTTP_WEB_SOCKET_STATUS * pCompletionStatus
+    );
+
+    HRESULT
+    OnWinHttpIoError(
+        WINHTTP_WEB_SOCKET_ASYNC_RESULT *pCompletionStatus
+    );
+
+private:
+    enum CleanupReason
+    {
+        CleanupReasonUnknown = 0,
+        IdleTimeout = 1,
+        ConnectFailed = 2,
+        ClientDisconnect = 3,
+        ServerDisconnect = 4,
+        ServerStateUnavailable = 5
+    };
+
+    WEBSOCKET_HANDLER(const WEBSOCKET_HANDLER &);
+    void operator=(const WEBSOCKET_HANDLER &);
+
+    VOID
+    InsertRequest(
+        VOID
+        );
+
+    VOID
+    RemoveRequest(
+        VOID
+        );
+
+    static
+    VOID
+    WINAPI
+    OnReadIoCompletion(
+        HRESULT     hrError,
+        VOID *      pvCompletionContext,
+        DWORD       cbIO,
+        BOOL        fUTF8Encoded,
+        BOOL        fFinalFragment,
+        BOOL        fClose
+        );
+
+    static
+    VOID
+    WINAPI
+    OnWriteIoCompletion(
+        HRESULT     hrError,
+        VOID *      pvCompletionContext,
+        DWORD       cbIO,
+        BOOL        fUTF8Encoded,
+        BOOL        fFinalFragment,
+        BOOL        fClose
+    );
+
+    VOID
+    Cleanup(
+        CleanupReason  reason
+        );
+
+    HRESULT
+    DoIisWebSocketReceive(
+        VOID
+    );
+
+    HRESULT
+    DoWinHttpWebSocketReceive(
+        VOID
+    );
+
+    HRESULT
+    DoIisWebSocketSend(
+        DWORD cbData,
+        WINHTTP_WEB_SOCKET_BUFFER_TYPE  eBufferType
+    );
+
+    HRESULT
+    DoWinHttpWebSocketSend(
+        DWORD cbData,
+        WINHTTP_WEB_SOCKET_BUFFER_TYPE  eBufferType
+    );
+
+    HRESULT
+    OnIisSendComplete(
+        HRESULT     hrError,
+        DWORD       cbIO
+    );
+
+    HRESULT
+    OnIisReceiveComplete(
+        HRESULT     hrError,
+        DWORD       cbIO,
+        BOOL        fUTF8Encoded,
+        BOOL        fFinalFragment,
+        BOOL        fClose
+    );
+
+    VOID
+    IncrementOutstandingIo(
+        VOID
+    );
+
+    VOID
+    DecrementOutstandingIo(
+        VOID
+    );
+
+    VOID
+    IndicateCompletionToIIS(
+        VOID
+    );
+
+private:
+    static const
+    DWORD               RECEIVE_BUFFER_SIZE = 4*1024;
+
+    LIST_ENTRY          _listEntry;
+
+    IHttpContext3 *     _pHttpContext;
+
+    IWebSocketContext * _pWebSocketContext;
+
+    FORWARDING_HANDLER *_pHandler;
+
+    HINTERNET           _hWebSocketRequest;
+
+    BYTE                _WinHttpReceiveBuffer[RECEIVE_BUFFER_SIZE];
+
+    BYTE                _IisReceiveBuffer[RECEIVE_BUFFER_SIZE];
+
+    CRITICAL_SECTION    _RequestLock;
+
+    LONG                _dwOutstandingIo;
+
+    volatile
+    BOOL                _fHandleClosed;
+
+    volatile
+    BOOL                _fCleanupInProgress;
+
+    volatile
+    BOOL                _fIndicateCompletionToIis;
+
+    volatile
+    BOOL                _fReceivedCloseMsg;
+
+    static
+    LIST_ENTRY          sm_RequestsListHead;
+
+    static
+    SRWLOCK             sm_RequestsListLock;
+
+    static
+    TRACE_LOG *         sm_pTraceLog;
+};
\ No newline at end of file
diff --git a/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/Inc/winhttphelper.h b/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/Inc/winhttphelper.h
new file mode 100644
index 0000000000000000000000000000000000000000..b301a76cf239c10f990925a623cf83bdcf8839eb
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/Inc/winhttphelper.h
@@ -0,0 +1,91 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#pragma once
+
+typedef
+HINTERNET
+(WINAPI * PFN_WINHTTP_WEBSOCKET_COMPLETE_UPGRADE)(
+    _In_ HINTERNET hRequest,
+    _In_opt_ DWORD_PTR pContext
+);
+
+
+typedef
+DWORD
+(WINAPI * PFN_WINHTTP_WEBSOCKET_SEND)(
+    _In_ HINTERNET hWebSocket,
+    _In_ WINHTTP_WEB_SOCKET_BUFFER_TYPE eBufferType,
+    _In_reads_opt_(dwBufferLength) PVOID pvBuffer,
+    _In_ DWORD dwBufferLength
+);
+
+typedef
+DWORD
+(WINAPI * PFN_WINHTTP_WEBSOCKET_RECEIVE)(
+    _In_ HINTERNET hWebSocket,
+    _Out_writes_bytes_to_(dwBufferLength, *pdwBytesRead) PVOID pvBuffer,
+    _In_ DWORD dwBufferLength,
+    _Out_range_(0, dwBufferLength) DWORD *pdwBytesRead,
+    _Out_ WINHTTP_WEB_SOCKET_BUFFER_TYPE *peBufferType
+);
+
+typedef
+DWORD
+(WINAPI * PFN_WINHTTP_WEBSOCKET_SHUTDOWN)(
+    _In_ HINTERNET hWebSocket,
+    _In_ USHORT usStatus,
+    _In_reads_bytes_opt_(dwReasonLength) PVOID pvReason,
+    _In_range_(0, WINHTTP_WEB_SOCKET_MAX_CLOSE_REASON_LENGTH) DWORD dwReasonLength
+);
+
+typedef
+DWORD
+(WINAPI * PFN_WINHTTP_WEBSOCKET_QUERY_CLOSE_STATUS)(
+    _In_ HINTERNET hWebSocket,
+    _Out_ USHORT *pusStatus,
+    _Out_writes_bytes_to_opt_(dwReasonLength, *pdwReasonLengthConsumed) PVOID pvReason,
+    _In_range_(0, WINHTTP_WEB_SOCKET_MAX_CLOSE_REASON_LENGTH) DWORD dwReasonLength,
+    _Out_range_(0, WINHTTP_WEB_SOCKET_MAX_CLOSE_REASON_LENGTH) DWORD *pdwReasonLengthConsumed
+);
+
+class WINHTTP_HELPER
+{
+public:
+    static
+    HRESULT
+    StaticInitialize();
+
+    static
+    VOID
+    GetFlagsFromBufferType(
+        __in  WINHTTP_WEB_SOCKET_BUFFER_TYPE   BufferType,
+        __out BOOL *                           pfUtf8Encoded,
+        __out BOOL *                           pfFinalFragment,
+        __out BOOL *                           pfClose
+    );
+
+    static
+    VOID
+    GetBufferTypeFromFlags(
+        __in  BOOL                             fUtf8Encoded,
+        __in  BOOL                             fFinalFragment,
+        __in  BOOL                             fClose,
+        __out WINHTTP_WEB_SOCKET_BUFFER_TYPE*  pBufferType
+    );
+
+    static
+    PFN_WINHTTP_WEBSOCKET_COMPLETE_UPGRADE      sm_pfnWinHttpWebSocketCompleteUpgrade;
+
+    static
+    PFN_WINHTTP_WEBSOCKET_SEND                  sm_pfnWinHttpWebSocketSend;
+
+    static
+    PFN_WINHTTP_WEBSOCKET_RECEIVE               sm_pfnWinHttpWebSocketReceive;
+
+    static
+    PFN_WINHTTP_WEBSOCKET_SHUTDOWN              sm_pfnWinHttpWebSocketShutdown;
+
+    static
+    PFN_WINHTTP_WEBSOCKET_QUERY_CLOSE_STATUS    sm_pfnWinHttpWebSocketQueryCloseStatus;
+};
\ No newline at end of file
diff --git a/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/Source.def b/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/Source.def
new file mode 100644
index 0000000000000000000000000000000000000000..9aae10ab5d9a85608376c438ec770b90db3e5094
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/Source.def
@@ -0,0 +1,4 @@
+LIBRARY aspnetcore
+
+EXPORTS
+    RegisterModule
diff --git a/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/aspnetcore_msg.mc b/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/aspnetcore_msg.mc
new file mode 100644
index 0000000000000000000000000000000000000000..50bf87b6568a8c22cc026884937b4dd16ed33d93
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/aspnetcore_msg.mc
@@ -0,0 +1,78 @@
+;/*++
+;
+;Copyright (c) 2014 Microsoft Corporation
+;
+;Module Name:
+;
+;    aspnetcore_msg.mc
+;
+;Abstract:
+;
+;    Asp.Net Core Module localizable messages.
+;
+;--*/
+;
+;
+;#ifndef _ASPNETCORE_MSG_H_
+;#define _ASPNETCORE_MSG_H_
+;
+
+SeverityNames=(Success=0x0
+               Informational=0x1
+               Warning=0x2
+               Error=0x3
+              )
+
+MessageIdTypedef=DWORD
+
+Messageid=1000
+SymbolicName=ASPNETCORE_EVENT_PROCESS_START_ERROR
+Language=English
+%1
+.
+
+Messageid=1001
+SymbolicName=ASPNETCORE_EVENT_PROCESS_START_SUCCESS
+Language=English
+%1
+.
+
+Messageid=1002
+SymbolicName=ASPNETCORE_EVENT_PROCESS_CRASH
+Language=English
+%1
+.
+
+Messageid=1003
+SymbolicName=ASPNETCORE_EVENT_RAPID_FAIL_COUNT_EXCEEDED
+Language=English
+%1
+.
+
+Messageid=1004
+SymbolicName=ASPNETCORE_EVENT_CONFIG_ERROR
+Language=English
+%1
+.
+
+Messageid=1005
+SymbolicName=ASPNETCORE_EVENT_GRACEFUL_SHUTDOWN_FAILURE
+Language=English
+%1
+.
+
+Messageid=1006
+SymbolicName=ASPNETCORE_EVENT_SENT_SHUTDOWN_HTTP_REQUEST
+Language=English
+%1
+.
+
+Messageid=1012
+SymbolicName=ASPNETCORE_EVENT_RECYCLE_APPOFFLINE
+Language=English
+%1
+.
+
+;
+;#endif     // _ASPNETCORE_MODULE_MSG_H_
+;
diff --git a/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/aspnetcore_schema.xml b/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/aspnetcore_schema.xml
new file mode 100644
index 0000000000000000000000000000000000000000..d65be071958cc6acf6e55f7e6f786c3ac61f2a3b
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/aspnetcore_schema.xml
@@ -0,0 +1,47 @@
+<!--
+    
+    IIS Asp.Net Core Extension Schema
+    
+    ** Please DO NOT edit this file yourself. **
+    
+    If you want to add configuration sections to the schema, you may place 
+    them in .xml files similar to this one, in this directory. They will be 
+    picked up automatically on startup.
+
+-->
+
+<configSchema>
+    <sectionSchema name="system.webServer/aspNetCore">
+        <attribute name="processPath" type="string" expanded="true"/>
+        <attribute name="arguments" type="string" expanded="true" defaultValue=""/>
+        <attribute name="startupTimeLimit" type="uint" defaultValue="120" validationType="integerRange" validationParameter="0,3600"/>
+        <!-- in seconds -->
+        <attribute name="shutdownTimeLimit" type="uint" defaultValue="10" validationType="integerRange" validationParameter="0,600"/>
+        <!-- in seconds -->
+        <attribute name="rapidFailsPerMinute" type="uint" defaultValue="10" validationType="integerRange" validationParameter="0,100"/>
+        <attribute name="requestTimeout" type="timeSpan" defaultValue="00:02:00" validationType="timeSpanRange" validationParameter="0,1296000,1"/>
+        <attribute name="stdoutLogEnabled" type="bool" defaultValue="false" />
+        <attribute name="stdoutLogFile" type="string" defaultValue=".\aspnetcore-stdout" expanded="true"/>
+        <attribute name="processesPerApplication" type="uint" defaultValue="1" validationType="integerRange" validationParameter="1,100"/>
+        <attribute name="forwardWindowsAuthToken" type="bool" defaultValue="true" />
+        <attribute name="disableStartUpErrorPage" type="bool" defaultValue="false" />
+        <attribute name="hostingModel" type="string" />
+        <element name="recycleOnFileChange">
+            <collection addElement="file" clearElement="clear">
+                <attribute name="path" type="string" required="true" validationType="nonEmptyString" expanded="true"/>
+            </collection>
+        </element>
+        <element name="environmentVariables">
+            <collection addElement="environmentVariable" clearElement="clear" >
+                <attribute name="name" type="string" required="true" validationType="nonEmptyString"/>
+                <attribute name="value" type="string" required="true"/>
+            </collection>
+        </element>
+        <element name="handlerSettings">
+            <collection addElement="handlerSetting" clearElement="clear" >
+                <attribute name="name" type="string" required="true" validationType="nonEmptyString"/>
+               <attribute name="value" type="string" required="true"/>
+            </collection>
+        </element>
+    </sectionSchema>
+</configSchema>
diff --git a/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/aspnetcoremodule.rc b/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/aspnetcoremodule.rc
new file mode 100644
index 0000000000000000000000000000000000000000..d37eb29238d3a4065e64b81c3898b552878e1737
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/aspnetcoremodule.rc
@@ -0,0 +1,120 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include <windows.h>
+#include "version.h"
+#include "resource.h"
+#include "aspnetcore_msg.rc"
+/////////////////////////////////////////////////////////////////////////////
+// English (United States) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+
+#define FileDescription "IIS AspNetCore Module. Commit: " CommitHash
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// 11
+//
+
+//1 11
+//BEGIN
+//    0x0001, 0x0000, 0x03e8, 0x0000, 0x03ed, 0x0000, 0x0010, 0x0000, 0x0010, 
+//    0x0001, 0x0025, 0x0031, 0x000d, 0x000a, 0x0000, 0x0000, 0x0010, 0x0001, 
+//    0x0025, 0x0031, 0x000d, 0x000a, 0x0000, 0x0000, 0x0010, 0x0001, 0x0025, 
+//    0x0031, 0x000d, 0x000a, 0x0000, 0x0000, 0x0010, 0x0001, 0x0025, 0x0031, 
+//    0x000d, 0x000a, 0x0000, 0x0000, 0x0010, 0x0001, 0x0025, 0x0031, 0x000d, 
+//    0x000a, 0x0000, 0x0000, 0x0010, 0x0001, 0x0025, 0x0031, 0x000d, 0x000a, 
+//    0x0000, 0x0000
+//END
+
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE 
+BEGIN
+    "resource.h\0"
+END
+
+2 TEXTINCLUDE 
+BEGIN
+    "\0"
+END
+
+3 TEXTINCLUDE 
+BEGIN
+    "\r\n"
+    "\0"
+END
+
+#endif    // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION FileVersion
+ PRODUCTVERSION ProductVersion
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x40004L
+ FILETYPE 0x2L
+ FILESUBTYPE 0x0L
+BEGIN
+    BLOCK "StringFileInfo"
+    BEGIN
+        BLOCK "040904b0"
+        BEGIN
+            VALUE "CompanyName", "Microsoft"
+            VALUE "FileDescription", FileDescription
+            VALUE "FileVersion", FileVersionStr
+            VALUE "InternalName", "aspnetcore.dll"
+            VALUE "LegalCopyright", "Copyright (C) 2016"
+            VALUE "OriginalFilename", "aspnetcore.dll"
+            VALUE "ProductName", "ASP.NET Core Module"
+            VALUE "ProductVersion", ProductVersionStr
+        END
+    END
+    BLOCK "VarFileInfo"
+    BEGIN
+        VALUE "Translation", 0x409, 1200
+    END
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// String Table
+//
+
+STRINGTABLE
+BEGIN
+    IDS_INVALID_PROPERTY    "Property name '%s' in system.webServer/aspNetCore section has invalid value '%s' which does not conform to the prescribed format"
+    IDS_SERVER_ERROR        "There was a connection error while trying to route the request."
+END
+
+#endif    // English (United States) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif    // not APSTUDIO_INVOKED
diff --git a/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/resource.h b/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/resource.h
new file mode 100644
index 0000000000000000000000000000000000000000..493c3e2797f2641ccbe058f0eab0d15f9fb28118
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/resource.h
@@ -0,0 +1,18 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by aspnetcoremodule.rc
+//
+#define ASPNETCORE_EVENT_MSG_BUFFER_SIZE 256
+#define IDS_INVALID_PROPERTY            1000
+#define IDS_SERVER_ERROR                1001
+
+// Next default values for new objects
+// 
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE        101
+#define _APS_NEXT_COMMAND_VALUE         40001
+#define _APS_NEXT_CONTROL_VALUE         1000
+#define _APS_NEXT_SYMED_VALUE           101
+#endif
+#endif
diff --git a/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/src/application.cxx b/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/src/application.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..f80435cfbb358891a62fae3af5f7868a00df4074
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/src/application.cxx
@@ -0,0 +1,164 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#include "precomp.hxx"
+
+APPLICATION::~APPLICATION()
+{
+    if (m_pAppOfflineHtm != NULL)
+    {
+        m_pAppOfflineHtm->DereferenceAppOfflineHtm();
+        m_pAppOfflineHtm = NULL;
+    }
+
+    if (m_pFileWatcherEntry != NULL)
+    {
+        // Mark the entry as invalid,
+        // StopMonitor will close the file handle and trigger a FCN
+        // the entry will delete itself when processing this FCN 
+        m_pFileWatcherEntry->MarkEntryInValid();
+        m_pFileWatcherEntry->StopMonitor();
+        m_pFileWatcherEntry = NULL;
+    }
+
+    if (m_pProcessManager != NULL)
+    {
+        m_pProcessManager->ShutdownAllProcesses();
+        m_pProcessManager->DereferenceProcessManager();
+        m_pProcessManager = NULL;
+    }
+}
+
+HRESULT
+APPLICATION::Initialize(
+    _In_ APPLICATION_MANAGER* pApplicationManager,
+    _In_ LPCWSTR  pszApplication,
+    _In_ LPCWSTR  pszPhysicalPath
+)
+{
+    HRESULT hr = S_OK;
+
+    DBG_ASSERT(pszPhysicalPath != NULL);
+    DBG_ASSERT(pApplicationManager != NULL);
+    DBG_ASSERT(pszPhysicalPath != NULL);
+    m_strAppPhysicalPath.Copy(pszPhysicalPath);
+
+    m_pApplicationManager = pApplicationManager;
+
+    hr = m_applicationKey.Initialize(pszApplication);
+    if (FAILED(hr))
+    {
+        goto Finished;
+    }
+
+    if (m_pProcessManager == NULL)
+    {
+        m_pProcessManager = new PROCESS_MANAGER;
+        if (m_pProcessManager == NULL)
+        {
+            hr = E_OUTOFMEMORY;
+            goto Finished;
+        }
+
+        hr = m_pProcessManager->Initialize();
+        if (FAILED(hr))
+        {
+            goto Finished;
+        }
+    }
+
+    if (m_pFileWatcherEntry == NULL)
+    {
+        m_pFileWatcherEntry = new FILE_WATCHER_ENTRY(pApplicationManager->GetFileWatcher());
+        if (m_pFileWatcherEntry == NULL)
+        {
+            hr = E_OUTOFMEMORY;
+            goto Finished;
+        }
+    }
+
+    UpdateAppOfflineFileHandle();
+
+Finished:
+
+    if (FAILED(hr))
+    {
+        if (m_pFileWatcherEntry != NULL)
+        {
+            m_pFileWatcherEntry->DereferenceFileWatcherEntry();
+            m_pFileWatcherEntry = NULL;
+        }
+
+        if (m_pProcessManager != NULL)
+        {
+            m_pProcessManager->DereferenceProcessManager();
+            m_pProcessManager = NULL;
+        }
+    }
+
+    return hr;
+}
+
+HRESULT
+APPLICATION::StartMonitoringAppOffline()
+{
+    HRESULT hr = S_OK;
+
+    hr = m_pFileWatcherEntry->Create(m_strAppPhysicalPath.QueryStr(), L"app_offline.htm", this, NULL);
+
+    return hr;
+}
+
+VOID
+APPLICATION::UpdateAppOfflineFileHandle()
+{
+    STRU strFilePath;
+    PATH::ConvertPathToFullPath(L".\\app_offline.htm", m_strAppPhysicalPath.QueryStr(), &strFilePath);
+    APP_OFFLINE_HTM *pOldAppOfflineHtm = NULL;
+    APP_OFFLINE_HTM *pNewAppOfflineHtm = NULL;
+
+    if (INVALID_FILE_ATTRIBUTES == GetFileAttributes(strFilePath.QueryStr()) && GetLastError() == ERROR_FILE_NOT_FOUND)
+    {
+        m_fAppOfflineFound = FALSE;
+    }
+    else
+    {
+        m_fAppOfflineFound = TRUE;
+        
+        //
+        // send shutdown signal
+        //
+
+        // The reason why we send the shutdown signal before loading the new app_offline file is because we want to make some delay 
+        // before reading the appoffline.htm so that the file change can be done on time.
+        if (m_pProcessManager != NULL)
+        {
+            m_pProcessManager->SendShutdownSignal();
+        }
+
+        pNewAppOfflineHtm = new APP_OFFLINE_HTM(strFilePath.QueryStr());
+
+        if ( pNewAppOfflineHtm != NULL )
+        {
+            if (pNewAppOfflineHtm->Load())
+            {
+                //
+                // loaded the new app_offline.htm
+                //
+                pOldAppOfflineHtm = (APP_OFFLINE_HTM *)InterlockedExchangePointer((VOID**)&m_pAppOfflineHtm, pNewAppOfflineHtm);
+
+                if (pOldAppOfflineHtm != NULL)
+                {
+                    pOldAppOfflineHtm->DereferenceAppOfflineHtm();
+                    pOldAppOfflineHtm = NULL;
+                }
+            }
+            else
+            {
+                // ignored the new app_offline file because the file does not exist.
+                pNewAppOfflineHtm->DereferenceAppOfflineHtm(); 
+                pNewAppOfflineHtm = NULL;
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/src/applicationmanager.cxx b/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/src/applicationmanager.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..41f20013b719432c00cf7ec653b53280fa0054e4
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/src/applicationmanager.cxx
@@ -0,0 +1,178 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#include "precomp.hxx"
+
+APPLICATION_MANAGER* APPLICATION_MANAGER::sm_pApplicationManager = NULL;
+
+HRESULT
+APPLICATION_MANAGER::GetApplication(
+    _In_ IHttpContext*         pContext,
+    _Out_ APPLICATION **       ppApplication
+)
+{
+    HRESULT          hr = S_OK;
+    APPLICATION     *pApplication = NULL;
+    APPLICATION_KEY  key;
+    BOOL             fExclusiveLock = FALSE;
+    PCWSTR           pszApplicationId = NULL;
+
+    *ppApplication = NULL;
+    
+    DBG_ASSERT(pContext != NULL);
+    DBG_ASSERT(pContext->GetApplication() != NULL);
+    pszApplicationId = pContext->GetApplication()->GetApplicationId();
+
+    hr = key.Initialize(pszApplicationId);
+    if (FAILED(hr))
+    {
+        goto Finished;
+    }
+
+    m_pApplicationHash->FindKey(&key, ppApplication);
+
+    if (*ppApplication == NULL)
+    {
+
+        pApplication = new APPLICATION();
+        if (pApplication == NULL)
+        {
+            hr = E_OUTOFMEMORY;
+            goto Finished;
+        }
+
+        AcquireSRWLockExclusive(&m_srwLock);
+        fExclusiveLock = TRUE;
+        m_pApplicationHash->FindKey(&key, ppApplication);
+
+        if (*ppApplication != NULL)
+        {
+            // someone else created the application
+            delete pApplication;
+            pApplication = NULL;
+            goto Finished;
+        }
+
+        hr = pApplication->Initialize(this, pszApplicationId, pContext->GetApplication()->GetApplicationPhysicalPath());
+        if (FAILED(hr))
+        {
+            goto Finished;
+        }
+
+        hr = m_pApplicationHash->InsertRecord( pApplication );
+
+        if (FAILED(hr))
+        {
+            goto Finished;
+        }
+        ReleaseSRWLockExclusive(&m_srwLock);
+        fExclusiveLock = FALSE;
+
+        pApplication->StartMonitoringAppOffline();
+
+        *ppApplication = pApplication;
+        pApplication = NULL;
+    }
+
+Finished:
+
+    if (fExclusiveLock == TRUE)
+        ReleaseSRWLockExclusive(&m_srwLock);
+
+    if (FAILED(hr))
+    {
+        if (pApplication != NULL)
+        {
+            pApplication->DereferenceApplication();
+            pApplication = NULL;
+        }
+    }
+
+    return hr;
+}
+
+
+HRESULT
+APPLICATION_MANAGER::RecycleApplication(
+    _In_ LPCWSTR pszApplication
+)
+{
+    HRESULT          hr = S_OK;
+    APPLICATION_KEY  key;
+
+    hr = key.Initialize(pszApplication);
+    if (FAILED(hr))
+    {
+        goto Finished;
+    }
+    AcquireSRWLockExclusive(&m_srwLock);
+    m_pApplicationHash->DeleteKey(&key);
+    ReleaseSRWLockExclusive(&m_srwLock);
+
+Finished:
+
+    return hr;
+}
+
+HRESULT
+APPLICATION_MANAGER::Get502ErrorPage(
+    _Out_ HTTP_DATA_CHUNK**     ppErrorPage
+)
+{
+    HRESULT           hr = S_OK;
+    BOOL              fExclusiveLock = FALSE;
+    HTTP_DATA_CHUNK  *pHttp502ErrorPage = NULL;
+
+    DBG_ASSERT(ppErrorPage != NULL);
+
+    //on-demand create the error page
+    if (m_pHttp502ErrorPage != NULL)
+    {
+        *ppErrorPage = m_pHttp502ErrorPage;
+    }
+    else
+    {
+        AcquireSRWLockExclusive(&m_srwLock);
+        fExclusiveLock = TRUE;
+        if (m_pHttp502ErrorPage != NULL)
+        {
+            *ppErrorPage = m_pHttp502ErrorPage;
+        }
+        else
+        {
+            size_t maxsize = 5000;
+            pHttp502ErrorPage = new HTTP_DATA_CHUNK();
+            if (pHttp502ErrorPage == NULL)
+            {
+                hr = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
+                goto Finished;
+            }
+            pHttp502ErrorPage->DataChunkType = HttpDataChunkFromMemory;
+            pHttp502ErrorPage->FromMemory.pBuffer = (PVOID)m_pstrErrorInfo;
+
+            pHttp502ErrorPage->FromMemory.BufferLength = (ULONG)strnlen(m_pstrErrorInfo, maxsize); //(ULONG)(wcslen(m_pstrErrorInfo)); // *sizeof(WCHAR);
+            if(m_pHttp502ErrorPage != NULL)
+            {
+                delete m_pHttp502ErrorPage;
+            }
+            m_pHttp502ErrorPage = pHttp502ErrorPage;
+            *ppErrorPage = m_pHttp502ErrorPage;
+        }
+    }
+
+Finished:
+    if (fExclusiveLock)
+    {
+        ReleaseSRWLockExclusive(&m_srwLock);
+    }
+
+    if (FAILED(hr))
+    {
+        if (pHttp502ErrorPage != NULL)
+        {
+            delete pHttp502ErrorPage;
+        }
+    }
+
+    return hr;
+}
diff --git a/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/src/aspnetcoreconfig.cxx b/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/src/aspnetcoreconfig.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..d8bcd8d777b568160fe5e6d5684072b2c476470d
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/src/aspnetcoreconfig.cxx
@@ -0,0 +1,416 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#include "precomp.hxx"
+
+ASPNETCORE_CONFIG::~ASPNETCORE_CONFIG()
+{
+    //
+    // the destructor will be called once IIS decides to recycle the module context (i.e., application)
+    //
+    if (!m_struApplication.IsEmpty())
+    {
+        APPLICATION_MANAGER::GetInstance()->RecycleApplication(m_struApplication.QueryStr());
+    }
+    if(m_pEnvironmentVariables != NULL)
+    {
+        m_pEnvironmentVariables->Clear();
+        delete m_pEnvironmentVariables;
+        m_pEnvironmentVariables = NULL;
+    }
+}
+
+HRESULT
+ASPNETCORE_CONFIG::GetConfig(
+    _In_  IHttpContext            *pHttpContext,
+    _Out_ ASPNETCORE_CONFIG     **ppAspNetCoreConfig
+)
+{
+    HRESULT                 hr = S_OK;
+    IHttpApplication       *pHttpApplication = pHttpContext->GetApplication();
+    ASPNETCORE_CONFIG      *pAspNetCoreConfig = NULL;
+
+    if (ppAspNetCoreConfig == NULL)
+    {
+        hr = E_INVALIDARG;
+        goto Finished;
+    }
+
+    *ppAspNetCoreConfig = NULL;
+
+    // potential bug if user sepcific config at virtual dir level
+    pAspNetCoreConfig = (ASPNETCORE_CONFIG*)
+        pHttpApplication->GetModuleContextContainer()->GetModuleContext(g_pModuleId);
+
+    if (pAspNetCoreConfig != NULL)
+    {
+        *ppAspNetCoreConfig = pAspNetCoreConfig;
+        pAspNetCoreConfig = NULL;
+        goto Finished;
+    }
+
+    pAspNetCoreConfig = new ASPNETCORE_CONFIG;
+    if (pAspNetCoreConfig == NULL)
+    {
+        hr = E_OUTOFMEMORY;
+        goto Finished;
+    }
+
+    hr = pAspNetCoreConfig->Populate(pHttpContext);
+    if (FAILED(hr))
+    {
+        goto Finished;
+    }
+
+    hr = pHttpApplication->GetModuleContextContainer()->
+        SetModuleContext(pAspNetCoreConfig, g_pModuleId);
+    if (FAILED(hr))
+    {
+        if (hr == HRESULT_FROM_WIN32(ERROR_ALREADY_ASSIGNED))
+        {
+            delete pAspNetCoreConfig;
+
+            pAspNetCoreConfig = (ASPNETCORE_CONFIG*)pHttpApplication->
+                                 GetModuleContextContainer()->
+                                 GetModuleContext(g_pModuleId);
+
+            _ASSERT(pAspNetCoreConfig != NULL);
+
+            hr = S_OK;
+        }
+        else
+        {
+            goto Finished;
+        }
+    }
+    else
+    {
+        // set appliction info here instead of inside Populate()
+        // as the destructor will delete the backend process 
+        hr = pAspNetCoreConfig->QueryApplicationPath()->Copy(pHttpApplication->GetApplicationId());
+        if (FAILED(hr))
+        {
+            goto Finished;
+        }
+    }
+
+    *ppAspNetCoreConfig = pAspNetCoreConfig;
+    pAspNetCoreConfig = NULL;
+
+Finished:
+
+    if (pAspNetCoreConfig != NULL)
+    {
+        delete pAspNetCoreConfig;
+        pAspNetCoreConfig = NULL;
+    }
+
+    return hr;
+}
+
+HRESULT
+ASPNETCORE_CONFIG::Populate(
+    IHttpContext   *pHttpContext
+)
+{
+    HRESULT                         hr = S_OK;
+    STACK_STRU(strSiteConfigPath, 256);
+    STRU                            strEnvName;
+    STRU                            strEnvValue;
+    STRU                            strExpandedEnvValue;
+    IAppHostAdminManager           *pAdminManager = NULL;
+    IAppHostElement                *pAspNetCoreElement = NULL;
+    IAppHostElement                *pWindowsAuthenticationElement = NULL;
+    IAppHostElement                *pBasicAuthenticationElement = NULL;
+    IAppHostElement                *pAnonymousAuthenticationElement = NULL;
+    IAppHostElement                *pEnvVarList = NULL;
+    IAppHostElement                *pEnvVar = NULL;
+    IAppHostElementCollection      *pEnvVarCollection = NULL;
+    ULONGLONG                       ullRawTimeSpan = 0;
+    ENUM_INDEX                      index;
+    ENVIRONMENT_VAR_ENTRY*          pEntry = NULL;
+
+    m_pEnvironmentVariables = new ENVIRONMENT_VAR_HASH();
+    if (m_pEnvironmentVariables == NULL)
+    {
+        hr = E_OUTOFMEMORY;
+        goto Finished;
+    }
+    if (FAILED(hr = m_pEnvironmentVariables->Initialize(37 /*prime*/)))
+    {
+        delete m_pEnvironmentVariables;
+        m_pEnvironmentVariables = NULL;
+        goto Finished;
+    }
+
+    pAdminManager = g_pHttpServer->GetAdminManager();
+
+    hr = strSiteConfigPath.Copy(pHttpContext->GetApplication()->GetAppConfigPath());
+    if (FAILED(hr))
+    {
+        goto Finished;
+    }
+
+    hr = pAdminManager->GetAdminSection(CS_WINDOWS_AUTHENTICATION_SECTION,
+        strSiteConfigPath.QueryStr(),
+        &pWindowsAuthenticationElement);
+    if (FAILED(hr))
+    {
+        // assume the corresponding authen was not enabled
+        // as the section may get deleted by user in some HWC case
+        // ToDo: log a warning to event log
+        m_fWindowsAuthEnabled = FALSE;
+    }
+    else
+    {
+        hr = GetElementBoolProperty(pWindowsAuthenticationElement,
+            CS_AUTHENTICATION_ENABLED,
+            &m_fWindowsAuthEnabled);
+        if (FAILED(hr))
+        {
+            goto Finished;
+        }
+    }
+
+    hr = pAdminManager->GetAdminSection(CS_BASIC_AUTHENTICATION_SECTION,
+        strSiteConfigPath.QueryStr(),
+        &pBasicAuthenticationElement);
+    if (FAILED(hr))
+    {
+        m_fBasicAuthEnabled = FALSE;
+    }
+    else
+    {
+        hr = GetElementBoolProperty(pBasicAuthenticationElement,
+            CS_AUTHENTICATION_ENABLED,
+            &m_fBasicAuthEnabled);
+        if (FAILED(hr))
+        {
+            goto Finished;
+        }
+    }
+
+    hr = pAdminManager->GetAdminSection(CS_ANONYMOUS_AUTHENTICATION_SECTION,
+        strSiteConfigPath.QueryStr(),
+        &pAnonymousAuthenticationElement);
+    if (FAILED(hr))
+    {
+        m_fAnonymousAuthEnabled = FALSE;
+    }
+    else
+    {
+        hr = GetElementBoolProperty(pAnonymousAuthenticationElement,
+            CS_AUTHENTICATION_ENABLED,
+            &m_fAnonymousAuthEnabled);
+        if (FAILED(hr))
+        {
+            goto Finished;
+        }
+    }
+
+    hr = pAdminManager->GetAdminSection(CS_ASPNETCORE_SECTION,
+        strSiteConfigPath.QueryStr(),
+        &pAspNetCoreElement);
+    if (FAILED(hr))
+    {
+        goto Finished;
+    }
+
+    hr = GetElementStringProperty(pAspNetCoreElement,
+        CS_ASPNETCORE_PROCESS_EXE_PATH,
+        &m_struProcessPath);
+    if (FAILED(hr))
+    {
+        goto Finished;
+    }
+
+    hr = GetElementStringProperty(pAspNetCoreElement,
+        CS_ASPNETCORE_PROCESS_ARGUMENTS,
+        &m_struArguments);
+    if (FAILED(hr))
+    {
+        goto Finished;
+    }
+
+    hr = GetElementDWORDProperty(pAspNetCoreElement,
+        CS_ASPNETCORE_RAPID_FAILS_PER_MINUTE,
+        &m_dwRapidFailsPerMinute);
+    if (FAILED(hr))
+    {
+        goto Finished;
+    }
+
+    //
+    // rapidFailsPerMinute cannot be greater than 100.
+    //
+    if (m_dwRapidFailsPerMinute > MAX_RAPID_FAILS_PER_MINUTE)
+    {
+        m_dwRapidFailsPerMinute = MAX_RAPID_FAILS_PER_MINUTE;
+    }
+
+    hr = GetElementDWORDProperty(pAspNetCoreElement,
+        CS_ASPNETCORE_PROCESSES_PER_APPLICATION,
+        &m_dwProcessesPerApplication);
+    if (FAILED(hr))
+    {
+        goto Finished;
+    }
+
+    hr = GetElementDWORDProperty(
+        pAspNetCoreElement,
+        CS_ASPNETCORE_PROCESS_STARTUP_TIME_LIMIT,
+        &m_dwStartupTimeLimitInMS
+    );
+    if (FAILED(hr))
+    {
+        goto Finished;
+    }
+
+    m_dwStartupTimeLimitInMS *= MILLISECONDS_IN_ONE_SECOND;
+
+    hr = GetElementDWORDProperty(
+        pAspNetCoreElement,
+        CS_ASPNETCORE_PROCESS_SHUTDOWN_TIME_LIMIT,
+        &m_dwShutdownTimeLimitInMS
+    );
+    if (FAILED(hr))
+    {
+        goto Finished;
+    }
+    m_dwShutdownTimeLimitInMS *= MILLISECONDS_IN_ONE_SECOND;
+
+    hr = GetElementBoolProperty(pAspNetCoreElement,
+        CS_ASPNETCORE_FORWARD_WINDOWS_AUTH_TOKEN,
+        &m_fForwardWindowsAuthToken);
+    if (FAILED(hr))
+    {
+        goto Finished;
+    }
+
+    hr = GetElementBoolProperty(pAspNetCoreElement,
+        CS_ASPNETCORE_DISABLE_START_UP_ERROR_PAGE,
+        &m_fDisableStartUpErrorPage);
+    if (FAILED(hr))
+    {
+        goto Finished;
+    }
+
+    hr = GetElementRawTimeSpanProperty(
+        pAspNetCoreElement,
+        CS_ASPNETCORE_WINHTTP_REQUEST_TIMEOUT,
+        &ullRawTimeSpan
+    );
+    if (FAILED(hr))
+    {
+        goto Finished;
+    }
+
+    m_dwRequestTimeoutInMS = (DWORD)TIMESPAN_IN_MILLISECONDS(ullRawTimeSpan);
+
+    hr = GetElementBoolProperty(pAspNetCoreElement,
+        CS_ASPNETCORE_STDOUT_LOG_ENABLED,
+        &m_fStdoutLogEnabled);
+    if (FAILED(hr))
+    {
+        goto Finished;
+    }
+
+    hr = GetElementStringProperty(pAspNetCoreElement,
+        CS_ASPNETCORE_STDOUT_LOG_FILE,
+        &m_struStdoutLogFile);
+    if (FAILED(hr))
+    {
+        goto Finished;
+    }
+
+    hr = GetElementChildByName(pAspNetCoreElement,
+        CS_ASPNETCORE_ENVIRONMENT_VARIABLES,
+        &pEnvVarList);
+    if (FAILED(hr))
+    {
+        goto Finished;
+    }
+
+    hr = pEnvVarList->get_Collection(&pEnvVarCollection);
+    if (FAILED(hr))
+    {
+        goto Finished;
+    }
+
+    for (hr = FindFirstElement(pEnvVarCollection, &index, &pEnvVar);
+        SUCCEEDED(hr);
+        hr = FindNextElement(pEnvVarCollection, &index, &pEnvVar))
+    {
+        if (hr == S_FALSE)
+        {
+            hr = S_OK;
+            break;
+        }
+
+        if (FAILED(hr = GetElementStringProperty(pEnvVar,
+            CS_ASPNETCORE_ENVIRONMENT_VARIABLE_NAME,
+            &strEnvName)) ||
+            FAILED(hr = GetElementStringProperty(pEnvVar,
+                CS_ASPNETCORE_ENVIRONMENT_VARIABLE_VALUE,
+                &strEnvValue)) ||
+            FAILED(hr = strEnvName.Append(L"=")) ||
+            FAILED(hr = STRU::ExpandEnvironmentVariables(strEnvValue.QueryStr(), &strExpandedEnvValue)))
+        {
+            goto Finished;
+        }
+
+        pEntry = new ENVIRONMENT_VAR_ENTRY();
+        if (pEntry == NULL)
+        {
+            hr = E_OUTOFMEMORY;
+            goto Finished;
+        }
+
+        if (FAILED(hr = pEntry->Initialize(strEnvName.QueryStr(), strExpandedEnvValue.QueryStr())) ||
+            FAILED(hr = m_pEnvironmentVariables->InsertRecord(pEntry)))
+        {
+            goto Finished;
+        }
+        strEnvName.Reset();
+        strEnvValue.Reset();
+        strExpandedEnvValue.Reset();
+        pEnvVar->Release();
+        pEnvVar = NULL;
+        pEntry->Dereference();
+        pEntry = NULL;
+    }
+
+Finished:
+
+    if (pAspNetCoreElement != NULL)
+    {
+        pAspNetCoreElement->Release();
+        pAspNetCoreElement = NULL;
+    }
+
+    if (pEnvVarList != NULL)
+    {
+        pEnvVarList->Release();
+        pEnvVarList = NULL;
+    }
+
+    if (pEnvVar != NULL)
+    {
+        pEnvVar->Release();
+        pEnvVar = NULL;
+    }
+
+    if (pEnvVarCollection != NULL)
+    {
+        pEnvVarCollection->Release();
+        pEnvVarCollection = NULL;
+    }
+
+    if (pEntry != NULL)
+    {
+        pEntry->Dereference();
+        pEntry = NULL;
+    }
+
+    return hr;
+}
\ No newline at end of file
diff --git a/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/src/filewatcher.cxx b/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/src/filewatcher.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..086ed8774f24757d75186f5e865ab753f803132a
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/src/filewatcher.cxx
@@ -0,0 +1,481 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#include "precomp.hxx"
+
+FILE_WATCHER::FILE_WATCHER() :
+    m_hCompletionPort(NULL),
+    m_hChangeNotificationThread(NULL)
+{
+}
+
+FILE_WATCHER::~FILE_WATCHER()
+{
+    if (m_hChangeNotificationThread != NULL)
+    {
+        CloseHandle(m_hChangeNotificationThread);
+        m_hChangeNotificationThread = NULL;
+    }
+}
+
+HRESULT
+FILE_WATCHER::Create(
+    VOID
+)
+{
+    HRESULT                 hr = S_OK;
+
+    m_hCompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE,
+        NULL,
+        0,
+        0);
+
+    if (m_hCompletionPort == NULL)
+    {
+        hr = HRESULT_FROM_WIN32(GetLastError());
+        goto Finished;
+    }
+
+    m_hChangeNotificationThread = CreateThread(NULL,
+        0,
+        ChangeNotificationThread,
+        this,
+        0,
+        NULL);
+
+    if (m_hChangeNotificationThread == NULL)
+    {
+        hr = HRESULT_FROM_WIN32(GetLastError());
+
+        CloseHandle(m_hCompletionPort);
+        m_hCompletionPort = NULL;
+
+        goto Finished;
+    }
+
+Finished:
+    return hr;
+}
+
+DWORD
+WINAPI
+FILE_WATCHER::ChangeNotificationThread(
+    LPVOID  pvArg
+)
+/*++
+
+Routine Description:
+
+IO completion thread
+
+Arguments:
+
+None
+
+Return Value:
+
+Win32 error
+
+--*/
+{
+    FILE_WATCHER *       pFileMonitor;
+    BOOL                 fSuccess = FALSE;
+    DWORD                cbCompletion = 0;
+    OVERLAPPED *         pOverlapped = NULL;
+    DWORD                dwErrorStatus;
+    ULONG_PTR            completionKey;
+
+    pFileMonitor = (FILE_WATCHER*)pvArg;
+    DBG_ASSERT(pFileMonitor != NULL);
+
+    while (TRUE)
+    {
+        fSuccess = GetQueuedCompletionStatus(
+            pFileMonitor->m_hCompletionPort,
+            &cbCompletion,
+            &completionKey,
+            &pOverlapped,
+            INFINITE);
+
+        DBG_ASSERT(fSuccess);
+        DebugPrint(1, "FILE_WATCHER::ChangeNotificationThread");
+        dwErrorStatus = fSuccess ? ERROR_SUCCESS : GetLastError();
+
+        if (completionKey == FILE_WATCHER_SHUTDOWN_KEY)
+        {
+            continue;
+        }
+
+        DBG_ASSERT(pOverlapped != NULL);
+        if (pOverlapped != NULL)
+        {
+            FileWatcherCompletionRoutine(
+                dwErrorStatus,
+                cbCompletion,
+                pOverlapped);
+        }
+        pOverlapped = NULL;
+        cbCompletion = 0;
+    }
+}
+
+VOID
+WINAPI
+FILE_WATCHER::FileWatcherCompletionRoutine(
+    DWORD                   dwCompletionStatus,
+    DWORD                   cbCompletion,
+    OVERLAPPED *            pOverlapped
+)
+/*++
+
+Routine Description:
+
+Called when ReadDirectoryChangesW() completes
+
+Arguments:
+
+dwCompletionStatus - Error of completion
+cbCompletion - Bytes of completion
+pOverlapped - State of completion
+
+Return Value:
+
+None
+
+--*/
+{
+    FILE_WATCHER_ENTRY *     pMonitorEntry;
+    pMonitorEntry = CONTAINING_RECORD(pOverlapped, FILE_WATCHER_ENTRY, _overlapped);
+    pMonitorEntry->DereferenceFileWatcherEntry();
+    DBG_ASSERT(pMonitorEntry != NULL);
+
+    pMonitorEntry->HandleChangeCompletion(dwCompletionStatus, cbCompletion);
+
+    if (pMonitorEntry->QueryIsValid())
+    {
+        //
+        // Continue monitoring
+        //
+        pMonitorEntry->Monitor();
+    }
+    else
+    {
+        //
+        // Marked by application distructor
+        // Deference the entry to delete it
+        // 
+        pMonitorEntry->DereferenceFileWatcherEntry();
+    }
+}
+
+
+FILE_WATCHER_ENTRY::FILE_WATCHER_ENTRY(FILE_WATCHER *   pFileMonitor) :
+    _pFileMonitor(pFileMonitor),
+    _hDirectory(INVALID_HANDLE_VALUE),
+    _hImpersonationToken(NULL),
+    _pApplication(NULL),
+    _lStopMonitorCalled(0),
+    _cRefs(1),
+    _fIsValid(TRUE)
+{
+    _dwSignature = FILE_WATCHER_ENTRY_SIGNATURE;
+    InitializeSRWLock(&_srwLock);
+}
+
+FILE_WATCHER_ENTRY::~FILE_WATCHER_ENTRY()
+{
+    _dwSignature = FILE_WATCHER_ENTRY_SIGNATURE_FREE;
+
+    if (_hDirectory != INVALID_HANDLE_VALUE)
+    {
+        CloseHandle(_hDirectory);
+        _hDirectory = INVALID_HANDLE_VALUE;
+    }
+
+    if (_hImpersonationToken != NULL)
+    {
+        CloseHandle(_hImpersonationToken);
+        _hImpersonationToken = NULL;
+    }
+}
+
+#pragma warning(disable:4100)
+
+HRESULT
+FILE_WATCHER_ENTRY::HandleChangeCompletion(
+    _In_ DWORD          dwCompletionStatus,
+    _In_ DWORD          cbCompletion
+)
+/*++
+
+Routine Description:
+
+Handle change notification (see if any of associated config files
+need to be flushed)
+
+Arguments:
+
+dwCompletionStatus - Completion status
+cbCompletion - Bytes of completion
+
+Return Value:
+
+HRESULT
+
+--*/
+{
+    HRESULT                     hr = S_OK;
+    FILE_NOTIFY_INFORMATION *   pNotificationInfo;
+    BOOL                        fFileChanged = FALSE;
+    STRU                        strEventMsg;
+
+    AcquireSRWLockExclusive(&_srwLock);
+    if (!_fIsValid)
+    {
+        goto Finished;
+    }
+
+    // When directory handle is closed then HandleChangeCompletion  
+    // happens with cbCompletion = 0 and dwCompletionStatus = 0  
+    // From documentation it is not clear if that combination  
+    // of return values is specific to closing handles or whether  
+    // it could also mean an error condition. Hence we will maintain  
+    // explicit flag that will help us determine if entry   
+    // is being shutdown (StopMonitor() called)  
+    //  
+    if (_lStopMonitorCalled)
+    {
+        goto Finished;
+    }
+
+    //
+    // There could be a FCN overflow
+    // Let assume the file got changed instead of checking files 
+    // Othersie we have to cache the file info 
+    //
+    if (cbCompletion == 0)
+    { 
+        fFileChanged = TRUE;
+    }
+    else
+    {
+        pNotificationInfo = (FILE_NOTIFY_INFORMATION*)_buffDirectoryChanges.QueryPtr();
+        DBG_ASSERT(pNotificationInfo != NULL);
+
+        while (pNotificationInfo != NULL)
+        {
+            //
+            // check whether the monitored file got changed
+            //
+            if (_wcsnicmp(pNotificationInfo->FileName,
+                _strFileName.QueryStr(),
+                pNotificationInfo->FileNameLength/sizeof(WCHAR)) == 0)
+            {
+                fFileChanged = TRUE;
+                break;
+            }
+            //
+            // Advance to next notification
+            //
+            if (pNotificationInfo->NextEntryOffset == 0)
+            {
+                pNotificationInfo = NULL;
+            }
+            else
+            {
+                pNotificationInfo = (FILE_NOTIFY_INFORMATION*)
+                    ((PBYTE)pNotificationInfo +
+                    pNotificationInfo->NextEntryOffset);
+            }
+        }
+    }
+
+    if (fFileChanged)
+    {
+        LPCWSTR                 apsz[1];
+        if (SUCCEEDED(strEventMsg.SafeSnwprintf(
+            ASPNETCORE_EVENT_RECYCLE_APPOFFLINE_MSG,
+            _strFileName.QueryStr())))
+        {
+            apsz[0] = strEventMsg.QueryStr();
+
+            //
+            // not checking return code because if ReportEvent
+            // fails, we cannot do anything.
+            //
+            if (FORWARDING_HANDLER::QueryEventLog() != NULL)
+            {
+                ReportEventW(FORWARDING_HANDLER::QueryEventLog(),
+                    EVENTLOG_INFORMATION_TYPE,
+                    0,
+                    ASPNETCORE_EVENT_RECYCLE_APPOFFLINE,
+                    NULL,
+                    1,
+                    0,
+                    apsz,
+                    NULL);
+            }
+        }
+        //
+        // so far we only monitoring app_offline
+        //
+        _pApplication->UpdateAppOfflineFileHandle();
+    }
+
+Finished:
+    ReleaseSRWLockExclusive(&_srwLock);
+    return hr;
+}
+
+#pragma warning( error : 4100 )
+
+HRESULT
+FILE_WATCHER_ENTRY::Monitor(VOID)
+{
+    HRESULT hr = S_OK;
+    DWORD   cbRead;
+
+    AcquireSRWLockExclusive(&_srwLock);
+    ReferenceFileWatcherEntry();
+    ZeroMemory(&_overlapped, sizeof(_overlapped));
+
+    if(!ReadDirectoryChangesW(_hDirectory,
+        _buffDirectoryChanges.QueryPtr(),
+        _buffDirectoryChanges.QuerySize(),
+        FALSE,        // Watching sub dirs. Set to False now as only monitoring app_offline
+        FILE_NOTIFY_VALID_MASK & ~FILE_NOTIFY_CHANGE_LAST_ACCESS, 
+        &cbRead,
+        &_overlapped,
+        NULL))
+    {
+        hr = HRESULT_FROM_WIN32(GetLastError());
+    }
+
+    ReleaseSRWLockExclusive(&_srwLock);
+    return hr;
+}
+
+VOID
+FILE_WATCHER_ENTRY::StopMonitor(VOID)
+{
+    //
+    // Flag that monitoring is being stopped so that
+    // we know that HandleChangeCompletion() call
+    // can be ignored
+    //
+    InterlockedExchange(&_lStopMonitorCalled, 1);
+
+    AcquireSRWLockExclusive(&_srwLock);
+
+    if (_hDirectory != INVALID_HANDLE_VALUE)
+    {
+        CloseHandle(_hDirectory);
+        _hDirectory = INVALID_HANDLE_VALUE;
+    }
+
+    ReleaseSRWLockExclusive(&_srwLock);
+}
+
+HRESULT
+FILE_WATCHER_ENTRY::Create(
+    _In_ PCWSTR                  pszDirectoryToMonitor,
+    _In_ PCWSTR                  pszFileNameToMonitor,
+    _In_ APPLICATION*            pApplication,
+    _In_ HANDLE                  hImpersonationToken
+)
+{
+    HRESULT             hr = S_OK;
+    BOOL                fRet = FALSE;
+
+    if (pszDirectoryToMonitor == NULL ||
+        pszFileNameToMonitor == NULL ||
+        pApplication == NULL)
+    {
+        DBG_ASSERT(FALSE);
+        hr = HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
+        goto Finished;
+    }
+
+    //
+    //remember the application
+    //
+    _pApplication = pApplication;
+
+    if (FAILED(hr = _strFileName.Copy(pszFileNameToMonitor)))
+    {
+        goto Finished;
+    }
+
+    if (FAILED(hr = _strDirectoryName.Copy(pszDirectoryToMonitor)))
+    {
+        goto Finished;
+    }
+
+    //
+    // Resize change buffer to something "reasonable"
+    //
+    if (!_buffDirectoryChanges.Resize(FILE_WATCHER_ENTRY_BUFFER_SIZE))
+    {
+        hr = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
+        goto Finished;
+    }
+
+    if (hImpersonationToken != NULL)
+    {
+        fRet = DuplicateHandle(GetCurrentProcess(),
+            hImpersonationToken,
+            GetCurrentProcess(),
+            &_hImpersonationToken,
+            0,
+            FALSE,
+            DUPLICATE_SAME_ACCESS);
+
+        if (!fRet)
+        {
+            hr = HRESULT_FROM_WIN32(GetLastError());
+            goto Finished;
+        }
+    }
+    else
+    {
+        if (_hImpersonationToken != NULL)
+        {
+            CloseHandle(_hImpersonationToken);
+            _hImpersonationToken = NULL;
+        }
+    }
+
+    _hDirectory = CreateFileW(
+        _strDirectoryName.QueryStr(),
+        FILE_LIST_DIRECTORY,
+        FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+        NULL,
+        OPEN_EXISTING,
+        FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED,
+        NULL);
+
+    if (_hDirectory == INVALID_HANDLE_VALUE)
+    {
+        hr = HRESULT_FROM_WIN32(GetLastError());
+        goto Finished;
+    }
+
+    if (CreateIoCompletionPort(
+        _hDirectory,
+        _pFileMonitor->QueryCompletionPort(),
+        NULL,
+        0) == NULL)
+    {
+        hr = HRESULT_FROM_WIN32(GetLastError());
+        goto Finished;
+    }
+
+    //
+    // Start monitoring
+    //
+    hr = Monitor();
+
+Finished:
+
+    return hr;
+}
\ No newline at end of file
diff --git a/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/src/forwarderconnection.cxx b/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/src/forwarderconnection.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..ed1e29aadd5933db733bee7acb8b9e2ac1ba92d5
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/src/forwarderconnection.cxx
@@ -0,0 +1,52 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#include "precomp.hxx"
+
+FORWARDER_CONNECTION::FORWARDER_CONNECTION(
+    VOID
+) : m_cRefs (1),
+    m_hConnection (NULL)
+{    
+}
+
+HRESULT
+FORWARDER_CONNECTION::Initialize(
+    DWORD   dwPort
+)
+{
+    HRESULT hr = S_OK;
+
+    hr = m_ConnectionKey.Initialize( dwPort );
+    if ( FAILED( hr ) )
+    {
+        goto Finished;
+    }
+
+    m_hConnection = WinHttpConnect(FORWARDING_HANDLER::sm_hSession,
+                                   L"127.0.0.1",
+                                   (USHORT) dwPort,
+                                   0);
+    if (m_hConnection == NULL)
+    {
+        hr = HRESULT_FROM_WIN32(GetLastError());
+        goto Finished;
+    }
+
+    //
+    // Since WinHttp will not emit WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING
+    // when closing WebSocket handle on Win8. Register callback at Connect level as a workaround
+    //
+    if (WinHttpSetStatusCallback(m_hConnection,
+                                 FORWARDING_HANDLER::OnWinHttpCompletion,
+                                 WINHTTP_CALLBACK_FLAG_HANDLES,
+                                 NULL) == WINHTTP_INVALID_STATUS_CALLBACK)
+    {
+        hr = HRESULT_FROM_WIN32(GetLastError());
+        goto Finished;
+    }
+
+Finished:
+
+    return hr;
+}
\ No newline at end of file
diff --git a/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/src/forwardinghandler.cxx b/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/src/forwardinghandler.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..f02a318f410a939ea2db49966f3a925ab1420ee0
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/src/forwardinghandler.cxx
@@ -0,0 +1,3073 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#include "precomp.hxx"
+#include <dbgutil.h>
+
+// Just to be aware of the FORWARDING_HANDLER object size.
+C_ASSERT(sizeof(FORWARDING_HANDLER) <= 632);
+
+#define DEF_MAX_FORWARDS        32
+#define HEX_TO_ASCII(c) ((CHAR)(((c) < 10) ? ((c) + '0') : ((c) + 'a' - 10)))
+
+#define BUFFER_SIZE         (8192UL)
+#define ENTITY_BUFFER_SIZE  (6 + BUFFER_SIZE + 2)
+#define STR_ANCM_CHILDREQUEST       "ANCM_WasCreateProcessFailure"
+
+HINTERNET                   FORWARDING_HANDLER::sm_hSession = NULL;
+STRU                        FORWARDING_HANDLER::sm_strErrorFormat;
+HANDLE                      FORWARDING_HANDLER::sm_hEventLog = NULL;
+ALLOC_CACHE_HANDLER *       FORWARDING_HANDLER::sm_pAlloc = NULL;
+TRACE_LOG *                 FORWARDING_HANDLER::sm_pTraceLog = NULL;
+PROTOCOL_CONFIG             FORWARDING_HANDLER::sm_ProtocolConfig;
+
+FORWARDING_HANDLER::FORWARDING_HANDLER(
+    __in IHttpContext * pW3Context
+) : m_Signature(FORWARDING_HANDLER_SIGNATURE),
+m_cRefs(1),
+m_dwHandlers(1),
+m_pW3Context(pW3Context),
+m_hRequest(NULL),
+m_fResponseHeadersReceivedAndSet(FALSE),
+m_fDoReverseRewriteHeaders(FALSE),
+m_msStartTime(0),
+m_BytesToReceive(0),
+m_BytesToSend(0),
+m_pEntityBuffer(NULL),
+m_cchLastSend(0),
+m_cEntityBuffers(0),
+m_cBytesBuffered(0),
+m_cMinBufferLimit(0),
+m_pszOriginalHostHeader(NULL),
+m_RequestStatus(FORWARDER_START),
+m_pDisconnect(NULL),
+m_pszHeaders(NULL),
+m_cchHeaders(0),
+m_fWebSocketEnabled(FALSE),
+m_cContentLength(0),
+m_pWebSocket(NULL),
+m_pApplication(NULL),
+m_pAppOfflineHtm(NULL),
+m_fFinishRequest(FALSE),
+m_fClientDisconnected(FALSE),
+m_fHasError(FALSE),
+m_fServerResetConn(FALSE),
+m_fDoneAsyncCompletion(FALSE),
+m_fHttpHandleInClose(FALSE),
+m_fWebSocketHandleInClose(FALSE)
+{
+    DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO,
+        "FORWARDING_HANDLER --%p\n", this);
+
+    InitializeSRWLock(&m_RequestLock);
+}
+
+FORWARDING_HANDLER::~FORWARDING_HANDLER(
+    VOID
+)
+{
+    //
+    // Destructor has started.
+    //
+    DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO,
+        "~FORWARDING_HANDLER --%p\n", this);
+
+    m_Signature = FORWARDING_HANDLER_SIGNATURE_FREE;
+
+    //
+    // Disconnect notification cleanup would happen first, before
+    // the FORWARDING_HANDLER instance got removed from m_pSharedhandler list.
+    // The m_pServer cleanup would happen afterwards, since there may be a 
+    // call pending from SHARED_HANDLER to  FORWARDING_HANDLER::SetStatusAndHeaders()
+    // 
+    DBG_ASSERT(m_pDisconnect == NULL);
+
+    FreeResponseBuffers();
+
+    if (m_hRequest != NULL)
+    {
+        // m_hRequest should have already been closed and set to NULL
+        // if not, we cannot close it as it may callback and cause AV
+        // let's do our best job here
+        WinHttpSetStatusCallback(m_hRequest,
+                                 NULL, // Callback Function
+                                 WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS,
+                                 NULL);
+        WinHttpCloseHandle(m_hRequest);
+        m_hRequest = NULL;
+    }
+
+    if(m_pApplication != NULL)
+    {
+        m_pApplication->DereferenceApplication();
+        m_pApplication = NULL;
+    }
+
+    if(m_pAppOfflineHtm != NULL)
+    {
+        m_pAppOfflineHtm->DereferenceAppOfflineHtm();
+        m_pAppOfflineHtm = NULL;
+    }
+
+    m_pW3Context = NULL;
+}
+
+// static
+void * FORWARDING_HANDLER::operator new(size_t)
+{
+    DBG_ASSERT(sm_pAlloc != NULL);
+    if (sm_pAlloc == NULL)
+    {
+        return NULL;
+    }
+    return sm_pAlloc->Alloc();
+}
+
+// static
+void FORWARDING_HANDLER::operator delete(void * pMemory)
+{
+    DBG_ASSERT(sm_pAlloc != NULL);
+    if (sm_pAlloc != NULL)
+    {
+        sm_pAlloc->Free(pMemory);
+    }
+}
+
+VOID
+FORWARDING_HANDLER::ReferenceForwardingHandler(
+    VOID
+) const
+{
+    LONG cRefs = InterlockedIncrement(&m_cRefs);
+    if (sm_pTraceLog != NULL)
+    {
+        WriteRefTraceLog(sm_pTraceLog,
+            cRefs,
+            this);
+    }
+}
+
+VOID
+FORWARDING_HANDLER::DereferenceForwardingHandler(
+    VOID
+) const
+{
+    DBG_ASSERT(m_cRefs != 0);
+
+    LONG cRefs = InterlockedDecrement(&m_cRefs);
+    if (cRefs == 0)
+    {
+        delete this;
+    }
+
+    if (sm_pTraceLog != NULL)
+    {
+        WriteRefTraceLog(sm_pTraceLog,
+            cRefs,
+            this);
+    }
+}
+
+HRESULT
+FORWARDING_HANDLER::SetStatusAndHeaders(
+    PCSTR           pszHeaders,
+    DWORD
+)
+{
+    HRESULT         hr;
+    IHttpResponse * pResponse = m_pW3Context->GetResponse();
+    IHttpRequest *  pRequest = m_pW3Context->GetRequest();
+    STACK_STRA(strHeaderName, 128);
+    STACK_STRA(strHeaderValue, 2048);
+    DWORD           index = 0;
+    PSTR            pchNewline;
+    PCSTR           pchEndofHeaderValue;
+    BOOL            fServerHeaderPresent = FALSE;
+
+    _ASSERT(pszHeaders != NULL);
+
+    //
+    // The first line is the status line
+    //
+    PSTR pchStatus = const_cast<PSTR>(strchr(pszHeaders, ' '));
+    if (pchStatus == NULL)
+    {
+        return HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
+    }
+    while (*pchStatus == ' ')
+    {
+        pchStatus++;
+    }
+    USHORT uStatus = static_cast<USHORT>(atoi(pchStatus));
+
+    if (m_fWebSocketEnabled && uStatus != 101)
+    {
+        //
+        // Expected 101 response.
+        //
+
+        m_fWebSocketEnabled = FALSE;
+    }
+
+    pchStatus = strchr(pchStatus, ' ');
+    if (pchStatus == NULL)
+    {
+        return HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
+    }
+    while (*pchStatus == ' ')
+    {
+        pchStatus++;
+    }
+    if (*pchStatus == '\r' || *pchStatus == '\n')
+    {
+        pchStatus--;
+    }
+
+    pchNewline = strchr(pchStatus, '\n');
+    if (pchNewline == NULL)
+    {
+        return HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
+    }
+
+    if (uStatus != 200)
+    {
+        //
+        // Skip over any spaces before the '\n'
+        //
+        for (pchEndofHeaderValue = pchNewline - 1;
+            (pchEndofHeaderValue > pchStatus) &&
+            ((*pchEndofHeaderValue == ' ') ||
+            (*pchEndofHeaderValue == '\r'));
+            pchEndofHeaderValue--)
+        {}
+
+        //
+        // Copy the status description
+        //
+        if (FAILED(hr = strHeaderValue.Copy(
+            pchStatus,
+            (DWORD)(pchEndofHeaderValue - pchStatus) + 1)) ||
+            FAILED(hr = pResponse->SetStatus(uStatus,
+                strHeaderValue.QueryStr(),
+                0,
+                S_OK,
+                NULL,
+                TRUE)))
+        {
+            return hr;
+        }
+    }
+
+    for (index = static_cast<DWORD>(pchNewline - pszHeaders) + 1;
+        pszHeaders[index] != '\r' && pszHeaders[index] != '\n' && pszHeaders[index] != '\0';
+        index = static_cast<DWORD>(pchNewline - pszHeaders) + 1)
+    {
+        //
+        // Find the ':' in Header : Value\r\n
+        //
+        PCSTR pchColon = strchr(pszHeaders + index, ':');
+
+        //
+        // Find the '\n' in Header : Value\r\n
+        //
+        pchNewline = const_cast<PSTR>(strchr(pszHeaders + index, '\n'));
+
+        if (pchNewline == NULL)
+        {
+            return HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
+        }
+
+        //
+        // Take care of header continuation
+        //
+        while (pchNewline[1] == ' ' ||
+            pchNewline[1] == '\t')
+        {
+            pchNewline = strchr(pchNewline + 1, '\n');
+        }
+
+        DBG_ASSERT(
+            (pchColon != NULL) && (pchColon < pchNewline));
+        if ((pchColon == NULL) || (pchColon >= pchNewline))
+        {
+            return HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
+        }
+
+        //
+        // Skip over any spaces before the ':'
+        //
+        PCSTR pchEndofHeaderName;
+        for (pchEndofHeaderName = pchColon - 1;
+            (pchEndofHeaderName >= pszHeaders + index) &&
+            (*pchEndofHeaderName == ' ');
+            pchEndofHeaderName--)
+        {}
+
+        pchEndofHeaderName++;
+
+        //
+        // Copy the header name
+        //
+        if (FAILED(hr = strHeaderName.Copy(
+            pszHeaders + index,
+            (DWORD)(pchEndofHeaderName - pszHeaders) - index)))
+        {
+            return hr;
+        }
+
+        //
+        // Skip over the ':' and any trailing spaces
+        //
+        for (index = static_cast<DWORD>(pchColon - pszHeaders) + 1;
+            pszHeaders[index] == ' ';
+            index++)
+        {}
+
+
+        //
+        // Skip over any spaces before the '\n'
+        //
+        for (pchEndofHeaderValue = pchNewline - 1;
+            (pchEndofHeaderValue >= pszHeaders + index) &&
+            ((*pchEndofHeaderValue == ' ') ||
+            (*pchEndofHeaderValue == '\r'));
+            pchEndofHeaderValue--)
+        {}
+
+        pchEndofHeaderValue++;
+
+        //
+        // Copy the header value
+        //
+        if (pchEndofHeaderValue == pszHeaders + index)
+        {
+            strHeaderValue.Reset();
+        }
+        else if (FAILED(hr = strHeaderValue.Copy(
+            pszHeaders + index,
+            (DWORD)(pchEndofHeaderValue - pszHeaders) - index)))
+        {
+            return hr;
+        }
+
+        //
+        // Do not pass the transfer-encoding:chunked, Connection, Date or
+        // Server headers along
+        //
+        DWORD headerIndex = g_pResponseHeaderHash->GetIndex(strHeaderName.QueryStr());
+        if (headerIndex == UNKNOWN_INDEX)
+        {
+            hr = pResponse->SetHeader(strHeaderName.QueryStr(),
+                strHeaderValue.QueryStr(),
+                static_cast<USHORT>(strHeaderValue.QueryCCH()),
+                FALSE); // fReplace
+        }
+        else
+        {
+            switch (headerIndex)
+            {
+            case HttpHeaderTransferEncoding:
+                if (!strHeaderValue.Equals("chunked", TRUE))
+                {
+                    break;
+                }
+                __fallthrough;
+            case HttpHeaderConnection:
+            case HttpHeaderDate:
+                continue;
+
+            case HttpHeaderServer:
+                fServerHeaderPresent = TRUE;
+                break;
+
+            case HttpHeaderContentLength:
+                if (pRequest->GetRawHttpRequest()->Verb != HttpVerbHEAD)
+                {
+                    m_cContentLength = _atoi64(strHeaderValue.QueryStr());
+                }
+                break;
+            }
+
+            hr = pResponse->SetHeader(static_cast<HTTP_HEADER_ID>(headerIndex),
+                strHeaderValue.QueryStr(),
+                static_cast<USHORT>(strHeaderValue.QueryCCH()),
+                TRUE); // fReplace
+        }
+        if (FAILED(hr))
+        {
+            return hr;
+        }
+    }
+
+    //
+    // Explicitly remove the Server header if the back-end didn't set one.
+    //
+
+    if (!fServerHeaderPresent)
+    {
+        pResponse->DeleteHeader("Server");
+    }
+
+    if (m_fDoReverseRewriteHeaders)
+    {
+        hr = DoReverseRewrite(pResponse);
+        if (FAILED(hr))
+        {
+            return hr;
+        }
+    }
+
+    m_fResponseHeadersReceivedAndSet = TRUE;
+
+    return S_OK;
+}
+
+HRESULT
+FORWARDING_HANDLER::DoReverseRewrite(
+    __in IHttpResponse *pResponse
+)
+{
+    DBG_ASSERT(pResponse == m_pW3Context->GetResponse());
+    BOOL fSecure = (m_pW3Context->GetRequest()->GetRawHttpRequest()->pSslInfo != NULL);
+    STRA strTemp;
+    PCSTR pszHeader;
+    PCSTR pszStartHost;
+    PCSTR pszEndHost;
+    HTTP_RESPONSE_HEADERS *pHeaders;
+    HRESULT hr;
+
+    //
+    // Content-Location and Location are easy, one known header in
+    // http[s]://host/url format
+    //
+    pszHeader = pResponse->GetHeader(HttpHeaderContentLocation);
+    if (pszHeader != NULL)
+    {
+        if (_strnicmp(pszHeader, "http://", 7) == 0)
+        {
+            pszStartHost = pszHeader + 7;
+        }
+        else if (_strnicmp(pszHeader, "https://", 8) == 0)
+        {
+            pszStartHost = pszHeader + 8;
+        }
+        else
+        {
+            goto Location;
+        }
+
+        pszEndHost = strchr(pszStartHost, '/');
+
+        if (FAILED(hr = strTemp.Copy(fSecure ? "https://" : "http://")) ||
+            FAILED(hr = strTemp.Append(m_pszOriginalHostHeader)))
+        {
+            return hr;
+        }
+        if (pszEndHost != NULL &&
+            FAILED(hr = strTemp.Append(pszEndHost)))
+        {
+            return hr;
+        }
+        if (FAILED(hr = pResponse->SetHeader(HttpHeaderContentLocation,
+            strTemp.QueryStr(),
+            static_cast<USHORT>(strTemp.QueryCCH()),
+            TRUE)))
+        {
+            return hr;
+        }
+    }
+
+Location:
+
+    pszHeader = pResponse->GetHeader(HttpHeaderLocation);
+    if (pszHeader != NULL)
+    {
+        if (_strnicmp(pszHeader, "http://", 7) == 0)
+        {
+            pszStartHost = pszHeader + 7;
+        }
+        else if (_strnicmp(pszHeader, "https://", 8) == 0)
+        {
+            pszStartHost = pszHeader + 8;
+        }
+        else
+        {
+            goto SetCookie;
+        }
+
+        pszEndHost = strchr(pszStartHost, '/');
+
+        if (FAILED(hr = strTemp.Copy(fSecure ? "https://" : "http://")) ||
+            FAILED(hr = strTemp.Append(m_pszOriginalHostHeader)))
+        {
+            return hr;
+        }
+        if (pszEndHost != NULL &&
+            FAILED(hr = strTemp.Append(pszEndHost)))
+        {
+            return hr;
+        }
+        if (FAILED(hr = pResponse->SetHeader(HttpHeaderLocation,
+            strTemp.QueryStr(),
+            static_cast<USHORT>(strTemp.QueryCCH()),
+            TRUE)))
+        {
+            return hr;
+        }
+    }
+
+SetCookie:
+
+    //
+    // Set-Cookie is different - possibly multiple unknown headers with
+    // syntax name=value ; ... ; Domain=.host ; ...
+    //
+    pHeaders = &pResponse->GetRawHttpResponse()->Headers;
+    for (DWORD i = 0; i<pHeaders->UnknownHeaderCount; i++)
+    {
+        if (_stricmp(pHeaders->pUnknownHeaders[i].pName, "Set-Cookie") != 0)
+        {
+            continue;
+        }
+
+        pszHeader = pHeaders->pUnknownHeaders[i].pRawValue;
+        pszStartHost = strchr(pszHeader, ';');
+        while (pszStartHost != NULL)
+        {
+            pszStartHost++;
+            while (IsSpace(*pszStartHost))
+            {
+                pszStartHost++;
+            }
+
+            if (_strnicmp(pszStartHost, "Domain", 6) != 0)
+            {
+                pszStartHost = strchr(pszStartHost, ';');
+                continue;
+            }
+            pszStartHost += 6;
+
+            while (IsSpace(*pszStartHost))
+            {
+                pszStartHost++;
+            }
+            if (*pszStartHost != '=')
+            {
+                break;
+            }
+            pszStartHost++;
+            while (IsSpace(*pszStartHost))
+            {
+                pszStartHost++;
+            }
+            if (*pszStartHost == '.')
+            {
+                pszStartHost++;
+            }
+            pszEndHost = pszStartHost;
+            while (!IsSpace(*pszEndHost) &&
+                *pszEndHost != ';' &&
+                *pszEndHost != '\0')
+            {
+                pszEndHost++;
+            }
+
+            if (FAILED(hr = strTemp.Copy(pszHeader, static_cast<DWORD>(pszStartHost - pszHeader))) ||
+                FAILED(hr = strTemp.Append(m_pszOriginalHostHeader)) ||
+                FAILED(hr = strTemp.Append(pszEndHost)))
+            {
+                return hr;
+            }
+
+            pszHeader = (PCSTR)m_pW3Context->AllocateRequestMemory(strTemp.QueryCCH() + 1);
+            if (pszHeader == NULL)
+            {
+                return E_OUTOFMEMORY;
+            }
+            StringCchCopyA(const_cast<PSTR>(pszHeader), strTemp.QueryCCH() + 1, strTemp.QueryStr());
+            pHeaders->pUnknownHeaders[i].pRawValue = pszHeader;
+            pHeaders->pUnknownHeaders[i].RawValueLength = static_cast<USHORT>(strTemp.QueryCCH());
+
+            break;
+        }
+    }
+
+    return S_OK;
+}
+
+HRESULT
+FORWARDING_HANDLER::GetHeaders(
+    const PROTOCOL_CONFIG * pProtocol,
+    PCWSTR *                ppszHeaders,
+    DWORD *                 pcchHeaders,
+    ASPNETCORE_CONFIG*      pAspNetCoreConfig,
+    SERVER_PROCESS*         pServerProcess
+)
+{
+
+    HRESULT hr = S_OK;
+    PCSTR pszCurrentHeader;
+    PCSTR ppHeadersToBeRemoved;
+    PCSTR pszFinalHeader;
+    USHORT cchCurrentHeader;
+    DWORD cchFinalHeader;
+    BOOL  fSecure = FALSE;  // dummy. Used in SplitUrl. Value will not be used 
+                            // as ANCM always use http protocol to communicate with backend  
+    STRU  struDestination;
+    STRU  struUrl;
+    STACK_STRA(strTemp, 64);
+    HTTP_REQUEST_HEADERS *pHeaders;
+    IHttpRequest *pRequest = m_pW3Context->GetRequest();
+    MULTISZA mszMsAspNetCoreHeaders;
+
+    //
+    // We historically set the host section in request url to the new host header
+    // this is wrong but Kestrel has dependency on it.
+    // should change it in the future
+    //
+    if (!pProtocol->QueryPreserveHostHeader())
+    {
+        if (FAILED(hr = PATH::SplitUrl(pRequest->GetRawHttpRequest()->CookedUrl.pFullUrl,
+            &fSecure,
+            &struDestination,
+            &struUrl)) ||
+            FAILED(hr = strTemp.CopyW(struDestination.QueryStr())) ||
+            FAILED(hr = pRequest->SetHeader(HttpHeaderHost,
+                strTemp.QueryStr(),
+                static_cast<USHORT>(strTemp.QueryCCH()),
+                TRUE))) // fReplace
+        {
+            return hr;
+        }
+    }
+    //
+    // Strip all headers starting with MS-ASPNETCORE.
+    // These headers are generated by the asp.net core module and 
+    // passed to the process it creates.
+    //
+
+    pHeaders = &m_pW3Context->GetRequest()->GetRawHttpRequest()->Headers;
+    for (DWORD i = 0; i<pHeaders->UnknownHeaderCount; i++)
+    {
+        if (_strnicmp(pHeaders->pUnknownHeaders[i].pName, "MS-ASPNETCORE", 13) == 0)
+        {
+            mszMsAspNetCoreHeaders.Append(pHeaders->pUnknownHeaders[i].pName, (DWORD)pHeaders->pUnknownHeaders[i].NameLength);
+        }
+    }
+
+    ppHeadersToBeRemoved = mszMsAspNetCoreHeaders.First();
+
+    //
+    // iterate the list of headers to be removed and delete them from the request.
+    //
+
+    while (ppHeadersToBeRemoved != NULL)
+    {
+        m_pW3Context->GetRequest()->DeleteHeader(ppHeadersToBeRemoved);
+        ppHeadersToBeRemoved = mszMsAspNetCoreHeaders.Next(ppHeadersToBeRemoved);
+    }
+
+    if (pServerProcess->QueryGuid() != NULL)
+    {
+        hr = m_pW3Context->GetRequest()->SetHeader("MS-ASPNETCORE-TOKEN",
+            pServerProcess->QueryGuid(),
+            (USHORT)strlen(pServerProcess->QueryGuid()),
+            TRUE);
+        if (FAILED(hr))
+        {
+            return hr;
+        }
+    }
+
+    if (pAspNetCoreConfig->QueryForwardWindowsAuthToken() &&
+        (_wcsicmp(m_pW3Context->GetUser()->GetAuthenticationType(), L"negotiate") == 0 ||
+            _wcsicmp(m_pW3Context->GetUser()->GetAuthenticationType(), L"ntlm") == 0))
+    {
+        if (m_pW3Context->GetUser()->GetPrimaryToken() != NULL &&
+            m_pW3Context->GetUser()->GetPrimaryToken() != INVALID_HANDLE_VALUE)
+        {
+            HANDLE hTargetTokenHandle = NULL;
+            hr = pServerProcess->SetWindowsAuthToken(m_pW3Context->GetUser()->GetPrimaryToken(),
+                &hTargetTokenHandle);
+            if (FAILED(hr))
+            {
+                return hr;
+            }
+
+            //
+            // set request header with target token value
+            //
+            CHAR pszHandleStr[16] = { 0 };
+            if (_ui64toa_s((UINT64)hTargetTokenHandle, pszHandleStr, 16, 16) != 0)
+            {
+                hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
+                return hr;
+            }
+
+            hr = m_pW3Context->GetRequest()->SetHeader("MS-ASPNETCORE-WINAUTHTOKEN",
+                pszHandleStr,
+                (USHORT)strlen(pszHandleStr),
+                TRUE);
+            if (FAILED(hr))
+            {
+                return hr;
+            }
+        }
+    }
+
+    if (!pProtocol->QueryXForwardedForName()->IsEmpty())
+    {
+        strTemp.Reset();
+
+        pszCurrentHeader = pRequest->GetHeader(pProtocol->QueryXForwardedForName()->QueryStr(), &cchCurrentHeader);
+        if (pszCurrentHeader != NULL)
+        {
+            if (FAILED(hr = strTemp.Copy(pszCurrentHeader, cchCurrentHeader)) ||
+                FAILED(hr = strTemp.Append(", ", 2)))
+            {
+                return hr;
+            }
+        }
+
+        if (FAILED(hr = m_pW3Context->GetServerVariable("REMOTE_ADDR",
+            &pszFinalHeader,
+            &cchFinalHeader)))
+        {
+            return hr;
+        }
+
+        if (pRequest->GetRawHttpRequest()->Address.pRemoteAddress->sa_family == AF_INET6)
+        {
+            if (FAILED(hr = strTemp.Append("[", 1)) ||
+                FAILED(hr = strTemp.Append(pszFinalHeader, cchFinalHeader)) ||
+                FAILED(hr = strTemp.Append("]", 1)))
+            {
+                return hr;
+            }
+        }
+        else
+        {
+            if (FAILED(hr = strTemp.Append(pszFinalHeader, cchFinalHeader)))
+            {
+                return hr;
+            }
+        }
+
+        if (pProtocol->QueryIncludePortInXForwardedFor())
+        {
+            if (FAILED(hr = m_pW3Context->GetServerVariable("REMOTE_PORT",
+                &pszFinalHeader,
+                &cchFinalHeader)))
+            {
+                return hr;
+            }
+
+            if (FAILED(hr = strTemp.Append(":", 1)) ||
+                FAILED(hr = strTemp.Append(pszFinalHeader, cchFinalHeader)))
+            {
+                return hr;
+            }
+        }
+
+        if (FAILED(hr = pRequest->SetHeader(pProtocol->QueryXForwardedForName()->QueryStr(),
+            strTemp.QueryStr(),
+            static_cast<USHORT>(strTemp.QueryCCH()),
+            TRUE))) // fReplace
+        {
+            return hr;
+        }
+    }
+
+    if (!pProtocol->QuerySslHeaderName()->IsEmpty())
+    {
+        const HTTP_SSL_INFO *pSslInfo = pRequest->GetRawHttpRequest()->pSslInfo;
+        LPSTR pszScheme = "http";
+        if (pSslInfo != NULL)
+        {
+            pszScheme = "https";
+        }
+
+        strTemp.Reset();
+
+        pszCurrentHeader = pRequest->GetHeader(pProtocol->QuerySslHeaderName()->QueryStr(), &cchCurrentHeader);
+        if (pszCurrentHeader != NULL)
+        {
+            if (FAILED(hr = strTemp.Copy(pszCurrentHeader, cchCurrentHeader)) ||
+                FAILED(hr = strTemp.Append(", ", 2)))
+            {
+                return hr;
+            }
+        }
+
+        if (FAILED(hr = strTemp.Append(pszScheme)))
+        {
+            return hr;
+        }
+
+        if (FAILED(pRequest->SetHeader(pProtocol->QuerySslHeaderName()->QueryStr(),
+            strTemp.QueryStr(),
+            (USHORT)strTemp.QueryCCH(),
+            TRUE)))
+        {
+            return hr;
+        }
+    }
+
+    if (!pProtocol->QueryClientCertName()->IsEmpty())
+    {
+        if (pRequest->GetRawHttpRequest()->pSslInfo == NULL ||
+            pRequest->GetRawHttpRequest()->pSslInfo->pClientCertInfo == NULL)
+        {
+            pRequest->DeleteHeader(pProtocol->QueryClientCertName()->QueryStr());
+        }
+        else
+        {
+            // Resize the buffer large enough to hold the encoded certificate info
+            if (FAILED(hr = strTemp.Resize(
+                1 + (pRequest->GetRawHttpRequest()->pSslInfo->pClientCertInfo->CertEncodedSize + 2) / 3 * 4)))
+            {
+                return hr;
+            }
+
+            Base64Encode(
+                pRequest->GetRawHttpRequest()->pSslInfo->pClientCertInfo->pCertEncoded,
+                pRequest->GetRawHttpRequest()->pSslInfo->pClientCertInfo->CertEncodedSize,
+                strTemp.QueryStr(),
+                strTemp.QuerySize(),
+                NULL);
+            strTemp.SyncWithBuffer();
+
+            if (FAILED(hr = pRequest->SetHeader(
+                pProtocol->QueryClientCertName()->QueryStr(),
+                strTemp.QueryStr(),
+                static_cast<USHORT>(strTemp.QueryCCH()),
+                TRUE))) // fReplace
+            {
+                return hr;
+            }
+        }
+    }
+
+    //
+    // Remove the connection header
+    //
+    if (!m_fWebSocketEnabled)
+    {
+        pRequest->DeleteHeader(HttpHeaderConnection);
+    }
+
+    //
+    // Get all the headers to send to the client
+    //
+    hr = m_pW3Context->GetServerVariable("ALL_RAW",
+        ppszHeaders,
+        pcchHeaders);
+    if (FAILED(hr))
+    {
+        return hr;
+    }
+
+    return S_OK;
+}
+
+HRESULT
+FORWARDING_HANDLER::CreateWinHttpRequest(
+    __in const IHttpRequest *       pRequest,
+    __in const PROTOCOL_CONFIG *    pProtocol,
+    __in HINTERNET                  hConnect,
+    __inout STRU *                  pstrUrl,
+    ASPNETCORE_CONFIG*              pAspNetCoreConfig,
+    SERVER_PROCESS*                 pServerProcess
+)
+{
+    HRESULT         hr = S_OK;
+    PCWSTR          pszVersion = NULL;
+    PCSTR           pszVerb;
+    STACK_STRU(strVerb, 32);
+
+    //
+    // Create the request handle for this request (leave some fields blank,
+    // we will fill them when sending the request)
+    //
+    pszVerb = pRequest->GetHttpMethod();
+    if (FAILED(hr = strVerb.CopyA(pszVerb)))
+    {
+        goto Finished;
+    }
+
+    //pszVersion = pProtocol->QueryVersion();
+    if (pszVersion == NULL)
+    {
+        DWORD cchUnused;
+        hr = m_pW3Context->GetServerVariable(
+            "HTTP_VERSION",
+            &pszVersion,
+            &cchUnused);
+        if (FAILED(hr))
+        {
+            goto Finished;
+        }
+    }
+
+    m_hRequest = WinHttpOpenRequest(hConnect,
+        strVerb.QueryStr(),
+        pstrUrl->QueryStr(),
+        pszVersion,
+        WINHTTP_NO_REFERER,
+        WINHTTP_DEFAULT_ACCEPT_TYPES,
+        WINHTTP_FLAG_ESCAPE_DISABLE_QUERY
+        | g_OptionalWinHttpFlags);
+    if (m_hRequest == NULL)
+    {
+        hr = HRESULT_FROM_WIN32(GetLastError());
+        goto Finished;
+    }
+
+    if (!WinHttpSetTimeouts(m_hRequest,
+        pProtocol->QueryTimeout(),
+        pProtocol->QueryTimeout(),
+        pProtocol->QueryTimeout(),
+        pProtocol->QueryTimeout()))
+    {
+        hr = HRESULT_FROM_WIN32(GetLastError());
+        goto Finished;
+    }
+
+    DWORD dwResponseBufferLimit = pProtocol->QueryResponseBufferLimit();
+    if (!WinHttpSetOption(m_hRequest,
+        WINHTTP_OPTION_MAX_RESPONSE_DRAIN_SIZE,
+        &dwResponseBufferLimit,
+        sizeof(dwResponseBufferLimit)))
+    {
+        hr = HRESULT_FROM_WIN32(GetLastError());
+        goto Finished;
+    }
+
+    DWORD dwMaxHeaderSize = pProtocol->QueryMaxResponseHeaderSize();
+    if (!WinHttpSetOption(m_hRequest,
+        WINHTTP_OPTION_MAX_RESPONSE_HEADER_SIZE,
+        &dwMaxHeaderSize,
+        sizeof(dwMaxHeaderSize)))
+    {
+        hr = HRESULT_FROM_WIN32(GetLastError());
+        goto Finished;
+    }
+
+    DWORD dwOption = WINHTTP_DISABLE_COOKIES;
+
+    dwOption |= WINHTTP_DISABLE_AUTHENTICATION;
+
+    if (!pProtocol->QueryDoKeepAlive())
+    {
+        dwOption |= WINHTTP_DISABLE_KEEP_ALIVE;
+    }
+    if (!WinHttpSetOption(m_hRequest,
+        WINHTTP_OPTION_DISABLE_FEATURE,
+        &dwOption,
+        sizeof(dwOption)))
+    {
+        hr = HRESULT_FROM_WIN32(GetLastError());
+        goto Finished;
+    }
+
+    if (WinHttpSetStatusCallback(m_hRequest,
+        FORWARDING_HANDLER::OnWinHttpCompletion,
+        (WINHTTP_CALLBACK_FLAG_ALL_COMPLETIONS |
+            WINHTTP_CALLBACK_FLAG_HANDLES |
+            WINHTTP_CALLBACK_STATUS_SENDING_REQUEST),
+        NULL) == WINHTTP_INVALID_STATUS_CALLBACK)
+    {
+        hr = HRESULT_FROM_WIN32(GetLastError());
+        goto Finished;
+    }
+
+    hr = GetHeaders(pProtocol,
+        &m_pszHeaders,
+        &m_cchHeaders,
+        pAspNetCoreConfig,
+        pServerProcess);
+    if (FAILED(hr))
+    {
+        goto Finished;
+    }
+
+Finished:
+
+    return hr;
+}
+
+REQUEST_NOTIFICATION_STATUS
+FORWARDING_HANDLER::OnExecuteRequestHandler(
+    VOID
+)
+{
+    REQUEST_NOTIFICATION_STATUS retVal = RQ_NOTIFICATION_CONTINUE;
+    HRESULT                     hr = S_OK;
+    ASPNETCORE_CONFIG          *pAspNetCoreConfig = NULL;
+    FORWARDER_CONNECTION       *pConnection = NULL;
+    STACK_STRU(strDestination, 32);
+    STACK_STRU(strUrl, 2048);
+    STACK_STRU(struEscapedUrl, 2048);
+    STACK_STRU(strDescription, 128);
+    HINTERNET                   hConnect = NULL;
+    IHttpRequest               *pRequest = m_pW3Context->GetRequest();
+    IHttpResponse              *pResponse = m_pW3Context->GetResponse();
+    PROTOCOL_CONFIG            *pProtocol = &sm_ProtocolConfig;
+    APPLICATION_MANAGER        *pApplicationManager = NULL;
+    SERVER_PROCESS             *pServerProcess = NULL;
+    USHORT                      cchHostName = 0;
+    BOOL                        fSecure = FALSE;
+    BOOL                        fProcessStartFailure = FALSE;
+    HTTP_DATA_CHUNK            *pDataChunk = NULL;
+    IHttpConnection            *pClientConnection = NULL;
+
+    DBG_ASSERT(m_RequestStatus == FORWARDER_START);
+
+    //
+    // Take a reference so that object does not go away as a result of
+    // async completion.
+    //
+    ReferenceForwardingHandler();
+
+    m_pszOriginalHostHeader = pRequest->GetHeader(HttpHeaderHost, &cchHostName);
+
+    // read per site aspNetCore configuration.
+    hr = ASPNETCORE_CONFIG::GetConfig(m_pW3Context, &pAspNetCoreConfig);
+    if (FAILED(hr))
+    {
+        // configuration error.
+        goto Failure;
+    }
+
+    // override Protocol related config from aspNetCore config
+    pProtocol->OverrideConfig(pAspNetCoreConfig);
+
+    //
+    // parse original url
+    //
+    if (FAILED(hr = PATH::SplitUrl(pRequest->GetRawHttpRequest()->CookedUrl.pFullUrl,
+        &fSecure,
+        &strDestination,
+        &strUrl)))
+    {
+        goto Failure;
+    }
+
+    if (FAILED(hr = PATH::EscapeAbsPath(pRequest, &struEscapedUrl)))
+    {
+        goto Failure;
+    }
+
+    m_fDoReverseRewriteHeaders = pProtocol->QueryReverseRewriteHeaders();
+
+    m_cMinBufferLimit = pProtocol->QueryMinResponseBuffer();
+
+    pClientConnection = m_pW3Context->GetConnection();
+    if (pClientConnection == NULL ||
+        !pClientConnection->IsConnected())
+    {
+        hr = HRESULT_FROM_WIN32(WSAECONNRESET);
+        goto Failure;
+    }
+
+    //
+    // Find the application that is supposed to service this request.
+    //
+    pApplicationManager = APPLICATION_MANAGER::GetInstance();
+    if (pApplicationManager == NULL)
+    {
+        hr = E_OUTOFMEMORY;
+        goto Failure;
+    }
+
+    hr = pApplicationManager->GetApplication(m_pW3Context,
+        &m_pApplication);
+    if (FAILED(hr))
+    {
+        goto Failure;
+    }
+
+    m_pAppOfflineHtm = m_pApplication->QueryAppOfflineHtm();
+    if (m_pAppOfflineHtm != NULL)
+    {
+        m_pAppOfflineHtm->ReferenceAppOfflineHtm();
+    }
+
+    if (m_pApplication->AppOfflineFound() && m_pAppOfflineHtm != NULL)
+    {
+        HTTP_DATA_CHUNK DataChunk;
+
+        DataChunk.DataChunkType = HttpDataChunkFromMemory;
+        DataChunk.FromMemory.pBuffer = (PVOID)m_pAppOfflineHtm->m_Contents.QueryStr();
+        DataChunk.FromMemory.BufferLength = m_pAppOfflineHtm->m_Contents.QueryCB();
+
+        pResponse->SetStatus(503, "Service Unavailable", 0, hr, NULL, TRUE);
+        pResponse->SetHeader("Content-Type",
+            "text/html",
+            (USHORT)strlen("text/html"),
+            FALSE
+        ); // no need to check return hresult
+
+        pResponse->WriteEntityChunkByReference(&DataChunk);
+        goto Finished;
+    }
+
+    hr = m_pApplication->GetProcess(m_pW3Context,
+        pAspNetCoreConfig,
+        &pServerProcess);
+    if (FAILED(hr))
+    {
+        fProcessStartFailure = TRUE;
+        goto Failure;
+    }
+
+    if (pServerProcess == NULL)
+    {
+        hr = HRESULT_FROM_WIN32(ERROR_CREATE_FAILED);
+        goto Failure;
+    }
+
+    if (pServerProcess->QueryWinHttpConnection() == NULL)
+    {
+        hr = HRESULT_FROM_WIN32(ERROR_INVALID_HANDLE);
+        goto Failure;
+    }
+
+    hConnect = pServerProcess->QueryWinHttpConnection()->QueryHandle();
+
+    //
+    // Mark request as websocket if upgrade header is present.
+    //
+
+    if (g_fWebSocketSupported)
+    {
+        USHORT cchHeader = 0;
+        PCSTR pszWebSocketHeader = pRequest->GetHeader("Upgrade", &cchHeader);
+
+        if (cchHeader == 9 && _stricmp(pszWebSocketHeader, "websocket") == 0)
+        {
+            m_fWebSocketEnabled = TRUE;
+        }
+    }
+
+    hr = CreateWinHttpRequest(pRequest,
+        pProtocol,
+        hConnect,
+        &struEscapedUrl,
+        pAspNetCoreConfig,
+        pServerProcess);
+
+    if (FAILED(hr))
+    {
+        goto Failure;
+    }
+
+    //
+    // Register for connection disconnect notification with http.sys.
+    //
+    if (g_fAsyncDisconnectAvailable)
+    {
+        m_pDisconnect = static_cast<ASYNC_DISCONNECT_CONTEXT *>(
+            pClientConnection->GetModuleContextContainer()->
+                GetConnectionModuleContext(g_pModuleId));
+        if (m_pDisconnect == NULL)
+        {
+            m_pDisconnect = new ASYNC_DISCONNECT_CONTEXT;
+            if (m_pDisconnect == NULL)
+            {
+                hr = E_OUTOFMEMORY;
+                goto Failure;
+            }
+
+            hr = pClientConnection->GetModuleContextContainer()->
+                    SetConnectionModuleContext(m_pDisconnect,
+                                               g_pModuleId);
+            DBG_ASSERT(hr != HRESULT_FROM_WIN32(ERROR_ALREADY_ASSIGNED));
+            if (FAILED(hr))
+            {
+                m_pDisconnect->CleanupStoredContext();
+                m_pDisconnect = NULL;
+                goto Failure;
+            }
+        }
+
+        //
+        // Issue: There is a window of opportunity to miss on the disconnect
+        // notification if it happens before the SetHandler() call is made.
+        // It is suboptimal for performance, but should functionally be OK.
+        //
+
+        m_pDisconnect->SetHandler(this);
+    }
+
+    if (m_hRequest == NULL)
+    {
+        hr = HRESULT_FROM_WIN32(WSAECONNRESET);
+        goto Failure;
+    }
+
+    //
+    // Begins normal request handling. Send request to server.
+    //
+
+    m_RequestStatus = FORWARDER_SENDING_REQUEST;
+
+    //
+    // Calculate the bytes to receive from the content length.
+    //
+
+    DWORD cbContentLength = 0;
+    PCSTR pszContentLength = pRequest->GetHeader(HttpHeaderContentLength);
+    if (pszContentLength != NULL)
+    {
+        cbContentLength = m_BytesToReceive = atol(pszContentLength);
+        if (m_BytesToReceive == INFINITE)
+        {
+            hr = HRESULT_FROM_WIN32(WSAECONNRESET);
+            goto Failure;
+        }
+    }
+    else if (pRequest->GetHeader(HttpHeaderTransferEncoding) != NULL)
+    {
+        m_BytesToReceive = INFINITE;
+    }
+
+    if (m_fWebSocketEnabled)
+    {
+        //
+        // Set the upgrade flag for a websocket request.
+        //
+
+        if (!WinHttpSetOption(m_hRequest,
+            WINHTTP_OPTION_UPGRADE_TO_WEB_SOCKET,
+            NULL,
+            0))
+        {
+            hr = HRESULT_FROM_WIN32(GetLastError());
+            goto Finished;
+        }
+    }
+
+    m_cchLastSend = m_cchHeaders;
+
+    if (!WinHttpSendRequest(m_hRequest,
+        m_pszHeaders,
+        m_cchHeaders,
+        NULL,
+        0,
+        cbContentLength,
+        reinterpret_cast<DWORD_PTR>(static_cast<PVOID>(this))))
+    {
+        hr = HRESULT_FROM_WIN32(GetLastError());
+        DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO,
+            "FORWARDING_HANDLER::OnExecuteRequestHandler, Send request failed");
+        goto Failure;
+    }
+
+    //
+    // Async WinHTTP operation is in progress. Release this thread meanwhile,
+    // OnWinHttpCompletion method should resume the work by posting an IIS completion.
+    //
+    retVal = RQ_NOTIFICATION_PENDING;
+    goto Finished;
+
+Failure:
+
+    //
+    // Reset status for consistency.
+    //
+    m_RequestStatus = FORWARDER_DONE;
+    m_fHasError = TRUE;
+    pResponse->DisableKernelCache();
+    pResponse->GetRawHttpResponse()->EntityChunkCount = 0;
+    //
+    // Finish the request on failure.
+    //
+    retVal = RQ_NOTIFICATION_FINISH_REQUEST;
+
+    if (hr == HRESULT_FROM_WIN32(WSAECONNRESET))
+    {
+        pResponse->SetStatus(400, "Bad Request", 0, hr);
+        goto Finished;
+    }
+    else if (fProcessStartFailure && !pAspNetCoreConfig->QueryDisableStartUpErrorPage())
+    {
+        pResponse->SetStatus(502, "Bad Gateway", 5, hr, NULL, TRUE);
+        pResponse->SetHeader("Content-Type",
+            "text/html",
+            (USHORT)strlen("text/html"),
+            FALSE
+        );
+
+        if (SUCCEEDED(pApplicationManager->Get502ErrorPage(&pDataChunk)))
+        {
+            pResponse->WriteEntityChunkByReference(pDataChunk);
+            goto Finished;
+        }
+    }
+
+    //
+    // default error behavior
+    //
+    pResponse->SetStatus(502, "Bad Gateway", 3, hr);
+
+    if (hr > HRESULT_FROM_WIN32(WINHTTP_ERROR_BASE) &&
+        hr <= HRESULT_FROM_WIN32(WINHTTP_ERROR_LAST))
+    {
+#pragma prefast (suppress : __WARNING_FUNCTION_NEEDS_REVIEW, "Function and parameters reviewed.")
+        FormatMessage(
+            FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_HMODULE,
+            g_hWinHttpModule,
+            HRESULT_CODE(hr),
+            0,
+            strDescription.QueryStr(),
+            strDescription.QuerySizeCCH(),
+            NULL);
+    }
+    else
+    {
+        LoadString(g_hModule,
+            IDS_SERVER_ERROR,
+            strDescription.QueryStr(),
+            strDescription.QuerySizeCCH());
+    }
+
+    strDescription.SyncWithBuffer();
+    if (strDescription.QueryCCH() != 0)
+    {
+        pResponse->SetErrorDescription(
+            strDescription.QueryStr(),
+            strDescription.QueryCCH(),
+            FALSE);
+    }
+
+Finished:
+
+    if (pConnection != NULL)
+    {
+        pConnection->DereferenceForwarderConnection();
+        pConnection = NULL;
+    }
+
+    if (pServerProcess != NULL)
+    {
+        pServerProcess->DereferenceServerProcess();
+        pServerProcess = NULL;
+    }
+
+    if (retVal != RQ_NOTIFICATION_PENDING)
+    {
+        RemoveRequest();
+    }
+
+    DereferenceForwardingHandler();
+    //
+    // Do not use this object after dereferencing it, it may be gone.
+    //
+
+    return retVal;
+}
+
+VOID
+FORWARDING_HANDLER::RemoveRequest()
+{
+    ASYNC_DISCONNECT_CONTEXT *          pDisconnect;
+    pDisconnect = (ASYNC_DISCONNECT_CONTEXT *) InterlockedExchangePointer((PVOID*)&m_pDisconnect, NULL);
+    if (pDisconnect != NULL)
+    {
+        pDisconnect->ResetHandler();
+        pDisconnect = NULL;
+    }
+}
+
+REQUEST_NOTIFICATION_STATUS
+FORWARDING_HANDLER::OnAsyncCompletion(
+    DWORD                   cbCompletion,
+    HRESULT                 hrCompletionStatus
+)
+/*++
+
+Routine Description:
+
+Handle the completion from IIS and continue the execution
+of this request based on the current state.
+
+Arguments:
+
+cbCompletion - Number of bytes associated with this completion
+dwCompletionStatus - the win32 status associated with this completion
+
+Return Value:
+
+REQUEST_NOTIFICATION_STATUS
+
+--*/
+{
+    HRESULT                     hr = S_OK;
+    REQUEST_NOTIFICATION_STATUS retVal = RQ_NOTIFICATION_PENDING;
+    BOOL                        fLocked = FALSE;
+    BOOL                        fClientError = FALSE;
+    BOOL                        fClosed = FALSE;
+    BOOL                        fWebsocketUpgraded = FALSE;
+
+#ifdef DEBUG
+    FORWARDING_REQUEST_STATUS   dwLocalStatus = m_RequestStatus;
+#endif // DEBUG
+
+    if (sm_pTraceLog != NULL)
+    {
+        WriteRefTraceLogEx(sm_pTraceLog,
+            m_cRefs,
+            this,
+            "FORWARDING_HANDLER::OnAsyncCompletion Enter",
+            reinterpret_cast<PVOID>(static_cast<DWORD_PTR>(cbCompletion)),
+            reinterpret_cast<PVOID>(static_cast<DWORD_PTR>(hrCompletionStatus)));
+    }
+
+    DBG_ASSERT(m_pW3Context != NULL);
+    __analysis_assume(m_pW3Context != NULL);
+
+    //
+    // Take a reference so that object does not go away as a result of
+    // async completion.
+    //
+    ReferenceForwardingHandler();
+    DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO,
+        "FORWARDING_HANDLER::OnAsyncCompletion");
+
+    //
+    // OnAsyncCompletion can be called on a Winhttp io completion thread.
+    // Hence we need to check the TLS before we acquire the shared lock.
+    //
+    if (TlsGetValue(g_dwTlsIndex) != this)
+    {
+        DBG_ASSERT(TlsGetValue(g_dwTlsIndex) == NULL);
+        AcquireSRWLockExclusive(&m_RequestLock);
+        TlsSetValue(g_dwTlsIndex, this);
+        DBG_ASSERT(TlsGetValue(g_dwTlsIndex) == this);
+
+        fLocked = TRUE;
+    }
+
+    if (m_fClientDisconnected && (m_RequestStatus != FORWARDER_DONE) )
+    {
+        hr = ERROR_CONNECTION_ABORTED;
+        goto Failure;
+    }
+
+    if (m_RequestStatus == FORWARDER_RECEIVED_WEBSOCKET_RESPONSE)
+    {
+        DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO,
+            "FORWARDING_HANDLER::OnAsyncCompletion, Send completed for 101 response");
+        //
+        // This should be the write completion of the 101 response.
+        //
+        m_pWebSocket = new WEBSOCKET_HANDLER();
+        if (m_pWebSocket == NULL)
+        {
+            hr = E_OUTOFMEMORY;
+            goto Failure;
+        }
+
+        hr = m_pWebSocket->ProcessRequest(this, m_pW3Context, m_hRequest, &fWebsocketUpgraded);
+        if (fWebsocketUpgraded)
+        {
+            // WinHttp WebSocket handle has been created, bump the counter so that remember to close it
+            // and prevent from premature postcomplation and unexpected callback from winhttp
+            InterlockedIncrement(&m_dwHandlers);
+        }
+
+        if (FAILED(hr))
+        {
+            // This failure could happen when client disconnect happens or backend server fails 
+            // after websocket upgrade
+            goto Failure;
+        }
+
+        //
+        // WebSocket upgrade is successful. Close the WinHttpRequest Handle
+        //
+        m_fHttpHandleInClose = TRUE;
+        fClosed = WinHttpCloseHandle(m_hRequest);
+        DBG_ASSERT(fClosed);
+        m_hRequest = NULL;
+
+        if (!fClosed)
+        {
+            hr = HRESULT_FROM_WIN32(GetLastError());
+            goto Failure;
+        }
+        retVal = RQ_NOTIFICATION_PENDING;
+        goto Finished;
+    }
+
+    //
+    // Begins normal completion handling. There is already a shared acquired
+    // for protecting the WinHTTP request handle from being closed.
+    //
+    switch (m_RequestStatus)
+    {
+    case FORWARDER_RECEIVING_RESPONSE:
+
+        //
+        // This is a completion of a write (send) to http.sys, abort in case of
+        // failure, if there is more data available from WinHTTP, read it
+        // or else ask if there is more.
+        //
+        if (FAILED(hrCompletionStatus))
+        {
+            hr = hrCompletionStatus;
+            fClientError = TRUE;
+            goto Failure;
+        }
+
+        hr = OnReceivingResponse();
+        if (FAILED(hr))
+        {
+            goto Failure;
+        }
+        break;
+
+    case FORWARDER_SENDING_REQUEST:
+
+        hr = OnSendingRequest(cbCompletion,
+            hrCompletionStatus,
+            &fClientError);
+        if (FAILED(hr))
+        {
+            goto Failure;
+        }
+        break;
+
+    default:
+        DBG_ASSERT(m_RequestStatus == FORWARDER_DONE);
+        if (m_hRequest == NULL && m_pWebSocket == NULL)
+        {
+            // Request must have been done
+            if (!m_fFinishRequest)
+            {
+                goto Failure;
+            }
+
+            if (m_fHasError)
+            {
+                retVal = RQ_NOTIFICATION_FINISH_REQUEST;
+            }
+            else
+            {
+                retVal = RQ_NOTIFICATION_CONTINUE;
+            }
+        }
+        goto Finished;
+    }
+
+    //
+    // Either OnReceivingResponse or OnSendingRequest initiated an
+    // async WinHTTP operation, release this thread meanwhile,
+    // OnWinHttpCompletion method should resume the work by posting an IIS completion.
+    //
+    retVal = RQ_NOTIFICATION_PENDING;
+    goto Finished;
+
+Failure:
+
+    //
+    // Reset status for consistency.
+    //
+    m_RequestStatus = FORWARDER_DONE;
+    if (!m_fHasError)
+    {
+        m_fHasError = TRUE;
+
+        //
+        // Do the right thing based on where the error originated from.
+        //
+        IHttpResponse *pResponse = m_pW3Context->GetResponse();
+        pResponse->DisableKernelCache();
+        pResponse->GetRawHttpResponse()->EntityChunkCount = 0;
+
+        if (fClientError || m_fClientDisconnected)
+        {
+            if (!m_fResponseHeadersReceivedAndSet)
+            {
+                pResponse->SetStatus(400, "Bad Request", 0, HRESULT_FROM_WIN32(WSAECONNRESET));
+            }
+            else
+            {
+                //
+                // Response headers from origin server were
+                // already received and set for the current response.
+                // Honor the response status.
+                //
+            }
+        }
+        else
+        {
+            STACK_STRU(strDescription, 128);
+
+            pResponse->SetStatus(502, "Bad Gateway", 3, hr);
+
+            if (hr > HRESULT_FROM_WIN32(WINHTTP_ERROR_BASE) &&
+                hr <= HRESULT_FROM_WIN32(WINHTTP_ERROR_LAST))
+            {
+#pragma prefast (suppress : __WARNING_FUNCTION_NEEDS_REVIEW, "Function and parameters reviewed.")
+                FormatMessage(
+                    FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_HMODULE,
+                    g_hWinHttpModule,
+                    HRESULT_CODE(hr),
+                    0,
+                    strDescription.QueryStr(),
+                    strDescription.QuerySizeCCH(),
+                    NULL);
+            }
+            else
+            {
+                LoadString(g_hModule,
+                    IDS_SERVER_ERROR,
+                    strDescription.QueryStr(),
+                    strDescription.QuerySizeCCH());
+            }
+            (VOID)strDescription.SyncWithBuffer();
+
+#ifdef DEBUG
+            // adding more info to error descrption to help us diagnose the issue
+            STACK_STRA(strMoreData, 128);
+            sprintf_s(strMoreData.QueryStr(), 100, "OnAsyncCompletion --%p--%p--%d--%d--%d--%d\n", this, m_pW3Context, GetCurrentThreadId(), (UINT)dwLocalStatus, m_fServerResetConn, m_fClientDisconnected);
+            strMoreData.SyncWithBuffer();
+            strDescription.AppendA(strMoreData.QueryStr());
+#endif // DEBUG
+
+            if (strDescription.QueryCCH() != 0)
+            {
+                pResponse->SetErrorDescription(
+                    strDescription.QueryStr(),
+                    strDescription.QueryCCH(),
+                    FALSE);
+            }
+
+            if (hr == HRESULT_FROM_WIN32(ERROR_WINHTTP_INVALID_SERVER_RESPONSE))
+            {
+                if (!m_fServerResetConn)
+                {
+                    RemoveRequest();
+                    pResponse->ResetConnection();
+                    m_fServerResetConn = TRUE;
+                }
+            }
+        }
+    }
+
+    if (m_pWebSocket != NULL && !m_fWebSocketHandleInClose)
+    {
+        m_fWebSocketHandleInClose = TRUE;
+        m_pWebSocket->TerminateRequest();
+    }
+
+    if (m_hRequest != NULL && !m_fHttpHandleInClose)
+    {
+        m_fHttpHandleInClose = TRUE;
+        WinHttpCloseHandle(m_hRequest);
+        m_hRequest = NULL;
+    }
+
+Finished:
+
+    if (fLocked)
+    {
+        DBG_ASSERT(TlsGetValue(g_dwTlsIndex) == this);
+        TlsSetValue(g_dwTlsIndex, NULL);
+        ReleaseSRWLockExclusive(&m_RequestLock);
+        DBG_ASSERT(TlsGetValue(g_dwTlsIndex) == NULL);
+    }
+
+    if (retVal != RQ_NOTIFICATION_PENDING)
+    {
+#ifdef DEBUG
+        DWORD counter = InterlockedIncrement(&g_dwLogCounter) % ASPNETCORE_DEBUG_STRU_ARRAY_SIZE;
+        g_strLogs[counter].Reset();
+        sprintf_s(g_strLogs[counter].QueryStr(), ASPNETCORE_DEBUG_STRU_BUFFER_SIZE,
+            "OnAyncCompletion--%p--%d--%d--%d--%d\n", this, GetCurrentThreadId(), (UINT)dwLocalStatus, retVal, m_fDoneAsyncCompletion);
+        g_strLogs[counter].SyncWithBuffer();
+#endif // DEBUG
+
+        DBG_ASSERT(m_dwHandlers == 0);
+        RemoveRequest();
+
+        // This is just a safety guard to prevent from returning non pending status no more once
+        // which should never happen
+        if (!m_fDoneAsyncCompletion)
+        {
+            m_fDoneAsyncCompletion = TRUE;
+        }
+        else
+        {
+            retVal = RQ_NOTIFICATION_PENDING;
+        }
+    }
+
+    DereferenceForwardingHandler();
+    //
+    // Do not use this object after dereferencing it, it may be gone.
+    //
+    DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO,
+        "FORWARDING_HANDLER::OnAsyncCompletion Done %d", retVal);
+    return retVal;
+}
+
+HRESULT
+FORWARDING_HANDLER::OnSendingRequest(
+    DWORD                       cbCompletion,
+    HRESULT                     hrCompletionStatus,
+    __out BOOL *                pfClientError
+)
+{
+    HRESULT hr = S_OK;
+
+    //
+    // This is a completion for a read from http.sys, abort in case
+    // of failure, if we read anything write it out over WinHTTP,
+    // but we have already reached EOF, now read the response
+    //
+    if (hrCompletionStatus == HRESULT_FROM_WIN32(ERROR_HANDLE_EOF))
+    {
+        DBG_ASSERT(m_BytesToReceive == 0 || m_BytesToReceive == INFINITE);
+        if (m_BytesToReceive == INFINITE)
+        {
+            m_BytesToReceive = 0;
+            m_cchLastSend = 5; // "0\r\n\r\n"
+
+                               //
+                               // WinHttpWriteData can operate asynchronously.
+                               //
+                               // Take reference so that object does not go away as a result of
+                               // async completion.
+                               //
+            if (!WinHttpWriteData(m_hRequest,
+                "0\r\n\r\n",
+                5,
+                NULL))
+            {
+                hr = HRESULT_FROM_WIN32(GetLastError());
+                goto Failure;
+            }
+        }
+        else
+        {
+            m_RequestStatus = FORWARDER_RECEIVING_RESPONSE;
+
+            //
+            // WinHttpReceiveResponse can operate asynchronously.
+            //
+            // Take reference so that object does not go away as a result of
+            // async completion.
+            //
+            if (!WinHttpReceiveResponse(m_hRequest, NULL))
+            {
+                hr = HRESULT_FROM_WIN32(GetLastError());
+                goto Failure;
+            }
+        }
+    }
+    else if (SUCCEEDED(hrCompletionStatus))
+    {
+        DWORD cbOffset;
+
+        if (m_BytesToReceive != INFINITE)
+        {
+            m_BytesToReceive -= cbCompletion;
+            cbOffset = 6;
+        }
+        else
+        {
+            //
+            // For chunk-encoded requests, need to re-chunk the
+            // entity body
+            //
+            // Add the CRLF just before and after the chunk data
+            //
+            m_pEntityBuffer[4] = '\r';
+            m_pEntityBuffer[5] = '\n';
+
+            m_pEntityBuffer[cbCompletion + 6] = '\r';
+            m_pEntityBuffer[cbCompletion + 7] = '\n';
+
+            if (cbCompletion < 0x10)
+            {
+                cbOffset = 3;
+                m_pEntityBuffer[3] = HEX_TO_ASCII(cbCompletion);
+                cbCompletion += 5;
+            }
+            else if (cbCompletion < 0x100)
+            {
+                cbOffset = 2;
+                m_pEntityBuffer[2] = HEX_TO_ASCII(cbCompletion >> 4);
+                m_pEntityBuffer[3] = HEX_TO_ASCII(cbCompletion & 0xf);
+                cbCompletion += 6;
+            }
+            else if (cbCompletion < 0x1000)
+            {
+                cbOffset = 1;
+                m_pEntityBuffer[1] = HEX_TO_ASCII(cbCompletion >> 8);
+                m_pEntityBuffer[2] = HEX_TO_ASCII((cbCompletion >> 4) & 0xf);
+                m_pEntityBuffer[3] = HEX_TO_ASCII(cbCompletion & 0xf);
+                cbCompletion += 7;
+            }
+            else
+            {
+                DBG_ASSERT(cbCompletion < 0x10000);
+
+                cbOffset = 0;
+                m_pEntityBuffer[0] = HEX_TO_ASCII(cbCompletion >> 12);
+                m_pEntityBuffer[1] = HEX_TO_ASCII((cbCompletion >> 8) & 0xf);
+                m_pEntityBuffer[2] = HEX_TO_ASCII((cbCompletion >> 4) & 0xf);
+                m_pEntityBuffer[3] = HEX_TO_ASCII(cbCompletion & 0xf);
+                cbCompletion += 8;
+            }
+        }
+        m_cchLastSend = cbCompletion;
+
+        //
+        // WinHttpWriteData can operate asynchronously.
+        //
+        // Take reference so that object does not go away as a result of
+        // async completion.
+        //
+        if (!WinHttpWriteData(m_hRequest,
+            m_pEntityBuffer + cbOffset,
+            cbCompletion,
+            NULL))
+        {
+            hr = HRESULT_FROM_WIN32(GetLastError());
+            goto Failure;
+        }
+    }
+    else
+    {
+        hr = hrCompletionStatus;
+        *pfClientError = TRUE;
+        goto Failure;
+    }
+
+Failure:
+
+    return hr;
+}
+
+HRESULT
+FORWARDING_HANDLER::OnReceivingResponse(
+)
+{
+    HRESULT hr = S_OK;
+
+    if (m_cBytesBuffered >= m_cMinBufferLimit)
+    {
+        FreeResponseBuffers();
+    }
+
+    if (m_BytesToSend == 0)
+    {
+        //
+        // If response buffering is enabled, try to read large chunks
+        // at a time - also treat very small buffering limit as no
+        // buffering
+        //
+        m_BytesToSend = min(m_cMinBufferLimit, BUFFER_SIZE);
+        if (m_BytesToSend < BUFFER_SIZE / 2)
+        {
+            //
+            // Disable buffering.
+            //
+            m_BytesToSend = 0;
+        }
+    }
+
+    if (m_BytesToSend == 0)
+    {
+        //
+        // No buffering enabled.
+        //
+        // WinHttpQueryDataAvailable can operate asynchronously.
+        //
+        if (!WinHttpQueryDataAvailable(m_hRequest, NULL))
+        {
+            hr = HRESULT_FROM_WIN32(GetLastError());
+            goto Failure;
+        }
+    }
+    else
+    {
+        //
+        // Buffering enabled.
+        //
+
+        if (m_pEntityBuffer == NULL)
+        {
+            m_pEntityBuffer = GetNewResponseBuffer(min(m_BytesToSend, BUFFER_SIZE));
+            if (m_pEntityBuffer == NULL)
+            {
+                hr = E_OUTOFMEMORY;
+                goto Failure;
+            }
+        }
+
+        //
+        // WinHttpReadData can operate asynchronously.
+        //
+        if (!WinHttpReadData(m_hRequest,
+            m_pEntityBuffer,
+            min(m_BytesToSend, BUFFER_SIZE),
+            NULL))
+        {
+            hr = HRESULT_FROM_WIN32(GetLastError());
+            goto Failure;
+        }
+    }
+
+Failure:
+
+    return hr;
+}
+
+VOID
+FORWARDING_HANDLER::OnWinHttpCompletionInternal(
+    HINTERNET   hRequest,
+    DWORD       dwInternetStatus,
+    LPVOID      lpvStatusInformation,
+    DWORD       dwStatusInformationLength
+)
+/*++
+
+Routine Description:
+
+Completion call associated with a WinHTTP operation
+
+Arguments:
+
+hRequest - The winhttp request handle associated with this completion
+dwInternetStatus - enum specifying what the completion is for
+lpvStatusInformation - completion specific information
+dwStatusInformationLength - length of the above information
+
+Return Value:
+
+None
+
+--*/
+{
+    HRESULT hr = S_OK;
+    BOOL fExclusiveLock = FALSE;
+    BOOL fSharedLock = FALSE;
+    BOOL fDoPostCompletion = FALSE;
+    BOOL fClientError = FALSE;
+    BOOL fAnotherCompletionExpected = FALSE;
+    DWORD dwHandlers = 1; // defaullt for http handler
+
+    DBG_ASSERT(m_pW3Context != NULL);
+    __analysis_assume(m_pW3Context != NULL);
+    IHttpResponse * pResponse = m_pW3Context->GetResponse();
+    BOOL fEndRequest = FALSE;
+
+    // Reference the request handler to prevent it from being released prematurely
+    ReferenceForwardingHandler();
+
+    UNREFERENCED_PARAMETER(dwStatusInformationLength);
+
+    if (sm_pTraceLog != NULL)
+    {
+        WriteRefTraceLogEx(sm_pTraceLog,
+            m_cRefs,
+            this,
+            "FORWARDING_HANDLER::OnWinHttpCompletionInternal Enter",
+            reinterpret_cast<PVOID>(static_cast<DWORD_PTR>(dwInternetStatus)),
+            NULL);
+    }
+
+    DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO,
+        "FORWARDING_HANDLER::OnWinHttpCompletionInternal %x --%p",
+        dwInternetStatus, this);
+
+    //
+    // Exclusive lock on the winhttp handle to protect from a client disconnect/
+    // server stop closing the handle while we are using it.
+    //
+    // WinHttp can call async completion on the same thread/stack, so
+    // we have to account for that and not try to take the lock again,
+    // otherwise, we could end up in a deadlock.
+    //
+
+    fEndRequest = (dwInternetStatus == WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING);
+
+    if (TlsGetValue(g_dwTlsIndex) != this)
+    {
+        DBG_ASSERT(TlsGetValue(g_dwTlsIndex) == NULL);
+        if (m_RequestStatus != FORWARDER_RECEIVED_WEBSOCKET_RESPONSE)
+        {
+            // Webscoket has already been guarded by critical section
+            // Only require exclisive lock for non-websocket scenario which has duplex channel
+            // Otherwise, there will be a deadlock
+            AcquireSRWLockExclusive(&m_RequestLock);
+            TlsSetValue(g_dwTlsIndex, this);
+            fExclusiveLock = TRUE;
+            DBG_ASSERT(TlsGetValue(g_dwTlsIndex) == this);
+        }
+        else
+        {
+            AcquireSRWLockShared(&m_RequestLock);
+            TlsSetValue(g_dwTlsIndex, this);
+            fSharedLock = TRUE;
+            DBG_ASSERT(TlsGetValue(g_dwTlsIndex) == this);
+        }
+    }
+
+    if (fEndRequest)
+    {
+        dwHandlers = InterlockedDecrement(&m_dwHandlers);
+    }
+
+    if (m_fFinishRequest)
+    {
+        // Request was done by another thread, skip
+        goto Finished;
+    }
+
+    if(m_fClientDisconnected && (m_RequestStatus != FORWARDER_DONE))
+    {
+        hr = ERROR_CONNECTION_ABORTED;
+        goto Failure;
+    }
+
+    if (m_RequestStatus == FORWARDER_RECEIVED_WEBSOCKET_RESPONSE)
+    {
+        fAnotherCompletionExpected = TRUE;
+
+        if(m_pWebSocket == NULL)
+        {
+            goto Finished;
+        }
+
+        switch (dwInternetStatus)
+        {
+        case WINHTTP_CALLBACK_STATUS_SHUTDOWN_COMPLETE:
+            m_pWebSocket->OnWinHttpShutdownComplete();
+            break;
+
+        case WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE:
+            m_pWebSocket->OnWinHttpSendComplete(
+                (WINHTTP_WEB_SOCKET_STATUS*)lpvStatusInformation
+            );
+            break;
+
+        case WINHTTP_CALLBACK_STATUS_READ_COMPLETE:
+            m_pWebSocket->OnWinHttpReceiveComplete(
+                (WINHTTP_WEB_SOCKET_STATUS*)lpvStatusInformation
+            );
+            break;
+
+        case WINHTTP_CALLBACK_STATUS_REQUEST_ERROR:
+            m_pWebSocket->OnWinHttpIoError(
+                 (WINHTTP_WEB_SOCKET_ASYNC_RESULT*)lpvStatusInformation
+                );
+            break;
+        }
+        goto Finished;
+    }
+
+    switch (dwInternetStatus)
+    {
+    case WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE:
+    case WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE:
+        hr = OnWinHttpCompletionSendRequestOrWriteComplete(hRequest,
+            dwInternetStatus,
+            &fClientError,
+            &fAnotherCompletionExpected);
+        break;
+
+    case WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE:
+        hr = OnWinHttpCompletionStatusHeadersAvailable(hRequest,
+            &fAnotherCompletionExpected);
+        break;
+
+    case WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE:
+        hr = OnWinHttpCompletionStatusDataAvailable(hRequest,
+            *reinterpret_cast<const DWORD *>(lpvStatusInformation), // dwBytes
+            &fAnotherCompletionExpected);
+        break;
+
+    case WINHTTP_CALLBACK_STATUS_READ_COMPLETE:
+        hr = OnWinHttpCompletionStatusReadComplete(pResponse,
+            dwStatusInformationLength,
+            &fAnotherCompletionExpected);
+        break;
+
+    case WINHTTP_CALLBACK_STATUS_REQUEST_ERROR:
+        hr = HRESULT_FROM_WIN32(static_cast<const WINHTTP_ASYNC_RESULT *>(lpvStatusInformation)->dwError);
+        break;
+
+    case WINHTTP_CALLBACK_STATUS_SENDING_REQUEST:
+        //
+        // This is a notification, not a completion.  This notifiation happens
+        // during the Send Request operation.
+        //
+        fAnotherCompletionExpected = TRUE;
+        break;
+
+    case WINHTTP_CALLBACK_STATUS_REQUEST_SENT:
+        //
+        // Need to ignore this event.  We get it as a side-effect of registering
+        // for WINHTTP_CALLBACK_STATUS_SENDING_REQUEST (which we actually need).
+        //
+        hr = S_OK;
+        fAnotherCompletionExpected = TRUE;
+        break;
+
+    case WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING:
+
+        fAnotherCompletionExpected = FALSE;
+
+        if (m_RequestStatus != FORWARDER_DONE)
+        {
+            hr = ERROR_CONNECTION_ABORTED;
+            fClientError = m_fClientDisconnected;
+            goto Failure;
+        }
+        break;
+
+    case WINHTTP_CALLBACK_STATUS_CONNECTION_CLOSED:
+        hr = ERROR_CONNECTION_ABORTED;
+        break;
+
+    default:
+        //
+        // E_UNEXPECTED is rarely used, if seen means that this condition may been occurred.
+        //
+        DBG_ASSERT(FALSE);
+        hr = E_UNEXPECTED;
+        if (sm_pTraceLog != NULL)
+        {
+            WriteRefTraceLogEx(sm_pTraceLog,
+                m_cRefs,
+                this,
+                "FORWARDING_HANDLER::OnWinHttpCompletionInternal Unexpected WinHTTP Status",
+                reinterpret_cast<PVOID>(static_cast<DWORD_PTR>(dwInternetStatus)),
+                NULL);
+        }
+        break;
+    }
+
+    //
+    // Handle failure code for switch statement above.
+    //
+    if (FAILED(hr))
+    {
+        goto Failure;
+    }
+
+    //
+    // WinHTTP completion handled successfully.
+    //
+    goto Finished;
+
+Failure:
+    m_RequestStatus = FORWARDER_DONE;
+    if(!m_fHasError)
+    {
+        m_fHasError = TRUE;
+        pResponse->DisableKernelCache();
+        pResponse->GetRawHttpResponse()->EntityChunkCount = 0;
+
+        if (fClientError || m_fClientDisconnected)
+        {
+            if (!m_fResponseHeadersReceivedAndSet)
+            {
+                pResponse->SetStatus(400, "Bad Request", 0, HRESULT_FROM_WIN32(WSAECONNRESET));
+            }
+            else
+            {
+                //
+                // Response headers from origin server were
+                // already received and set for the current response.
+                // Honor the response status.
+                //
+            }
+        }
+        else
+        {
+            STACK_STRU(strDescription, 128);
+            pResponse->SetStatus(502, "Bad Gateway", 3, hr);
+
+            if (hr > HRESULT_FROM_WIN32(WINHTTP_ERROR_BASE) &&
+                hr <= HRESULT_FROM_WIN32(WINHTTP_ERROR_LAST))
+            {
+#pragma prefast (suppress : __WARNING_FUNCTION_NEEDS_REVIEW, "Function and parameters reviewed.")
+                FormatMessage(
+                    FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_HMODULE,
+                    g_hWinHttpModule,
+                    HRESULT_CODE(hr),
+                    0,
+                    strDescription.QueryStr(),
+                    strDescription.QuerySizeCCH(),
+                    NULL);
+            }
+            else
+            {
+                LoadString(g_hModule,
+                    IDS_SERVER_ERROR,
+                    strDescription.QueryStr(),
+                    strDescription.QuerySizeCCH());
+            }
+            strDescription.SyncWithBuffer();
+
+#ifdef DEBUG
+            // addingmore data to error description to help us diaganose the issue
+            STACK_STRA(strMoreData, 128);
+            sprintf_s(strMoreData.QueryStr(), 100, "OnWinHttpCompletionInternal --%p--%d--%d--%d\n", this, GetCurrentThreadId(), dwInternetStatus, m_fServerResetConn);
+            strMoreData.SyncWithBuffer();
+            strDescription.AppendA(strMoreData.QueryStr());
+#endif // DEBUG
+
+            if (strDescription.QueryCCH() != 0)
+            {
+                pResponse->SetErrorDescription(
+                    strDescription.QueryStr(),
+                    strDescription.QueryCCH(),
+                    FALSE);
+            }
+
+            if (hr == HRESULT_FROM_WIN32(ERROR_WINHTTP_INVALID_SERVER_RESPONSE))
+            {
+                if (!m_fServerResetConn) 
+                {
+                    RemoveRequest();
+                    pResponse->ResetConnection();
+                    m_fServerResetConn = TRUE;
+                }
+            }
+        }
+    }
+
+Finished:
+    //
+    // Since we use TLS to guard WinHttp operation, call PostCompletion instead of
+    // IndicateCompletion to allow cleaning up the TLS before thread reuse.
+    // Never post after the request has been finished for whatever reason
+    //
+    // Only postCompletion after all WinHttp handle got closed,
+    // i.e., received WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING callback for all handles
+    // So that no further WinHttp callback will be called
+    // Never post completion again after that
+    // Otherwise, there will be a AV as the request already passed IIS pipeline
+    //
+    if (fEndRequest && !m_fFinishRequest && dwHandlers ==0)
+    {
+        //
+        // Happy path
+        //
+#ifdef DEBUG
+        DWORD counter = InterlockedIncrement(&g_dwLogCounter) % ASPNETCORE_DEBUG_STRU_ARRAY_SIZE;
+        sprintf_s(g_strLogs[counter].QueryStr(), ASPNETCORE_DEBUG_STRU_BUFFER_SIZE, 
+            "PostCompletion 0 --%p--%p--%d\n", this, m_pW3Context, GetCurrentThreadId());
+        g_strLogs[counter].SyncWithBuffer();
+#endif // DEBUG
+
+        // Marked the request is finished, no more PostCompletion is allowed
+        RemoveRequest();
+        m_fFinishRequest = TRUE;
+        fDoPostCompletion = TRUE;
+        if (m_pWebSocket != NULL)
+        {
+            delete(m_pWebSocket);
+            m_pWebSocket = NULL;
+        }
+    }
+
+    else if (m_RequestStatus == FORWARDER_DONE)
+    {
+        //
+        // Error path
+        //
+        RemoveRequest();
+        if (m_hRequest != NULL && !m_fHttpHandleInClose)
+        {
+            m_fHttpHandleInClose = TRUE;
+            WinHttpCloseHandle(m_hRequest);
+            m_hRequest = NULL;
+        }
+
+        if (m_pWebSocket != NULL && !m_fWebSocketHandleInClose)
+        {
+            m_fWebSocketHandleInClose = TRUE;
+            m_pWebSocket->TerminateRequest();
+        }
+
+        if (fEndRequest)
+        {
+            fDoPostCompletion = (dwHandlers == 0 && !m_fFinishRequest);
+            if (fDoPostCompletion)
+            {
+#ifdef DEBUG
+                DWORD counter = InterlockedIncrement(&g_dwLogCounter) % ASPNETCORE_DEBUG_STRU_ARRAY_SIZE;
+                sprintf_s(g_strLogs[counter].QueryStr(), ASPNETCORE_DEBUG_STRU_BUFFER_SIZE,
+                    "PostCompletion 1 --%p--%p--%d\n", this, m_pW3Context, GetCurrentThreadId());
+                g_strLogs[counter].SyncWithBuffer();
+#endif // DEBUG
+                // Marked the request is finished, no more PostCompletion is allowed
+                m_fFinishRequest = TRUE;
+            }
+        }
+    }
+    else if (!fAnotherCompletionExpected)
+    {
+        //
+        // Regular async IO operation
+        //
+        fDoPostCompletion = !m_fFinishRequest;
+#ifdef DEBUG
+        if (fDoPostCompletion)
+        {
+            DWORD counter = InterlockedIncrement(&g_dwLogCounter) % ASPNETCORE_DEBUG_STRU_ARRAY_SIZE;
+            sprintf_s(g_strLogs[counter].QueryStr(), ASPNETCORE_DEBUG_STRU_BUFFER_SIZE,
+                "PostCompletion 2 --%p--%p--%d\n", this, m_pW3Context, GetCurrentThreadId());
+            g_strLogs[counter].SyncWithBuffer();
+        }
+#endif // DEBUG
+    }
+
+    //
+    // No code should access IIS m_pW3Context after posting the completion.
+    //
+    if (fDoPostCompletion)
+    {
+        m_pW3Context->PostCompletion(0);
+    }
+
+    if (fExclusiveLock)
+    {
+        DBG_ASSERT(TlsGetValue(g_dwTlsIndex) == this);
+        TlsSetValue(g_dwTlsIndex, NULL);
+        ReleaseSRWLockExclusive(&m_RequestLock);
+        DBG_ASSERT(TlsGetValue(g_dwTlsIndex) == NULL);
+    }
+    else if (fSharedLock)
+    {
+        DBG_ASSERT(TlsGetValue(g_dwTlsIndex) == this);
+        TlsSetValue(g_dwTlsIndex, NULL);
+        ReleaseSRWLockShared(&m_RequestLock);
+        DBG_ASSERT(TlsGetValue(g_dwTlsIndex) == NULL);
+    }
+
+    DereferenceForwardingHandler();
+
+}
+
+HRESULT
+FORWARDING_HANDLER::OnWinHttpCompletionSendRequestOrWriteComplete(
+    HINTERNET                   hRequest,
+    DWORD,
+    __out BOOL *                pfClientError,
+    __out BOOL *                pfAnotherCompletionExpected
+)
+{
+    HRESULT hr = S_OK;
+    IHttpRequest *      pRequest = m_pW3Context->GetRequest();
+
+    //
+    // completion for sending the initial request or request entity to
+    // winhttp, get more request entity if available, else start receiving
+    // the response
+    //
+    if (m_BytesToReceive > 0)
+    {
+        if (m_pEntityBuffer == NULL)
+        {
+            m_pEntityBuffer = GetNewResponseBuffer(
+                ENTITY_BUFFER_SIZE);
+            if (m_pEntityBuffer == NULL)
+            {
+                hr = E_OUTOFMEMORY;
+                goto Finished;
+            }
+        }
+
+        if (sm_pTraceLog != NULL)
+        {
+            WriteRefTraceLogEx(sm_pTraceLog,
+                m_cRefs,
+                this,
+                "Calling ReadEntityBody",
+                NULL,
+                NULL);
+        }
+        hr = pRequest->ReadEntityBody(
+            m_pEntityBuffer + 6,
+            min(m_BytesToReceive, BUFFER_SIZE),
+            TRUE,       // fAsync
+            NULL,       // pcbBytesReceived
+            NULL);      // pfCompletionPending
+        if (hr == HRESULT_FROM_WIN32(ERROR_HANDLE_EOF))
+        {
+            DBG_ASSERT(m_BytesToReceive == 0 ||
+                m_BytesToReceive == INFINITE);
+
+            //
+            // ERROR_HANDLE_EOF is not an error.
+            //
+            hr = S_OK;
+
+            if (m_BytesToReceive == INFINITE)
+            {
+                m_BytesToReceive = 0;
+                m_cchLastSend = 5;
+
+                if (!WinHttpWriteData(m_hRequest,
+                    "0\r\n\r\n",
+                    5,
+                    NULL))
+                {
+                    hr = HRESULT_FROM_WIN32(GetLastError());
+                    goto Finished;
+                }
+                *pfAnotherCompletionExpected = TRUE;
+
+                goto Finished;
+            }
+        }
+        else if (FAILED(hr))
+        {
+            *pfClientError = TRUE;
+            goto Finished;
+        }
+        else
+        {
+            //
+            // ReadEntityBody will post a completion to IIS.
+            //
+            *pfAnotherCompletionExpected = TRUE;
+
+            goto Finished;
+        }
+    }
+
+    m_RequestStatus = FORWARDER_RECEIVING_RESPONSE;
+
+    if (!WinHttpReceiveResponse(hRequest, NULL))
+    {
+        hr = HRESULT_FROM_WIN32(GetLastError());
+        goto Finished;
+    }
+    *pfAnotherCompletionExpected = TRUE;
+
+Finished:
+
+    return hr;
+}
+
+HRESULT
+FORWARDING_HANDLER::OnWinHttpCompletionStatusHeadersAvailable(
+    HINTERNET                   hRequest,
+    __out BOOL *                pfAnotherCompletionExpected
+)
+{
+    HRESULT       hr = S_OK;
+    STACK_BUFFER(bufHeaderBuffer, 2048);
+    STACK_STRA(strHeaders, 2048);
+    DWORD         dwHeaderSize = bufHeaderBuffer.QuerySize();
+
+    UNREFERENCED_PARAMETER(pfAnotherCompletionExpected);
+
+    //
+    // Headers are available, read the status line and headers and pass
+    // them on to the client
+    //
+    // WinHttpQueryHeaders operates synchronously,
+    // no need for taking reference.
+    //
+    dwHeaderSize = bufHeaderBuffer.QuerySize();
+    if (!WinHttpQueryHeaders(hRequest,
+        WINHTTP_QUERY_RAW_HEADERS_CRLF,
+        WINHTTP_HEADER_NAME_BY_INDEX,
+        bufHeaderBuffer.QueryPtr(),
+        &dwHeaderSize,
+        WINHTTP_NO_HEADER_INDEX))
+    {
+        if (!bufHeaderBuffer.Resize(dwHeaderSize))
+        {
+            hr = E_OUTOFMEMORY;
+            goto Finished;
+        }
+
+        //
+        // WinHttpQueryHeaders operates synchronously,
+        // no need for taking reference.
+        //
+        if (!WinHttpQueryHeaders(hRequest,
+            WINHTTP_QUERY_RAW_HEADERS_CRLF,
+            WINHTTP_HEADER_NAME_BY_INDEX,
+            bufHeaderBuffer.QueryPtr(),
+            &dwHeaderSize,
+            WINHTTP_NO_HEADER_INDEX))
+        {
+            hr = HRESULT_FROM_WIN32(GetLastError());
+            goto Finished;
+        }
+    }
+
+    if (FAILED(hr = strHeaders.CopyW(
+        reinterpret_cast<PWSTR>(bufHeaderBuffer.QueryPtr()))))
+    {
+        goto Finished;
+    }
+
+    // Issue: The reason we add trailing \r\n is to eliminate issues that have been observed
+    // in some configurations where status and headers would not have final \r\n nor \r\n\r\n
+    // (last header was null terminated).That caused crash within header parsing code that expected valid
+    // format. Parsing code was fized to return ERROR_INVALID_PARAMETER, but we still should make
+    // Example of a status+header string that was causing problems (note the missing \r\n at the end)
+    // HTTP/1.1 302 Moved Permanently\r\n....\r\nLocation:http://site\0
+    //
+
+    if (!strHeaders.IsEmpty() && strHeaders.QueryStr()[strHeaders.QueryCCH() - 1] != '\n')
+    {
+        hr = strHeaders.Append("\r\n");
+        if (FAILED(hr))
+        {
+            goto Finished;
+        }
+    }
+
+    if (FAILED(hr = SetStatusAndHeaders(
+        strHeaders.QueryStr(),
+        strHeaders.QueryCCH())))
+    {
+        goto Finished;
+    }
+
+    FreeResponseBuffers();
+
+    //
+    // If the request was websocket, and response was 101,
+    // trigger a flush, so that IIS's websocket module
+    // can get a chance to initialize and complete the handshake.
+    //
+
+    if (m_fWebSocketEnabled)
+    {
+
+        hr = m_pW3Context->GetResponse()->Flush(
+            TRUE,
+            TRUE,
+            NULL,
+            NULL);
+
+        if (FAILED(hr))
+        {
+            *pfAnotherCompletionExpected = FALSE;
+        }
+        else
+        {
+            m_RequestStatus = FORWARDER_RECEIVED_WEBSOCKET_RESPONSE;
+            *pfAnotherCompletionExpected = TRUE;
+        }
+    }
+
+Finished:
+
+    return hr;
+}
+
+HRESULT
+FORWARDING_HANDLER::OnWinHttpCompletionStatusDataAvailable(
+    HINTERNET                   hRequest,
+    DWORD                       dwBytes,
+    __out BOOL *                pfAnotherCompletionExpected
+)
+{
+    HRESULT hr = S_OK;
+
+    //
+    // Response data is available from winhttp, read it
+    //
+    if (dwBytes == 0)
+    {
+        if (m_cContentLength != 0)
+        {
+            hr = HRESULT_FROM_WIN32(ERROR_WINHTTP_INVALID_SERVER_RESPONSE);
+            goto Finished;
+        }
+
+        m_RequestStatus = FORWARDER_DONE;
+
+        goto Finished;
+    }
+
+    m_BytesToSend = dwBytes;
+    if (m_cContentLength != 0)
+    {
+        m_cContentLength -= dwBytes;
+    }
+
+    m_pEntityBuffer = GetNewResponseBuffer(
+        min(m_BytesToSend, BUFFER_SIZE));
+    if (m_pEntityBuffer == NULL)
+    {
+        hr = E_OUTOFMEMORY;
+        goto Finished;
+    }
+
+    if (!WinHttpReadData(hRequest,
+        m_pEntityBuffer,
+        min(m_BytesToSend, BUFFER_SIZE),
+        NULL))
+    {
+        hr = HRESULT_FROM_WIN32(GetLastError());
+        goto Finished;
+    }
+    *pfAnotherCompletionExpected = TRUE;
+
+Finished:
+
+    return hr;
+}
+
+HRESULT
+FORWARDING_HANDLER::OnWinHttpCompletionStatusReadComplete(
+    __in IHttpResponse *        pResponse,
+    DWORD                       dwStatusInformationLength,
+    __out BOOL *                pfAnotherCompletionExpected
+)
+{
+    HRESULT hr = S_OK;
+
+    //
+    // Response data has been read from winhttp, send it to the client
+    //
+    m_BytesToSend -= dwStatusInformationLength;
+
+    if (m_cMinBufferLimit >= BUFFER_SIZE / 2)
+    {
+        if (m_cContentLength != 0)
+        {
+            m_cContentLength -= dwStatusInformationLength;
+        }
+
+        //
+        // If we were not using WinHttpQueryDataAvailable and winhttp
+        // did not fill our buffer, we must have reached the end of the
+        // response
+        //
+        if (dwStatusInformationLength == 0 ||
+            m_BytesToSend != 0)
+        {
+            if (m_cContentLength != 0)
+            {
+                hr = HRESULT_FROM_WIN32(ERROR_WINHTTP_INVALID_SERVER_RESPONSE);
+                goto Finished;
+            }
+
+            m_RequestStatus = FORWARDER_DONE;
+        }
+    }
+    else
+    {
+        DBG_ASSERT(dwStatusInformationLength != 0);
+    }
+
+    if (dwStatusInformationLength == 0)
+    {
+        goto Finished;
+    }
+    else
+    {
+        m_cBytesBuffered += dwStatusInformationLength;
+
+        HTTP_DATA_CHUNK Chunk;
+        Chunk.DataChunkType = HttpDataChunkFromMemory;
+        Chunk.FromMemory.pBuffer = m_pEntityBuffer;
+        Chunk.FromMemory.BufferLength = dwStatusInformationLength;
+        if (FAILED(hr = pResponse->WriteEntityChunkByReference(&Chunk)))
+        {
+            goto Finished;
+        }
+    }
+
+    if (m_cBytesBuffered >= m_cMinBufferLimit)
+    {
+        //
+        // Always post a completion to resume the WinHTTP data pump.
+        //
+        hr = pResponse->Flush(TRUE,     // fAsync
+            TRUE,     // fMoreData
+            NULL);    // pcbSent    
+        if (FAILED(hr))
+        {
+            goto Finished;
+        }
+        *pfAnotherCompletionExpected = TRUE;
+    }
+    else
+    {
+        *pfAnotherCompletionExpected = FALSE;
+    }
+
+Finished:
+
+    return hr;
+}
+
+// static
+HRESULT
+FORWARDING_HANDLER::StaticInitialize(
+    BOOL fEnableReferenceCountTracing
+)
+/*++
+
+Routine Description:
+
+Global initialization routine for FORWARDING_HANDLERs
+
+Arguments:
+
+fEnableReferenceCountTracing  - True if ref count tracing should be use.
+
+Return Value:
+
+HRESULT
+
+--*/
+{
+    HRESULT                         hr = S_OK;
+
+    sm_pAlloc = new ALLOC_CACHE_HANDLER;
+    if (sm_pAlloc == NULL)
+    {
+        hr = E_OUTOFMEMORY;
+        goto Failure;
+    }
+
+    hr = sm_pAlloc->Initialize(sizeof(FORWARDING_HANDLER),
+        128); // nThreshold
+    if (FAILED(hr))
+    {
+        goto Failure;
+    }
+
+    //
+    // Open the session handle, specify random user-agent that will be
+    // overwritten by the client
+    //
+    sm_hSession = WinHttpOpen(L"",
+        WINHTTP_ACCESS_TYPE_NO_PROXY,
+        WINHTTP_NO_PROXY_NAME,
+        WINHTTP_NO_PROXY_BYPASS,
+        WINHTTP_FLAG_ASYNC);
+    if (sm_hSession == NULL)
+    {
+        hr = HRESULT_FROM_WIN32(GetLastError());
+        goto Failure;
+    }
+
+    //
+    // Don't set non-blocking callbacks WINHTTP_OPTION_ASSURED_NON_BLOCKING_CALLBACKS, 
+    // as we will call WinHttpQueryDataAvailable to get response on the same thread
+    // that we received callback from Winhttp on completing sending/forwarding the request
+    // 
+
+    //
+    // Setup the callback function
+    //
+    if (WinHttpSetStatusCallback(sm_hSession,
+        FORWARDING_HANDLER::OnWinHttpCompletion,
+        (WINHTTP_CALLBACK_FLAG_ALL_COMPLETIONS |
+            WINHTTP_CALLBACK_STATUS_SENDING_REQUEST),
+        NULL) == WINHTTP_INVALID_STATUS_CALLBACK)
+    {
+        hr = HRESULT_FROM_WIN32(GetLastError());
+        goto Failure;
+    }
+
+    //
+    // Make sure we see the redirects (rather than winhttp doing it
+    // automatically)
+    //
+    DWORD dwRedirectOption = WINHTTP_OPTION_REDIRECT_POLICY_NEVER;
+    if (!WinHttpSetOption(sm_hSession,
+        WINHTTP_OPTION_REDIRECT_POLICY,
+        &dwRedirectOption,
+        sizeof(dwRedirectOption)))
+    {
+        hr = HRESULT_FROM_WIN32(GetLastError());
+        goto Failure;
+    }
+
+    // Initialize Application Manager
+    APPLICATION_MANAGER *pApplicationManager = APPLICATION_MANAGER::GetInstance();
+    if (pApplicationManager == NULL)
+    {
+        hr = E_OUTOFMEMORY;
+        goto Failure;
+    }
+
+    hr = pApplicationManager->Initialize();
+    if (FAILED(hr))
+    {
+        goto Failure;
+    }
+
+    // Initialize PROTOCOL_CONFIG
+    sm_ProtocolConfig.Initialize();
+
+    if (FAILED(hr = sm_strErrorFormat.Resize(256)))
+    {
+        goto Failure;
+    }
+
+    if (LoadString(g_hModule,
+        IDS_INVALID_PROPERTY,
+        sm_strErrorFormat.QueryStr(),
+        sm_strErrorFormat.QuerySizeCCH()) == 0)
+    {
+        hr = HRESULT_FROM_WIN32(GetLastError());
+        goto Failure;
+    }
+    sm_strErrorFormat.SyncWithBuffer();
+
+    // If RegisterEventSource failed, we cannot do any thing about it
+    // No need to check whether the returned handle is valid
+
+    if (g_pHttpServer->IsCommandLineLaunch())
+    {
+        sm_hEventLog = RegisterEventSource(NULL, ASPNETCORE_IISEXPRESS_EVENT_PROVIDER);
+    }
+    else
+    {
+        sm_hEventLog = RegisterEventSource(NULL, ASPNETCORE_EVENT_PROVIDER);
+    }
+
+    g_dwTlsIndex = TlsAlloc();
+    if (g_dwTlsIndex == TLS_OUT_OF_INDEXES)
+    {
+        hr = HRESULT_FROM_WIN32(GetLastError());
+        goto Failure;
+    }
+
+    if (fEnableReferenceCountTracing)
+    {
+        sm_pTraceLog = CreateRefTraceLog(10000, 0);
+    }
+
+    return S_OK;
+
+Failure:
+
+    StaticTerminate();
+
+    return hr;
+}
+
+// static
+VOID
+FORWARDING_HANDLER::StaticTerminate(
+    VOID
+)
+/*++
+
+Routine Description:
+
+Global termination routine for FORWARDING_HANDLERs
+
+Arguments:
+
+None
+
+Return Value:
+
+None
+
+--*/
+{
+    //
+    // Delete all the statics
+    //
+
+    APPLICATION_MANAGER::Cleanup();
+
+    //
+    // wait for all server processes to go away
+    // for a max of 10 seconds.
+    //
+
+    DWORD tickCount = GetTickCount();
+
+    while (g_dwActiveServerProcesses > 0)
+    {
+        if ((GetTickCount() - tickCount) > 10000)
+        {
+            break;
+        }
+        Sleep(250);
+    }
+
+    if (sm_hSession != NULL)
+    {
+        WinHttpCloseHandle(sm_hSession);
+        sm_hSession = NULL;
+    }
+
+    if (sm_hEventLog != NULL)
+    {
+        DeregisterEventSource(sm_hEventLog);
+        sm_hEventLog = NULL;
+    }
+
+    if (g_dwTlsIndex != TLS_OUT_OF_INDEXES)
+    {
+        DBG_REQUIRE(TlsFree(g_dwTlsIndex));
+        g_dwTlsIndex = TLS_OUT_OF_INDEXES;
+    }
+
+    sm_strErrorFormat.Reset();
+
+    if (sm_pTraceLog != NULL)
+    {
+        DestroyRefTraceLog(sm_pTraceLog);
+        sm_pTraceLog = NULL;
+    }
+
+    if (sm_pAlloc != NULL)
+    {
+        delete sm_pAlloc;
+        sm_pAlloc = NULL;
+    }
+}
+
+VOID
+CopyMultiSzToOutput(
+    IGlobalRSCAQueryProvider *  pProvider,
+    PCWSTR                      pszList,
+    DWORD *                     pcbData
+)
+{
+    PBYTE pvData;
+    DWORD cbData = 0;
+    PCWSTR pszListCopy = pszList;
+    while (*pszList != L'\0')
+    {
+        cbData += (static_cast<DWORD>(wcslen(pszList)) + 1) * sizeof(WCHAR);
+        pszList += wcslen(pszList) + 1;
+    }
+    cbData += sizeof(WCHAR);
+    if (FAILED(pProvider->GetOutputBuffer(cbData,
+        &pvData)))
+    {
+        return;
+    }
+    memcpy(pvData,
+        pszListCopy,
+        cbData);
+    *pcbData = cbData;
+}
+
+struct AFFINITY_LOOKUP_CONTEXT
+{
+    DWORD       timeout;
+    PCWSTR      pszServer;
+    BUFFER *    pHostNames;
+    DWORD       cbData;
+};
+
+struct CACHE_CONTEXT
+{
+    PCSTR   pszHostName;
+    IGlobalRSCAQueryProvider *pProvider;
+    __field_bcount_part(cbBuffer, cbData)
+        PBYTE   pvData;
+    DWORD   cbData;
+    DWORD   cbBuffer;
+};
+
+VOID
+FORWARDING_HANDLER::TerminateRequest(
+    BOOL    fClientInitiated
+)
+{
+    BOOL fAcquiredLock = FALSE;
+    if (TlsGetValue(g_dwTlsIndex) != this)
+    {
+        AcquireSRWLockExclusive(&m_RequestLock);
+        TlsSetValue(g_dwTlsIndex, this);
+        DBG_ASSERT(TlsGetValue(g_dwTlsIndex) == this);
+        fAcquiredLock = TRUE;
+    }
+
+    // Only set the disconnect flag as the disconnect happens, request most likely is in OnAsyncCompletion
+    // If we close the handle here, most likely WinHttp callback happens on the same threads. 
+    // We will have two OnAyncCompletion calls and may have race on PostCompletion
+    // Need do more investigation
+    if (!m_fHttpHandleInClose)
+    {
+        m_fClientDisconnected = fClientInitiated;
+        DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO,
+            "FORWARDING_HANDLER::TerminateRequest");
+        RemoveRequest();
+
+        if (m_RequestStatus == FORWARDER_RECEIVED_WEBSOCKET_RESPONSE)
+        {
+            //
+            // websocket client is gone, cannot finish closing handshake gracefully
+            // have to terminate the request
+            //
+            if (m_pWebSocket != NULL)
+            {
+                m_pWebSocket->TerminateRequest();
+            }
+        }
+    }
+    if (fAcquiredLock)
+    {
+        DBG_ASSERT(TlsGetValue(g_dwTlsIndex) == this);
+        TlsSetValue(g_dwTlsIndex, NULL);
+        ReleaseSRWLockExclusive(&m_RequestLock);
+        DBG_ASSERT(TlsGetValue(g_dwTlsIndex) == NULL);
+    }
+}
+
+BYTE *
+FORWARDING_HANDLER::GetNewResponseBuffer(
+    DWORD   dwBufferSize
+)
+{
+    DWORD dwNeededSize = (m_cEntityBuffers + 1) * sizeof(BYTE *);
+    if (dwNeededSize > m_buffEntityBuffers.QuerySize() &&
+        !m_buffEntityBuffers.Resize(
+            max(dwNeededSize, m_buffEntityBuffers.QuerySize() * 2)))
+    {
+        return NULL;
+    }
+
+    BYTE *pBuffer = (BYTE *)HeapAlloc(GetProcessHeap(),
+        0, // dwFlags
+        dwBufferSize);
+    if (pBuffer == NULL)
+    {
+        return NULL;
+    }
+
+    m_buffEntityBuffers.QueryPtr()[m_cEntityBuffers] = pBuffer;
+    m_cEntityBuffers++;
+
+    return pBuffer;
+}
+
+VOID
+FORWARDING_HANDLER::FreeResponseBuffers()
+{
+    BYTE **pBuffers = m_buffEntityBuffers.QueryPtr();
+    for (DWORD i = 0; i<m_cEntityBuffers; i++)
+    {
+        HeapFree(GetProcessHeap(),
+            0, // dwFlags
+            pBuffers[i]);
+    }
+    m_cEntityBuffers = 0;
+    m_pEntityBuffer = NULL;
+    m_cBytesBuffered = 0;
+}
diff --git a/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/src/main.cxx b/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/src/main.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..7195ca7dff63d73265483165a58353b123606a87
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/src/main.cxx
@@ -0,0 +1,272 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#include "precomp.hxx"
+#include <IPHlpApi.h>
+
+HTTP_MODULE_ID      g_pModuleId = NULL;
+IHttpServer *       g_pHttpServer = NULL;
+BOOL                g_fAsyncDisconnectAvailable = FALSE;
+BOOL                g_fWinHttpNonBlockingCallbackAvailable = FALSE;
+PCWSTR              g_pszModuleName = NULL;
+HINSTANCE           g_hModule;
+HINSTANCE           g_hWinHttpModule;
+BOOL                g_fWebSocketSupported = FALSE;
+DWORD               g_dwTlsIndex = TLS_OUT_OF_INDEXES;
+BOOL                g_fEnableReferenceCountTracing = FALSE;
+DWORD               g_dwAspNetCoreDebugFlags = 0;
+BOOL                g_fNsiApiNotSupported = FALSE;
+DWORD               g_dwActiveServerProcesses = 0;
+DWORD               g_OptionalWinHttpFlags = 0; //specify additional WinHTTP options when using WinHttpOpenRequest API.
+DWORD               g_dwDebugFlags = 0;
+PCSTR               g_szDebugLabel = "ASPNET_CORE_MODULE";
+
+#ifdef DEBUG
+STRA                g_strLogs[ASPNETCORE_DEBUG_STRU_ARRAY_SIZE];
+DWORD               g_dwLogCounter = 0;
+#endif // DEBUG
+
+
+BOOL WINAPI DllMain(
+    HMODULE hModule,
+    DWORD   dwReason,
+    LPVOID
+    )
+{
+    switch (dwReason)
+    {
+    case DLL_PROCESS_ATTACH:
+        g_hModule = hModule;
+        DisableThreadLibraryCalls(hModule);
+        break;
+    default:
+        break;
+    }
+
+    return TRUE;
+}
+
+VOID
+LoadGlobalConfiguration(
+VOID
+)
+{
+    HKEY hKey;
+
+    if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
+        L"SOFTWARE\\Microsoft\\IIS Extensions\\IIS AspNetCore Module\\Parameters",
+        0,
+        KEY_READ,
+        &hKey) == NO_ERROR)
+    {
+        DWORD dwType;
+        DWORD dwData;
+        DWORD cbData;
+
+        cbData = sizeof(dwData);
+        if ((RegQueryValueEx(hKey,
+            L"OptionalWinHttpFlags",
+            NULL,
+            &dwType,
+            (LPBYTE)&dwData,
+            &cbData) == NO_ERROR) &&
+            (dwType == REG_DWORD))
+        {
+            g_OptionalWinHttpFlags = dwData;
+        }
+
+        cbData = sizeof(dwData);
+        if ((RegQueryValueEx(hKey,
+            L"EnableReferenceCountTracing",
+            NULL,
+            &dwType,
+            (LPBYTE)&dwData,
+            &cbData) == NO_ERROR) &&
+            (dwType == REG_DWORD) && (dwData == 1 || dwData == 0))
+        {
+            g_fEnableReferenceCountTracing = !!dwData;
+        }
+
+        cbData = sizeof(dwData);
+        if ((RegQueryValueEx(hKey,
+            L"DebugFlags",
+            NULL,
+            &dwType,
+            (LPBYTE)&dwData,
+            &cbData) == NO_ERROR) &&
+            (dwType == REG_DWORD))
+        {
+            g_dwAspNetCoreDebugFlags = dwData;
+        }
+
+        RegCloseKey(hKey);
+    }
+
+    DWORD dwSize = 0;
+    DWORD dwResult = GetExtendedTcpTable(NULL,
+        &dwSize,
+        FALSE,
+        AF_INET,
+        TCP_TABLE_OWNER_PID_LISTENER,
+        0);
+    if (dwResult != NO_ERROR && dwResult != ERROR_INSUFFICIENT_BUFFER)
+    {
+        g_fNsiApiNotSupported = TRUE;
+    }
+}
+
+HRESULT
+__stdcall
+RegisterModule(
+DWORD                           dwServerVersion,
+IHttpModuleRegistrationInfo *   pModuleInfo,
+IHttpServer *                   pHttpServer
+)
+/*++
+
+Routine description:
+
+Function called by IIS immediately after loading the module, used to let
+IIS know what notifications the module is interested in
+
+Arguments:
+
+dwServerVersion - IIS version the module is being loaded on
+pModuleInfo - info regarding this module
+pHttpServer - callback functions which can be used by the module at
+any point
+
+Return value:
+
+HRESULT
+
+--*/
+{
+    HRESULT                 hr = S_OK;
+    CProxyModuleFactory *   pFactory = NULL;
+
+#ifdef DEBUG
+    CREATE_DEBUG_PRINT_OBJECT("Asp.Net Core Module");
+    g_dwDebugFlags = DEBUG_FLAGS_ANY;
+#endif // DEBUG
+
+    LoadGlobalConfiguration();
+
+    //
+    // 7.0 is 0,7
+    //
+    if (dwServerVersion > MAKELONG(0, 7))
+    {
+        g_fAsyncDisconnectAvailable = TRUE;
+    }
+
+    //
+    // 8.0 is 0,8
+    //
+    if (dwServerVersion >= MAKELONG(0, 8))
+    {
+        // IISOOB:36641 Enable back WINHTTP_OPTION_ASSURED_NON_BLOCKING_CALLBACKS for Win8.
+        // g_fWinHttpNonBlockingCallbackAvailable = TRUE;
+        g_fWebSocketSupported = TRUE;
+    }
+
+    hr = WINHTTP_HELPER::StaticInitialize();
+    if (FAILED(hr))
+    {
+        if (hr == HRESULT_FROM_WIN32(ERROR_PROC_NOT_FOUND))
+        {
+            g_fWebSocketSupported = FALSE;
+        }
+        else
+        {
+            goto Finished;
+        }
+    }
+
+    g_pModuleId = pModuleInfo->GetId();
+    g_pszModuleName = pModuleInfo->GetName();
+    g_pHttpServer = pHttpServer;
+
+#ifdef DEBUG
+    for (int i = 0; i < ASPNETCORE_DEBUG_STRU_ARRAY_SIZE; i++)
+    {
+        g_strLogs[i].Resize(ASPNETCORE_DEBUG_STRU_BUFFER_SIZE + 1);
+    }
+#endif // DEBUG
+    //
+    // WinHTTP does not create enough threads, ask it to create more.
+    // Starting in Windows 7, this setting is ignored because WinHTTP
+    // uses a thread pool.
+    //
+    SYSTEM_INFO si;
+    GetSystemInfo(&si);
+    DWORD dwThreadCount = (si.dwNumberOfProcessors * 3 + 1) / 2;
+    WinHttpSetOption(NULL,
+        WINHTTP_OPTION_WORKER_THREAD_COUNT,
+        &dwThreadCount,
+        sizeof(dwThreadCount));
+
+    //
+    // Create the factory before any static initialization.
+    // The CProxyModuleFactory::Terminate method will clean any
+    // static object initialized.
+    //
+    pFactory = new CProxyModuleFactory;
+    if (pFactory == NULL)
+    {
+        hr = E_OUTOFMEMORY;
+        goto Finished;
+    }
+
+    hr = pModuleInfo->SetRequestNotifications(
+        pFactory,
+        RQ_EXECUTE_REQUEST_HANDLER,
+        0);
+    if (FAILED(hr))
+    {
+        goto Finished;
+    }
+
+    pFactory = NULL;	
+    g_pResponseHeaderHash = new RESPONSE_HEADER_HASH;
+    if (g_pResponseHeaderHash == NULL)
+    {
+        hr = E_OUTOFMEMORY;
+        goto Finished;
+    }
+
+    hr = g_pResponseHeaderHash->Initialize();
+    if (FAILED(hr))
+    {
+        goto Finished;
+    }
+
+    hr = ALLOC_CACHE_HANDLER::StaticInitialize();
+    if (FAILED(hr))
+    {
+        goto Finished;
+    }
+
+    hr = FORWARDING_HANDLER::StaticInitialize(g_fEnableReferenceCountTracing);
+    if (FAILED(hr))
+    {
+        goto Finished;
+    }
+
+    hr = WEBSOCKET_HANDLER::StaticInitialize(g_fEnableReferenceCountTracing);
+    if (FAILED(hr))
+    {
+        goto Finished;
+    }
+
+Finished:
+
+    if (pFactory != NULL)
+    {
+        pFactory->Terminate();
+        pFactory = NULL;
+    }
+
+    return hr;
+}
+
diff --git a/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/src/path.cxx b/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/src/path.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..cde0dd53122ca45b78bd0b50ebcc5d5a010681b5
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/src/path.cxx
@@ -0,0 +1,442 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#include "precomp.hxx"
+
+// static
+HRESULT
+PATH::SplitUrl(
+    PCWSTR pszDestinationUrl,
+    BOOL *pfSecure,
+    STRU *pstrDestination,
+    STRU *pstrUrl
+)
+/*++
+
+Routine Description:
+
+    Split the URL specified for forwarding into its specific components
+    The format of the URL looks like
+    http[s]://destination[:port]/path
+    when port is omitted, the default port for that specific protocol is used
+    when host is omitted, it gets the same value as the destination
+
+Arguments:
+
+    pszDestinationUrl - the url to be split up
+    pfSecure - SSL to be used in forwarding?
+    pstrDestination - destination
+    pDestinationPort - port
+    pstrUrl - URL
+    
+Return Value:
+
+    HRESULT
+
+--*/
+{
+    HRESULT hr;
+
+    //
+    // First determine if the target is secure
+    //
+    if (_wcsnicmp(pszDestinationUrl, L"http://", 7) == 0)
+    {
+        *pfSecure = FALSE;
+        pszDestinationUrl += 7;
+    }
+    else if (_wcsnicmp(pszDestinationUrl, L"https://", 8) == 0)
+    {
+        *pfSecure = TRUE;
+        pszDestinationUrl += 8;
+    }
+    else
+    {
+        return HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
+    }
+
+    if (*pszDestinationUrl == L'\0')
+    {
+        return HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
+    }
+
+    //
+    // Find the 3rd slash corresponding to the url
+    //
+    LPCWSTR pszSlash = wcschr(pszDestinationUrl, L'/');
+    if (pszSlash == NULL)
+    {
+        if (FAILED(hr = pstrUrl->Copy(L"/", 1)) ||
+            FAILED(hr = pstrDestination->Copy(pszDestinationUrl)))
+        {
+            return hr;
+        }
+    }
+    else
+    {
+        if (FAILED(hr = pstrUrl->Copy(pszSlash)) ||
+            FAILED(hr = pstrDestination->Copy(pszDestinationUrl,
+                            (DWORD)(pszSlash - pszDestinationUrl))))
+        {
+            return hr;
+        }
+    }
+
+    return S_OK;
+}
+
+// Change a hexadecimal digit to its numerical equivalent
+#define TOHEX( ch )                                     \
+    ((ch) > L'9' ?                                      \
+        (ch) >= L'a' ?                                  \
+            (ch) - L'a' + 10 :                          \
+            (ch) - L'A' + 10                            \
+        : (ch) - L'0')
+
+// static
+HRESULT
+PATH::UnEscapeUrl(
+    PCWSTR      pszUrl,
+    DWORD       cchUrl,
+    bool        fCopyQuery,
+    STRA *      pstrResult
+)
+{
+    HRESULT hr;
+    CHAR pch[2];
+    pch[1] = '\0';
+    DWORD cchStart = 0;
+    DWORD index = 0;
+
+    while (index < cchUrl &&
+           (fCopyQuery || pszUrl[index] != L'?'))
+    {
+        switch (pszUrl[index])
+        {
+        case L'%':
+            if (iswxdigit(pszUrl[index+1]) && iswxdigit(pszUrl[index+2]))
+            {
+                if (index > cchStart &&
+                    FAILED(hr = pstrResult->AppendW(pszUrl + cchStart,
+                                                    index - cchStart)))
+                {
+                    return hr;
+                }
+                cchStart = index+3;
+
+                pch[0] = static_cast<CHAR>(TOHEX(pszUrl[index+1]) * 16 +
+                                TOHEX(pszUrl[index+2]));
+                if (FAILED(hr = pstrResult->Append(pch, 1)))
+                {
+                    return hr;
+                }
+                index += 3;
+                break;
+            }
+
+            __fallthrough;
+        default:
+            index++;
+        }
+    }
+
+    if (index > cchStart)
+    {
+        return pstrResult->AppendW(pszUrl + cchStart,
+                                   index - cchStart);
+    }
+
+    return S_OK;
+}
+
+// static
+HRESULT
+PATH::UnEscapeUrl(
+    PCWSTR      pszUrl,
+    DWORD       cchUrl,
+    STRU *      pstrResult
+)
+{
+    HRESULT hr;
+    WCHAR pch[2];
+    pch[1] = L'\0';
+    DWORD cchStart = 0;
+    DWORD index = 0;
+    bool fInQuery = FALSE;
+
+    while (index < cchUrl)
+    {
+        switch (pszUrl[index])
+        {
+        case L'%':
+            if (iswxdigit(pszUrl[index+1]) && iswxdigit(pszUrl[index+2]))
+            {
+                if (index > cchStart &&
+                    FAILED(hr = pstrResult->Append(pszUrl + cchStart,
+                                                   index - cchStart)))
+                {
+                    return hr;
+                }
+                cchStart = index+3;
+
+                pch[0] = static_cast<WCHAR>(TOHEX(pszUrl[index+1]) * 16 +
+                                 TOHEX(pszUrl[index+2]));
+                if (FAILED(hr = pstrResult->Append(pch, 1)))
+                {
+                    return hr;
+                }
+                index += 3;
+                if (pch[0] == L'?')
+                {
+                    fInQuery = TRUE;
+                }
+                break;
+            }
+
+            index++;
+            break;
+
+        case L'/':
+            if (fInQuery)
+            {
+                if (index > cchStart &&
+                    FAILED(hr = pstrResult->Append(pszUrl + cchStart,
+                                                   index - cchStart)))
+                {
+                    return hr;
+                }
+                cchStart = index+1;
+
+                if (FAILED(hr = pstrResult->Append(L"\\", 1)))
+                {
+                    return hr;
+                }
+                index += 1;
+                break;
+            }
+
+            __fallthrough;
+        default:
+            index++;
+        }
+    }
+
+    if (index > cchStart)
+    {
+        return pstrResult->Append(pszUrl + cchStart,
+                                  index - cchStart);
+    }
+
+    return S_OK;
+}
+
+HRESULT
+PATH::EscapeAbsPath(
+    IHttpRequest * pRequest,
+    STRU * strEscapedUrl
+)
+{
+    HRESULT hr = S_OK;
+    STRU    strAbsPath;
+    LPCWSTR pszAbsPath = NULL;
+    LPCWSTR pszFindStr = NULL;
+
+    hr = strAbsPath.Copy( pRequest->GetRawHttpRequest()->CookedUrl.pAbsPath,
+        pRequest->GetRawHttpRequest()->CookedUrl.AbsPathLength / sizeof(WCHAR) );
+    if(FAILED(hr))
+    {
+        goto Finished;
+    }
+
+    pszAbsPath = strAbsPath.QueryStr();
+    pszFindStr = wcschr(pszAbsPath, L'?');
+
+    while(pszFindStr != NULL)
+    {
+        strEscapedUrl->Append( pszAbsPath, pszFindStr - pszAbsPath);
+        strEscapedUrl->Append(L"%3F");
+        pszAbsPath = pszFindStr + 1;
+        pszFindStr = wcschr(pszAbsPath, L'?');
+    }
+
+    strEscapedUrl->Append(pszAbsPath);
+    strEscapedUrl->Append(pRequest->GetRawHttpRequest()->CookedUrl.pQueryString, 
+                          pRequest->GetRawHttpRequest()->CookedUrl.QueryStringLength / sizeof(WCHAR));
+
+Finished:
+    return hr;
+}
+
+// static
+bool
+PATH::IsValidAttributeNameChar(
+    WCHAR ch
+)
+{
+    //
+    // Values based on ASP.NET rendering for cookie names. RFC 2965 is not clear
+    // what the non-special characters are.
+    //
+    return ch == L'\t' || (ch > 31 && ch < 127);
+}
+
+// static
+bool
+PATH::FindInMultiString(
+    PCWSTR      pszMultiString,
+    PCWSTR      pszStringToFind
+)
+{
+    while (*pszMultiString != L'\0')
+    {
+        if (wcscmp(pszMultiString, pszStringToFind) == 0)
+        {
+            return TRUE;
+        }
+        pszMultiString += wcslen(pszMultiString) + 1;
+    }
+
+    return FALSE;
+}
+
+// static
+bool
+PATH::IsValidQueryStringName(
+    PCWSTR  pszName
+)
+{
+    while (*pszName != L'\0')
+    {
+        WCHAR c = *pszName;
+        if (c != L'-' && c != L'_' && c != L'+' &&
+            c != L'.' && c != L'*' && c != L'$' && c != L'%' && c != L',' &&
+            !iswalnum(c))
+        {
+            return FALSE;
+        }
+        pszName++;
+    }
+
+    return TRUE;
+}
+
+// static
+bool
+PATH::IsValidHeaderName(
+    PCWSTR  pszName
+)
+{
+    while (*pszName != L'\0')
+    {
+        WCHAR c = *pszName;
+        if (c != L'-' && c != L'_' && c != L'+' &&
+            c != L'.' && c != L'*' && c != L'$' && c != L'%'
+            && !iswalnum(c))
+        {
+            return FALSE;
+        }
+        pszName++;
+    }
+
+    return TRUE;
+}
+
+HRESULT
+PATH::IsPathUnc(
+    __in  LPCWSTR       pszPath, 
+    __out BOOL *        pfIsUnc 
+)
+{
+    HRESULT hr = S_OK;
+    STRU strTempPath;
+
+    if ( pszPath == NULL || pfIsUnc == NULL )
+    {
+        hr = E_INVALIDARG;
+        goto Finished;
+    }
+
+    hr = MakePathCanonicalizationProof( (LPWSTR) pszPath, &strTempPath );
+    if ( FAILED(hr) )
+    {
+        goto Finished;
+    }
+
+    //
+    // MakePathCanonicalizationProof will map \\?\UNC, \\.\UNC and \\ to \\?\UNC
+    //
+    (*pfIsUnc) = ( _wcsnicmp( strTempPath.QueryStr(), L"\\\\?\\UNC\\", 8 /* sizeof \\?\UNC\ */) == 0 );
+
+Finished:
+
+    return hr;
+}
+
+HRESULT
+PATH::ConvertPathToFullPath(
+    _In_  LPCWSTR   pszPath,
+    _In_  LPCWSTR   pszRootPath,
+    _Out_ STRU*     pStruFullPath
+)
+{
+    HRESULT hr = S_OK;
+    STRU strFileFullPath;
+    LPWSTR pszFullPath = NULL;
+
+    // if relative path, prefix with root path and then convert to absolute path.
+    if( pszPath[0] == L'.' )
+    {
+        hr = strFileFullPath.Copy(pszRootPath);
+        if(FAILED(hr))
+        {
+            goto Finished;
+        }
+
+        if(!strFileFullPath.EndsWith(L"\\"))
+        {
+            hr = strFileFullPath.Append(L"\\");
+            if(FAILED(hr))
+            {
+                goto Finished;
+            }
+        }
+    }
+
+    hr = strFileFullPath.Append( pszPath );
+    if(FAILED(hr))
+    {
+        goto Finished;
+    }
+
+    pszFullPath = new WCHAR[ strFileFullPath.QueryCCH() + 1];
+    if( pszFullPath == NULL )
+    {
+        hr = E_OUTOFMEMORY;
+        goto Finished;
+    }
+
+    if(_wfullpath( pszFullPath,
+                   strFileFullPath.QueryStr(),
+                   strFileFullPath.QueryCCH() + 1 ) == NULL )
+    {
+        hr = HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
+        goto Finished;
+    }
+
+    // convert to canonical path
+    hr = MakePathCanonicalizationProof( pszFullPath, pStruFullPath );
+    if(FAILED(hr))
+    {
+        goto Finished;
+    }
+
+Finished:
+
+    if( pszFullPath != NULL )
+    {
+        delete[] pszFullPath;
+        pszFullPath = NULL;
+    }
+
+    return hr;
+}
\ No newline at end of file
diff --git a/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/src/precomp.hxx b/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/src/precomp.hxx
new file mode 100644
index 0000000000000000000000000000000000000000..0aabd3b5f1d01b74d5ca023bc8318caf172ee6f7
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/src/precomp.hxx
@@ -0,0 +1,156 @@
+// Copyright(c).NET Foundation.All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#pragma once
+#pragma warning( disable : 4091)
+
+//
+// System related headers
+//
+#define _WINSOCKAPI_
+
+#define NTDDI_VERSION 0x06010000
+#define WINVER 0x0601
+#define _WIN32_WINNT 0x0601
+
+#include <windows.h>
+#include <atlbase.h>
+#include <pdh.h>
+
+//#include <ntassert.h>
+#include <Shlobj.h>
+#include <httpserv.h>
+
+// This should remove our issue of compiling for win7 without header files.
+// We  force the Windows 8 version check logic in iiswebsocket.h to succeed even though we're compiling for Windows 7.
+// Then, we set the version defines back to Windows 7 to for the remainder of the compilation.
+#undef NTDDI_VERSION
+#undef WINVER
+#undef _WIN32_WINNT
+#define NTDDI_VERSION 0x06020000
+#define WINVER 0x0602
+#define _WIN32_WINNT 0x0602
+#include <iiswebsocket.h>
+#undef NTDDI_VERSION
+#undef WINVER
+#undef _WIN32_WINNT
+
+#define NTDDI_VERSION 0x06010000
+#define WINVER 0x0601
+#define _WIN32_WINNT 0x0601
+
+#include <httptrace.h>
+#include <winhttp.h>
+
+//
+// Option available starting Windows 8.
+// 111 is the value in SDK on May 15, 2012.
+//
+#ifndef WINHTTP_OPTION_ASSURED_NON_BLOCKING_CALLBACKS
+#define WINHTTP_OPTION_ASSURED_NON_BLOCKING_CALLBACKS 111
+#endif
+
+#define ASPNETCORE_EVENT_PROVIDER L"IIS AspNetCore Module"
+#define ASPNETCORE_IISEXPRESS_EVENT_PROVIDER L"IIS Express AspNetCore Module"
+
+#define TIMESPAN_IN_MILLISECONDS(x)  ((x)/((LONGLONG)(10000)))
+#define TIMESPAN_IN_SECONDS(x)       ((TIMESPAN_IN_MILLISECONDS(x))/((LONGLONG)(1000)))
+#define TIMESPAN_IN_MINUTES(x)       ((TIMESPAN_IN_SECONDS(x))/((LONGLONG)(60)))
+
+#ifdef max
+#undef max
+template<typename T> inline T max(T a, T b)
+{
+    return a > b ? a : b;
+}
+#endif
+
+#ifdef min
+#undef min
+template<typename T> inline T min(T a, T b)
+{
+    return a < b ? a : b;
+}
+#endif
+
+inline bool IsSpace(char ch)
+{
+    switch(ch)
+    {
+    case 32: // ' '
+    case 9:  // '\t'
+    case 10: // '\n'
+    case 13: // '\r'
+    case 11: // '\v'
+    case 12: // '\f'
+        return true;
+    default:
+        return false;
+    }
+}
+
+#include <hashfn.h>
+#include <hashtable.h>
+#include <stringa.h>
+#include <stringu.h>
+#include <treehash.h>
+
+#include <dbgutil.h>
+#include "ahutil.h"
+#include "multisz.h"
+#include "multisza.h"
+#include "sttimer.h"
+#include <listentry.h>
+#include <base64.h>
+#include <datetime.h>
+#include <reftrace.h>
+#include <acache.h>
+#include <time.h>
+
+#include "filewatcher.h"
+#include "environmentvariablehash.h"
+#include "..\aspnetcore_msg.h"
+#include "aspnetcoreconfig.h"
+#include "serverprocess.h"
+#include "processmanager.h"
+#include "application.h"
+#include "applicationmanager.h"
+#include "resource.h"
+#include "path.h"
+#include "debugutil.h"
+#include "protocolconfig.h"
+#include "responseheaderhash.h"
+#include "forwarderconnection.h"
+#include "winhttphelper.h"
+#include "websockethandler.h"
+#include "forwardinghandler.h"
+#include "proxymodule.h"
+
+FORCEINLINE
+DWORD
+WIN32_FROM_HRESULT(
+    HRESULT hr
+)
+{
+    if ((FAILED(hr)) &&
+        (HRESULT_FACILITY(hr) == FACILITY_WIN32))
+    {
+        return HRESULT_CODE(hr);
+    }
+    return hr;
+}
+
+FORCEINLINE
+HRESULT
+HRESULT_FROM_GETLASTERROR()
+{
+    return  ( GetLastError() != NO_ERROR ) 
+           ? HRESULT_FROM_WIN32( GetLastError() )
+           : E_FAIL;
+}
+
+extern BOOL     g_fAsyncDisconnectAvailable;
+extern PVOID    g_pModuleId;
+extern BOOL     g_fWebSocketSupported;
+extern BOOL     g_fEnableReferenceCountTracing;
+extern DWORD    g_dwActiveServerProcesses;
diff --git a/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/src/processmanager.cxx b/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/src/processmanager.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..5029a52670e0e11147498cfa89dc1731f734b1f2
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/src/processmanager.cxx
@@ -0,0 +1,294 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#include "precomp.hxx"
+
+volatile BOOL               PROCESS_MANAGER::sm_fWSAStartupDone = FALSE;
+
+HRESULT
+PROCESS_MANAGER::Initialize(
+    VOID
+)
+{
+    HRESULT                              hr       = S_OK;
+    WSADATA                              wsaData;
+    int                                  result;
+    BOOL                                 fLocked = FALSE;
+
+    if( !sm_fWSAStartupDone )
+    {
+        AcquireSRWLockExclusive( &m_srwLock );
+        fLocked = TRUE;
+
+        if( !sm_fWSAStartupDone )
+        {
+            if( (result = WSAStartup(MAKEWORD(2, 2), &wsaData)) != 0 )
+            {
+                hr = HRESULT_FROM_WIN32( result );
+                goto Finished;
+            }
+            sm_fWSAStartupDone = TRUE;
+        }
+
+        ReleaseSRWLockExclusive( &m_srwLock );
+        fLocked = FALSE;
+    }
+
+    m_dwRapidFailTickStart = GetTickCount();
+
+    if( m_hNULHandle == NULL )
+    {
+        SECURITY_ATTRIBUTES saAttr;
+        saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
+        saAttr.bInheritHandle = TRUE; 
+        saAttr.lpSecurityDescriptor = NULL;
+
+        m_hNULHandle = CreateFileW( L"NUL",
+                                    FILE_WRITE_DATA,
+                                    FILE_SHARE_READ,
+                                    &saAttr,
+                                    CREATE_ALWAYS,
+                                    FILE_ATTRIBUTE_NORMAL,
+                                    NULL );
+        if( m_hNULHandle == INVALID_HANDLE_VALUE )
+        {
+            hr = HRESULT_FROM_GETLASTERROR();
+            goto Finished;
+        }
+    }
+
+Finished:
+
+    if(fLocked)
+    {
+        ReleaseSRWLockExclusive( &m_srwLock );
+    }
+
+    return hr;
+}
+
+PROCESS_MANAGER::~PROCESS_MANAGER()
+{
+    AcquireSRWLockExclusive(&m_srwLock);
+
+    if( m_ppServerProcessList != NULL )
+    {
+        for( DWORD i = 0; i < m_dwProcessesPerApplication; ++i )
+        {
+            if( m_ppServerProcessList[i] != NULL )
+            {
+                m_ppServerProcessList[i]->DereferenceServerProcess();
+                m_ppServerProcessList[i] = NULL;
+            }
+        }
+
+        delete[] m_ppServerProcessList;
+        m_ppServerProcessList = NULL;
+    }
+
+    if( m_hNULHandle != NULL )
+    {
+        CloseHandle( m_hNULHandle );
+        m_hNULHandle = NULL;
+    }
+
+    if( sm_fWSAStartupDone )
+    {
+        WSACleanup();
+        sm_fWSAStartupDone = FALSE;
+    }
+
+    ReleaseSRWLockExclusive(&m_srwLock);
+}
+
+HRESULT 
+PROCESS_MANAGER::GetProcess(
+    _In_    IHttpContext           *context,
+    _In_    ASPNETCORE_CONFIG      *pConfig,
+    _Out_   SERVER_PROCESS        **ppServerProcess
+)
+{
+    HRESULT          hr = S_OK;
+    BOOL             fSharedLock = FALSE;
+    BOOL             fExclusiveLock = FALSE;
+    PCWSTR           apsz[1];
+    STACK_STRU(      strEventMsg, 256 );
+    DWORD            dwProcessIndex = 0;
+    SERVER_PROCESS **ppSelectedServerProcess = NULL;
+
+    if (!m_fServerProcessListReady)
+    {
+        AcquireSRWLockExclusive( &m_srwLock );
+        fExclusiveLock  = TRUE;
+
+        if (!m_fServerProcessListReady)
+        {
+            m_dwProcessesPerApplication = pConfig->QueryProcessesPerApplication();
+            m_ppServerProcessList = new SERVER_PROCESS*[m_dwProcessesPerApplication];
+            if(m_ppServerProcessList == NULL)
+            {
+                hr = E_OUTOFMEMORY;
+                goto Finished;
+            }
+
+            for(DWORD i=0;i<m_dwProcessesPerApplication;++i)
+            {
+                m_ppServerProcessList[i] = NULL;
+            }
+        }
+        m_fServerProcessListReady = TRUE;
+        ReleaseSRWLockExclusive( &m_srwLock );
+        fExclusiveLock = FALSE;
+    }
+
+    AcquireSRWLockShared( &m_srwLock );
+    fSharedLock = TRUE;
+
+    //
+    // round robin through to the next available process.
+    //
+
+    dwProcessIndex = (DWORD) InterlockedIncrement64( (LONGLONG*) &m_dwRouteToProcessIndex );
+    dwProcessIndex = dwProcessIndex % m_dwProcessesPerApplication;
+    ppSelectedServerProcess = &m_ppServerProcessList[dwProcessIndex];
+
+    if( *ppSelectedServerProcess != NULL && 
+        m_ppServerProcessList[dwProcessIndex]->IsReady() )
+    {
+        m_ppServerProcessList[dwProcessIndex]->ReferenceServerProcess();
+        *ppServerProcess = m_ppServerProcessList[dwProcessIndex];
+        goto Finished;
+    }
+
+    ReleaseSRWLockShared( &m_srwLock );
+    fSharedLock = FALSE;
+    // should make the lock per process so that we can start processes simultaneously ?
+
+    if(m_ppServerProcessList[dwProcessIndex] == NULL || !m_ppServerProcessList[dwProcessIndex]->IsReady())
+    {
+        AcquireSRWLockExclusive( &m_srwLock );
+        fExclusiveLock  = TRUE;
+
+        if( m_ppServerProcessList[dwProcessIndex] != NULL )
+        {
+            if( !m_ppServerProcessList[dwProcessIndex]->IsReady() )
+            {
+                //
+                // terminate existing process that is not ready
+                // before creating new one.
+                //
+
+                ShutdownProcessNoLock( m_ppServerProcessList[dwProcessIndex] );
+            }
+            else
+            {
+                // server is already up and ready to serve requests.
+                m_ppServerProcessList[dwProcessIndex]->ReferenceServerProcess();
+                *ppServerProcess = m_ppServerProcessList[dwProcessIndex];
+                goto Finished;
+            }
+        }
+
+        if( RapidFailsPerMinuteExceeded(pConfig->QueryRapidFailsPerMinute()) )
+        {
+            //
+            // rapid fails per minute exceeded, do not create new process.
+            //
+
+            if( SUCCEEDED( strEventMsg.SafeSnwprintf(
+                ASPNETCORE_EVENT_RAPID_FAIL_COUNT_EXCEEDED_MSG,
+                pConfig->QueryRapidFailsPerMinute() ) ) )
+            {
+                apsz[0] = strEventMsg.QueryStr();
+
+                //
+                // not checking return code because if ReportEvent
+                // fails, we cannot do anything.
+                //
+                if (FORWARDING_HANDLER::QueryEventLog() != NULL)
+                {
+                    ReportEventW(FORWARDING_HANDLER::QueryEventLog(),
+                        EVENTLOG_INFORMATION_TYPE,
+                        0,
+                        ASPNETCORE_EVENT_RAPID_FAIL_COUNT_EXCEEDED,
+                        NULL,
+                        1,
+                        0,
+                        apsz,
+                        NULL);
+                }
+            }
+
+            hr = HRESULT_FROM_WIN32(ERROR_SERVER_DISABLED);
+            goto Finished;
+        }
+
+        if( m_ppServerProcessList[dwProcessIndex] == NULL )
+        {
+            m_ppServerProcessList[dwProcessIndex] = new SERVER_PROCESS();
+            if( m_ppServerProcessList[dwProcessIndex] == NULL )
+            {
+                hr = E_OUTOFMEMORY;
+                goto Finished;
+            }
+
+            hr = m_ppServerProcessList[dwProcessIndex]->Initialize(
+                                    this,
+                                    pConfig->QueryProcessPath(),
+                                    pConfig->QueryArguments(),
+                                    pConfig->QueryStartupTimeLimitInMS(),
+                                    pConfig->QueryShutdownTimeLimitInMS(),
+                                    pConfig->QueryWindowsAuthEnabled(),
+                                    pConfig->QueryBasicAuthEnabled(),
+                                    pConfig->QueryAnonymousAuthEnabled(),
+                                    pConfig->QueryEnvironmentVariables(),
+                                    pConfig->QueryStdoutLogEnabled(),
+                                    pConfig->QueryStdoutLogFile()
+                                    );
+            if( FAILED( hr ) )
+            {
+                goto Finished;
+            }
+
+            hr = m_ppServerProcessList[dwProcessIndex]->StartProcess(context);
+            if( FAILED( hr ) )
+            {
+                goto Finished;
+            }
+        }
+
+        if( !m_ppServerProcessList[dwProcessIndex]->IsReady() )
+        { 
+            hr = HRESULT_FROM_WIN32( ERROR_CREATE_FAILED );
+            goto Finished;
+        }
+
+        m_ppServerProcessList[dwProcessIndex]->ReferenceServerProcess();
+        *ppServerProcess = m_ppServerProcessList[dwProcessIndex];
+    }
+
+Finished:
+
+    if( FAILED(hr) )
+    {
+        if(m_ppServerProcessList[dwProcessIndex] != NULL )
+        {
+            m_ppServerProcessList[dwProcessIndex]->DereferenceServerProcess();
+            m_ppServerProcessList[dwProcessIndex] = NULL;
+        }
+    }
+
+    if( fSharedLock )
+    {
+        ReleaseSRWLockShared( &m_srwLock );
+        fSharedLock = FALSE;
+    }
+
+    if( fExclusiveLock )
+    {
+        ReleaseSRWLockExclusive( &m_srwLock );
+        fExclusiveLock = FALSE;
+    }
+
+    return hr;
+}
\ No newline at end of file
diff --git a/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/src/protocolconfig.cxx b/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/src/protocolconfig.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..83e26489258e378635595ba366bbb40b45daf5f8
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/src/protocolconfig.cxx
@@ -0,0 +1,48 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#include "precomp.hxx"
+
+HRESULT
+PROTOCOL_CONFIG::Initialize()
+{
+    HRESULT hr;
+    STRU strTemp;
+
+    m_fKeepAlive = TRUE;
+    m_msTimeout = 120000;
+    m_fPreserveHostHeader = TRUE;
+    m_fReverseRewriteHeaders = FALSE;
+
+    if (FAILED(hr = m_strXForwardedForName.CopyW(L"X-Forwarded-For")))
+    {
+        goto Finished;
+    }
+
+    if (FAILED(hr = m_strSslHeaderName.CopyW(L"X-Forwarded-Proto")))
+    {
+        goto Finished;
+    }
+
+    if (FAILED(hr = m_strClientCertName.CopyW(L"MS-ASPNETCORE-CLIENTCERT")))
+    {
+        goto Finished;
+    }
+
+    m_fIncludePortInXForwardedFor = TRUE;
+    m_dwMinResponseBuffer = 0; // no response buffering
+    m_dwResponseBufferLimit = 4096*1024;
+    m_dwMaxResponseHeaderSize = 65536;
+
+Finished:
+
+    return hr;
+}
+
+VOID
+PROTOCOL_CONFIG::OverrideConfig(
+    ASPNETCORE_CONFIG *pAspNetCoreConfig
+)
+{
+    m_msTimeout = pAspNetCoreConfig->QueryRequestTimeoutInMS();
+}
\ No newline at end of file
diff --git a/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/src/proxymodule.cxx b/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/src/proxymodule.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..4a4e8fb6bd9bde3759df0f9cb3c7e429362ee9fa
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/src/proxymodule.cxx
@@ -0,0 +1,114 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#include "precomp.hxx"
+
+
+__override
+HRESULT
+CProxyModuleFactory::GetHttpModule(
+    CHttpModule **      ppModule,
+    IModuleAllocator *  pAllocator
+)
+{
+    CProxyModule *pModule = new (pAllocator) CProxyModule();
+    if (pModule == NULL)
+    {
+        return E_OUTOFMEMORY;
+    }
+
+    *ppModule = pModule;
+    return S_OK;
+}
+
+__override
+VOID
+CProxyModuleFactory::Terminate(
+    VOID
+)
+/*++
+
+Routine description:
+
+Function called by IIS for global (non-request-specific) notifications
+
+Arguments:
+
+None.
+
+Return value:
+
+None
+
+--*/
+{
+    FORWARDING_HANDLER::StaticTerminate();
+
+    WEBSOCKET_HANDLER::StaticTerminate();
+
+    if (g_pResponseHeaderHash != NULL)
+    {
+        g_pResponseHeaderHash->Clear();
+        delete g_pResponseHeaderHash;
+        g_pResponseHeaderHash = NULL;
+    }
+
+    ALLOC_CACHE_HANDLER::StaticTerminate();
+
+    delete this;
+}
+
+CProxyModule::CProxyModule(
+) : m_pHandler(NULL)
+{
+}
+
+CProxyModule::~CProxyModule()
+{
+    if (m_pHandler != NULL)
+    {
+        //
+        // This will be called when the main notification is cleaned up
+        // i.e., the request is done with IIS pipeline
+        //
+        m_pHandler->DereferenceForwardingHandler();
+        m_pHandler = NULL;
+    }
+}
+
+__override
+REQUEST_NOTIFICATION_STATUS
+CProxyModule::OnExecuteRequestHandler(
+    IHttpContext *          pHttpContext,
+    IHttpEventProvider *
+)
+{
+    m_pHandler = new FORWARDING_HANDLER(pHttpContext);
+    if (m_pHandler == NULL)
+    {
+        pHttpContext->GetResponse()->SetStatus(500, "Internal Server Error", 0, E_OUTOFMEMORY);
+        return RQ_NOTIFICATION_FINISH_REQUEST;
+    }
+
+    return m_pHandler->OnExecuteRequestHandler();
+}
+
+__override
+REQUEST_NOTIFICATION_STATUS
+CProxyModule::OnAsyncCompletion(
+    IHttpContext *,
+    DWORD                   dwNotification,
+    BOOL                    fPostNotification,
+    IHttpEventProvider *,
+    IHttpCompletionInfo *   pCompletionInfo
+)
+{
+    UNREFERENCED_PARAMETER(dwNotification);
+    UNREFERENCED_PARAMETER(fPostNotification);
+    DBG_ASSERT(dwNotification == RQ_EXECUTE_REQUEST_HANDLER);
+    DBG_ASSERT(fPostNotification == FALSE);
+
+    return m_pHandler->OnAsyncCompletion(
+        pCompletionInfo->GetCompletionBytes(),
+        pCompletionInfo->GetCompletionStatus());
+}
\ No newline at end of file
diff --git a/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/src/responseheaderhash.cxx b/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/src/responseheaderhash.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..161095042cf8406d3c285add2c5be87bb10f83ed
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/src/responseheaderhash.cxx
@@ -0,0 +1,100 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#include "precomp.hxx"
+
+RESPONSE_HEADER_HASH *  g_pResponseHeaderHash = NULL;
+
+HEADER_RECORD RESPONSE_HEADER_HASH::sm_rgHeaders[] = 
+{
+    { "Cache-Control",       HttpHeaderCacheControl       },
+    { "Connection",          HttpHeaderConnection         },
+    { "Date",                HttpHeaderDate               },
+    { "Keep-Alive",          HttpHeaderKeepAlive          },
+    { "Pragma",              HttpHeaderPragma             },
+    { "Trailer",             HttpHeaderTrailer            },
+    { "Transfer-Encoding",   HttpHeaderTransferEncoding   },
+    { "Upgrade",             HttpHeaderUpgrade            },
+    { "Via",                 HttpHeaderVia                },
+    { "Warning",             HttpHeaderWarning            },
+    { "Allow",               HttpHeaderAllow              },
+    { "Content-Length",      HttpHeaderContentLength      },
+    { "Content-Type",        HttpHeaderContentType        },
+    { "Content-Encoding",    HttpHeaderContentEncoding    },
+    { "Content-Language",    HttpHeaderContentLanguage    },
+    { "Content-Location",    HttpHeaderContentLocation    },
+    { "Content-MD5",         HttpHeaderContentMd5         },
+    { "Content-Range",       HttpHeaderContentRange       },
+    { "Expires",             HttpHeaderExpires            },
+    { "Last-Modified",       HttpHeaderLastModified       },
+    { "Accept-Ranges",       HttpHeaderAcceptRanges       },
+    { "Age",                 HttpHeaderAge                },
+    { "ETag",                HttpHeaderEtag               },
+    { "Location",            HttpHeaderLocation           },
+    { "Proxy-Authenticate",  HttpHeaderProxyAuthenticate  },
+    { "Retry-After",         HttpHeaderRetryAfter         },
+    { "Server",              HttpHeaderServer             },
+    // Set it to something which cannot be a header name, in effect
+    // making Server an unknown header. w:w is used to avoid collision with Keep-Alive.
+    { "w:w\r\n",             HttpHeaderServer             },
+    // Set it to something which cannot be a header name, in effect
+    // making Set-Cookie an unknown header
+    { "y:y\r\n",             HttpHeaderSetCookie          },
+    { "Vary",                HttpHeaderVary               },
+    // Set it to something which cannot be a header name, in effect
+    // making WWW-Authenticate an unknown header
+    { "z:z\r\n",             HttpHeaderWwwAuthenticate    }
+
+};
+
+HRESULT
+RESPONSE_HEADER_HASH::Initialize(
+    VOID
+)
+/*++
+
+Routine Description:
+
+    Initialize global header hash table
+
+Arguments:
+
+    None
+
+Return Value:
+
+    HRESULT
+
+--*/
+{
+    HRESULT hr;
+
+    //
+    // 31 response headers.
+    // Make sure to update the number of buckets it new headers
+    // are added. Test it to avoid collisions.
+    //
+    C_ASSERT(_countof(sm_rgHeaders) == 31);
+
+    //
+    // 79 buckets will have less collisions for the 31 response headers.
+    // Known collisions are "Age" colliding with "Expire" and "Location"
+    // colliding with both "Expire" and "Age".
+    //
+    hr = HASH_TABLE::Initialize(79);
+    if (FAILED(hr))
+    {
+        return hr;
+    }
+
+    for ( DWORD Index = 0; Index < _countof(sm_rgHeaders); ++Index )
+    {
+        if (FAILED(hr = InsertRecord(&sm_rgHeaders[Index])))
+        {
+            return hr;
+        }
+    }
+    
+    return S_OK;
+}
+
diff --git a/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/src/serverprocess.cxx b/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/src/serverprocess.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..be5e250df5532ad442acc890967d746706018677
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/src/serverprocess.cxx
@@ -0,0 +1,2351 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#include "precomp.hxx"
+#include <IPHlpApi.h>
+#include <share.h>
+
+extern BOOL g_fNsiApiNotSupported;
+
+#define STARTUP_TIME_LIMIT_INCREMENT_IN_MILLISECONDS 5000
+
+HRESULT
+SERVER_PROCESS::Initialize(
+    PROCESS_MANAGER      *pProcessManager,
+    STRU                 *pszProcessExePath,
+    STRU                 *pszArguments,
+    DWORD                 dwStartupTimeLimitInMS,
+    DWORD                 dwShtudownTimeLimitInMS,
+    BOOL                  fWindowsAuthEnabled,
+    BOOL                  fBasicAuthEnabled,
+    BOOL                  fAnonymousAuthEnabled,
+    ENVIRONMENT_VAR_HASH *pEnvironmentVariables,
+    BOOL                  fStdoutLogEnabled,
+    STRU                  *pstruStdoutLogFile
+)
+{
+    HRESULT                                 hr = S_OK;
+    JOBOBJECT_EXTENDED_LIMIT_INFORMATION    jobInfo = { 0 };
+
+    m_pProcessManager = pProcessManager;
+    m_dwStartupTimeLimitInMS = dwStartupTimeLimitInMS;
+    m_dwShutdownTimeLimitInMS = dwShtudownTimeLimitInMS;
+    m_fStdoutLogEnabled = fStdoutLogEnabled;
+    m_fWindowsAuthEnabled = fWindowsAuthEnabled;
+    m_fBasicAuthEnabled = fBasicAuthEnabled;
+    m_fAnonymousAuthEnabled = fAnonymousAuthEnabled;
+    m_pProcessManager->ReferenceProcessManager();
+
+    if (FAILED (hr = m_ProcessPath.Copy(*pszProcessExePath)) ||
+        FAILED (hr = m_struLogFile.Copy(*pstruStdoutLogFile))||
+        FAILED (hr = m_Arguments.Copy(*pszArguments)))
+    {
+        goto Finished;
+    }
+
+    if (m_hJobObject == NULL)
+    {
+        m_hJobObject = CreateJobObject(NULL,   // LPSECURITY_ATTRIBUTES
+            NULL); // LPCTSTR lpName
+#pragma warning( disable : 4312)
+		// 0xdeadbeef is used by Antares
+        if (m_hJobObject == NULL || m_hJobObject == (HANDLE)0xdeadbeef)
+        {
+            m_hJobObject = NULL;
+            // ignore job object creation error.
+        }
+#pragma warning( error : 4312) 
+        if (m_hJobObject != NULL)
+        {
+            jobInfo.BasicLimitInformation.LimitFlags =
+                JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
+
+            if (!SetInformationJobObject(m_hJobObject,
+                JobObjectExtendedLimitInformation,
+                &jobInfo,
+                sizeof jobInfo))
+            {
+                hr = HRESULT_FROM_WIN32(GetLastError());
+                goto Finished;
+            }
+        }
+
+        m_pEnvironmentVarTable = pEnvironmentVariables;
+    }
+
+Finished:
+    return hr;
+}
+
+HRESULT
+SERVER_PROCESS::GetRandomPort
+(
+    DWORD* pdwPickedPort,
+    DWORD  dwExcludedPort = 0
+)
+{
+    HRESULT hr = S_OK;
+    BOOL    fPortInUse = FALSE;
+    DWORD   dwActualProcessId = 0;
+
+    std::uniform_int_distribution<> dist(MIN_PORT, MAX_PORT);
+
+    if (g_fNsiApiNotSupported)
+    {
+        //
+        // the default value for optional parameter dwExcludedPort is 0 which is reserved
+        // a random number between MIN_PORT and MAX_PORT
+        //
+        while ((*pdwPickedPort = dist(m_randomGenerator)) == dwExcludedPort);
+    }
+    else
+    {
+        DWORD cRetry = 0;
+        do
+        {
+            //
+            // ignore dwActualProcessId because here we are 
+            // determing whether the randomly generated port is
+            // in use by any other process.
+            //
+            while ((*pdwPickedPort = dist(m_randomGenerator)) == dwExcludedPort);
+            hr = CheckIfServerIsUp(*pdwPickedPort, &dwActualProcessId, &fPortInUse);
+        } while (fPortInUse && ++cRetry < MAX_RETRY);
+
+        if (cRetry >= MAX_RETRY)
+        {
+            hr = HRESULT_FROM_WIN32(ERROR_PORT_NOT_SET);
+        }
+    }
+
+    return hr;
+}
+
+HRESULT
+SERVER_PROCESS::SetupListenPort(
+    ENVIRONMENT_VAR_HASH    *pEnvironmentVarTable
+)
+{
+    HRESULT hr = S_OK;
+    ENVIRONMENT_VAR_ENTRY *pEntry = NULL;
+    pEnvironmentVarTable->FindKey(ASPNETCORE_PORT_ENV_STR, &pEntry);
+    if (pEntry != NULL)
+    {
+        if (pEntry->QueryValue() != NULL || pEntry->QueryValue()[0] != L'\0')
+        {
+            m_dwPort = (DWORD)_wtoi(pEntry->QueryValue());
+            if(m_dwPort >MAX_PORT || m_dwPort < MIN_PORT)
+            {
+                hr = E_INVALIDARG;
+                goto Finished;
+                // need add log for this one
+            }
+            hr = m_struPort.Copy(pEntry->QueryValue());
+            goto Finished;
+        }
+        else
+        {
+            //
+            // user set the env variable but did not give value, let's set it up
+            // 
+            pEnvironmentVarTable->DeleteKey(ASPNETCORE_PORT_ENV_STR);
+        }
+    }
+
+    WCHAR buffer[15];
+    if (FAILED(hr = GetRandomPort(&m_dwPort)))
+    {
+        goto Finished;
+    }
+
+    if (swprintf_s(buffer, 15, L"%d", m_dwPort) <= 0)
+    {
+        hr = E_INVALIDARG;
+        goto Finished;
+    }
+
+    pEntry = new ENVIRONMENT_VAR_ENTRY();
+    if (pEntry == NULL)
+    {
+        hr = E_OUTOFMEMORY;
+        goto Finished;
+    }
+
+    if (FAILED(hr = pEntry->Initialize(ASPNETCORE_PORT_ENV_STR, buffer)) || 
+        FAILED(hr = pEnvironmentVarTable->InsertRecord(pEntry)) ||
+        FAILED(hr = m_struPort.Copy(buffer)))
+    {
+        goto Finished;
+    }
+
+Finished:
+    if (pEntry != NULL)
+    {
+        pEntry->Dereference();
+        pEntry = NULL;
+    }
+    return hr;
+}
+
+HRESULT
+SERVER_PROCESS::SetupAppPath(
+    IHttpContext*            pContext,
+    ENVIRONMENT_VAR_HASH*    pEnvironmentVarTable
+)
+{
+    HRESULT      hr = S_OK;
+    DWORD        dwCounter = 0;
+    DWORD        dwPosition = 0;
+    WCHAR*       pszPath = NULL;
+    ENVIRONMENT_VAR_ENTRY*  pEntry = NULL;
+
+    pEnvironmentVarTable->FindKey(ASPNETCORE_APP_PATH_ENV_STR, &pEntry);
+    if (pEntry != NULL)
+    {
+        // user should not set this environment variable in configuration
+        pEnvironmentVarTable->DeleteKey(ASPNETCORE_APP_PATH_ENV_STR);
+        pEntry->Dereference();
+        pEntry = NULL;
+    }
+
+    if (m_struAppPath.IsEmpty())
+    {
+        if (FAILED(hr = m_pszRootApplicationPath.Copy(pContext->GetApplication()->GetApplicationPhysicalPath())) ||
+            FAILED(hr = m_struAppFullPath.Copy(pContext->GetApplication()->GetAppConfigPath())))
+        {
+            goto Finished;
+        }
+    }
+
+    // let's find the app path. IIS does not support nested sites
+    // we can seek for the fourth '/' if it exits
+    // MACHINE/WEBROOT/APPHOST/<site>/<app>. 
+    pszPath = m_struAppFullPath.QueryStr();
+    while (pszPath[dwPosition] != NULL)
+    {
+        if (pszPath[dwPosition] == '/')
+        {
+            dwCounter++;
+            if (dwCounter == 4)
+                break;
+        }
+        dwPosition++;
+    }
+
+    if (dwCounter == 4)
+    {
+        hr = m_struAppPath.Copy(pszPath + dwPosition);
+    }
+    else
+    {
+        hr = m_struAppPath.Copy(L"/");
+    }
+
+    if (FAILED(hr))
+    {
+        goto Finished;
+    }
+
+    pEntry = new ENVIRONMENT_VAR_ENTRY();
+    if (pEntry == NULL)
+    {
+        hr = E_OUTOFMEMORY;
+        goto Finished;
+    }
+    if (FAILED (hr = pEntry->Initialize(ASPNETCORE_APP_PATH_ENV_STR, m_struAppPath.QueryStr())) ||
+        FAILED (hr = pEnvironmentVarTable->InsertRecord(pEntry)))
+    {
+        goto Finished;
+    }
+
+Finished:
+    if (pEntry!= NULL)
+    {
+        pEntry->Dereference();
+        pEntry = NULL;
+    }
+    return hr;
+}
+
+HRESULT
+SERVER_PROCESS::SetupAppToken(
+    ENVIRONMENT_VAR_HASH    *pEnvironmentVarTable
+)
+{
+    HRESULT     hr = S_OK;
+    UUID        logUuid;
+    PSTR        pszLogUuid = NULL;
+    BOOL        fRpcStringAllocd = FALSE;
+    RPC_STATUS  rpcStatus;
+    STRU        strAppToken;
+    ENVIRONMENT_VAR_ENTRY*  pEntry = NULL;
+
+    pEnvironmentVarTable->FindKey(ASPNETCORE_APP_TOKEN_ENV_STR, &pEntry);
+    if (pEntry != NULL)
+    {
+        // user sets the environment variable
+        m_straGuid.Reset();
+        hr = m_straGuid.CopyW(pEntry->QueryValue());
+        pEntry->Dereference();
+        pEntry = NULL;
+        goto Finished;
+    }
+    else
+    {
+        if (m_straGuid.IsEmpty())
+        {
+            // the GUID has not been set yet
+            rpcStatus = UuidCreate(&logUuid);
+            if (rpcStatus != RPC_S_OK)
+            {
+                hr = rpcStatus;
+                goto Finished;
+            }
+
+            rpcStatus = UuidToStringA(&logUuid, (BYTE **)&pszLogUuid);
+            if (rpcStatus != RPC_S_OK)
+            {
+                hr = rpcStatus;
+                goto Finished;
+            }
+
+            fRpcStringAllocd = TRUE;
+
+            if (FAILED (hr = m_straGuid.Copy(pszLogUuid)))
+            {
+                goto Finished;
+            }
+        }
+
+        pEntry = new ENVIRONMENT_VAR_ENTRY();
+        if (pEntry == NULL)
+        {
+            hr = E_OUTOFMEMORY;
+            goto Finished;
+        }
+
+        if (FAILED(strAppToken.CopyA(m_straGuid.QueryStr())) ||
+            FAILED(hr = pEntry->Initialize(ASPNETCORE_APP_TOKEN_ENV_STR, strAppToken.QueryStr())) ||
+            FAILED(hr = pEnvironmentVarTable->InsertRecord(pEntry)))
+        {
+            goto Finished;
+        }
+    }
+
+Finished:
+
+    if (fRpcStringAllocd)
+    {
+        RpcStringFreeA((BYTE **)&pszLogUuid);
+        pszLogUuid = NULL;
+    }
+    if (pEntry != NULL)
+    {
+        pEntry->Dereference();
+        pEntry = NULL;
+    }
+    return hr;
+}
+
+
+HRESULT
+SERVER_PROCESS::InitEnvironmentVariablesTable(
+    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 
+    m_pEnvironmentVarTable->Apply(ENVIRONMENT_VAR_HASH::CopyToTable, pEnvironmentVarTable);
+    if (pEnvironmentVarTable->Count() != m_pEnvironmentVarTable->Count())
+    {
+        // hash table copy failed
+        hr = E_UNEXPECTED;
+        goto Finished;
+    }
+
+    pEnvironmentVarTable->FindKey(ASPNETCORE_IIS_AUTH_ENV_STR, &pIISAuthEntry);
+    if (pIISAuthEntry != NULL)
+    {
+        // user defined ASPNETCORE_IIS_HTTPAUTH in configuration, wipe it off
+        pIISAuthEntry->Dereference();
+        pEnvironmentVarTable->DeleteKey(ASPNETCORE_IIS_AUTH_ENV_STR);
+    }
+
+    if (m_fWindowsAuthEnabled)
+    {
+        strIisAuthEnvValue.Copy(ASPNETCORE_IIS_AUTH_WINDOWS);
+    }
+
+    if (m_fBasicAuthEnabled)
+    {
+        strIisAuthEnvValue.Append(ASPNETCORE_IIS_AUTH_BASIC);
+    }
+
+    if (m_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;
+    }
+
+
+    pEnvironmentVarTable->FindKey(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;
+}
+
+HRESULT
+SERVER_PROCESS::OutputEnvironmentVariables
+(
+    MULTISZ*                pmszOutput,
+    ENVIRONMENT_VAR_HASH*   pEnvironmentVarTable
+)
+{
+    HRESULT    hr = S_OK;
+    LPWSTR     pszEnvironmentVariables = NULL;
+    LPWSTR     pszCurrentVariable = NULL;
+    LPWSTR     pszNextVariable = NULL;
+    LPWSTR     pszEqualChar = NULL;
+    STRU       strEnvVar;
+    ENVIRONMENT_VAR_ENTRY* pEntry = NULL;
+
+    DBG_ASSERT(pmszOutput);
+    DBG_ASSERT(pEnvironmentVarTable); // We added some startup variables 
+    DBG_ASSERT(pEnvironmentVarTable->Count() >0);
+
+    pszEnvironmentVariables = GetEnvironmentStringsW();
+    if (pszEnvironmentVariables == NULL)
+    {
+        hr = HRESULT_FROM_WIN32(ERROR_INVALID_ENVIRONMENT);
+        goto Finished;
+    }
+    pszCurrentVariable = pszEnvironmentVariables;
+    while (*pszCurrentVariable != L'\0')
+    {
+        pszNextVariable = pszCurrentVariable + wcslen(pszCurrentVariable) + 1;
+        pszEqualChar = wcschr(pszCurrentVariable, L'=');
+        if (pszEqualChar != NULL)
+        {
+            if (FAILED(hr = strEnvVar.Copy(pszCurrentVariable, (DWORD)(pszEqualChar - pszCurrentVariable) + 1)))
+            {
+                goto Finished;
+            }
+            pEnvironmentVarTable->FindKey(strEnvVar.QueryStr(), &pEntry);
+            if (pEntry != NULL)
+            {
+                // same env variable is defined in configuration, use it
+                if (FAILED(hr = strEnvVar.Append(pEntry->QueryValue())))
+                {
+                    goto Finished;
+                }
+                pmszOutput->Append(strEnvVar);  //should we check the returned bool
+                // remove the record from hash table as we already output it
+                pEntry->Dereference();
+                pEnvironmentVarTable->DeleteKey(pEntry->QueryName());
+                strEnvVar.Reset();
+                pEntry = NULL;
+            }
+            else
+            {
+                pmszOutput->Append(pszCurrentVariable);
+            }
+        }
+        else
+        {
+            // env varaible is not well formated
+            hr = HRESULT_FROM_WIN32(ERROR_INVALID_ENVIRONMENT);
+            goto Finished;
+        }
+        // move to next env variable
+        pszCurrentVariable = pszNextVariable;
+    }
+    // append the remaining env variable in hash table
+    pEnvironmentVarTable->Apply(ENVIRONMENT_VAR_HASH::CopyToMultiSz, pmszOutput);
+
+Finished: 
+    if (pszEnvironmentVariables != NULL)
+    {
+        FreeEnvironmentStringsW(pszEnvironmentVariables);
+        pszEnvironmentVariables = NULL;
+    }
+    return hr;
+}
+
+HRESULT
+SERVER_PROCESS::SetupCommandLine(
+    STRU*      pstrCommandLine
+)
+{
+    HRESULT    hr = S_OK;
+    LPWSTR     pszPath = NULL;
+    LPWSTR     pszFullPath = NULL;
+    STRU       strRelativePath;
+    DWORD      dwBufferSize = 0;
+    FILE       *file = NULL;
+
+    DBG_ASSERT(pstrCommandLine);
+
+    pszPath = m_ProcessPath.QueryStr();
+
+    if ((wcsstr(pszPath, L":") == NULL) && (wcsstr(pszPath, L"%") == NULL))
+    {
+        // let's check whether it is a relative path
+        if (FAILED(hr = strRelativePath.Copy(m_pszRootApplicationPath.QueryStr())) ||
+            FAILED(hr = strRelativePath.Append(L"\\")) ||
+            FAILED(hr = strRelativePath.Append(pszPath)))
+        {
+            goto Finished;
+        }
+
+        dwBufferSize = strRelativePath.QueryCCH() + 1;
+        pszFullPath = new WCHAR[dwBufferSize];
+        if (pszFullPath == NULL)
+        {
+            hr = E_OUTOFMEMORY;
+            goto Finished;
+        }
+
+        if (_wfullpath(pszFullPath,
+            strRelativePath.QueryStr(),
+            dwBufferSize) == NULL)
+        {
+            hr = HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
+            goto Finished;
+        }
+
+        if ((file = _wfsopen(pszFullPath, L"r", _SH_DENYNO)) != NULL)
+        {
+            fclose(file);
+            pszPath = pszFullPath;
+        }
+    }
+    if (FAILED(hr = pstrCommandLine->Copy(pszPath)) ||
+        FAILED(hr = pstrCommandLine->Append(L" ")) ||
+        FAILED(hr = pstrCommandLine->Append(m_Arguments.QueryStr())))
+    {
+        goto Finished;
+    }
+
+Finished:
+    if (pszFullPath != NULL)
+    {
+        delete pszFullPath;
+    }
+    return hr;
+}
+
+
+HRESULT
+SERVER_PROCESS::PostStartCheck(
+    const STRU* const pStruCommandline,
+    STRU*             pStruErrorMessage)
+{
+    HRESULT hr = S_OK;
+
+    BOOL    fReady = FALSE;
+    BOOL    fProcessMatch = FALSE;
+    BOOL    fDebuggerAttached = FALSE;
+    DWORD   dwTickCount = 0;
+    DWORD   dwTimeDifference = 0;
+    DWORD   dwActualProcessId = 0;
+    INT     iChildProcessIndex = -1;
+
+    if (CheckRemoteDebuggerPresent(m_hProcessHandle, &fDebuggerAttached) == 0)
+    {
+        // some error occurred  - assume debugger is not attached;
+        fDebuggerAttached = FALSE;
+    }
+
+    dwTickCount = GetTickCount();
+    do
+    {
+        DWORD processStatus;
+        if (GetExitCodeProcess(m_hProcessHandle, &processStatus))
+        {
+            // make sure the process is still running
+            if (processStatus != STILL_ACTIVE)
+            {
+                hr = E_FAIL;
+                pStruErrorMessage->SafeSnwprintf(
+                    ASPNETCORE_EVENT_PROCESS_START_ERROR_MSG,
+                    m_struAppFullPath.QueryStr(),
+                    m_pszRootApplicationPath.QueryStr(),
+                    pStruCommandline->QueryStr(),
+                    hr,
+                    processStatus);
+                goto Finished;
+            }
+        }
+        //
+        // dwActualProcessId will be set only when NsiAPI(GetExtendedTcpTable) is supported
+        //
+        hr = CheckIfServerIsUp(m_dwPort, &dwActualProcessId, &fReady);
+        fDebuggerAttached = IsDebuggerIsAttached();
+
+        if (!fReady)
+        {
+            Sleep(250);
+        }
+
+        dwTimeDifference = (GetTickCount() - dwTickCount);
+    } while (fReady == FALSE &&
+        ((dwTimeDifference < m_dwStartupTimeLimitInMS) || fDebuggerAttached));
+
+    // register call back with the created process
+    if (FAILED(hr = RegisterProcessWait(&m_hProcessWaitHandle, m_hProcessHandle)))
+    {
+        goto Finished;
+    }
+
+    //
+    // check if debugger is attached after startupTimeout.
+    //
+    if (!fDebuggerAttached &&
+        CheckRemoteDebuggerPresent(m_hProcessHandle, &fDebuggerAttached) == 0)
+    {
+        // some error occurred  - assume debugger is not attached;
+        fDebuggerAttached = FALSE;
+    }
+    if (!g_fNsiApiNotSupported)
+    {
+        //
+        // NsiAPI(GetExtendedTcpTable) is supported. we should check whether processIds matche
+        //
+        if (dwActualProcessId == m_dwProcessId)
+        {
+            m_dwListeningProcessId = m_dwProcessId;
+            fProcessMatch = TRUE;
+        }
+
+        if (!fProcessMatch)
+        {
+            // could be the scenario that backend creates child process
+            if (FAILED(hr = GetChildProcessHandles()))
+            {
+                goto Finished;
+            }
+
+            for (DWORD i = 0; i < m_cChildProcess; ++i)
+            {
+                // a child process listen on the assigned port
+                if (dwActualProcessId == m_dwChildProcessIds[i])
+                {
+                    m_dwListeningProcessId = m_dwChildProcessIds[i];
+                    fProcessMatch = TRUE;
+
+                    if (m_hChildProcessHandles[i] != NULL)
+                    {
+                        if (fDebuggerAttached == FALSE &&
+                            CheckRemoteDebuggerPresent(m_hChildProcessHandles[i], &fDebuggerAttached) == 0)
+                        {
+                            // some error occurred  - assume debugger is not attached;
+                            fDebuggerAttached = FALSE;
+                        }
+
+                        if (FAILED(hr = RegisterProcessWait(&m_hChildProcessWaitHandles[i],
+                            m_hChildProcessHandles[i])))
+                        {
+                            goto Finished;
+                        }
+                        iChildProcessIndex = i;
+                    }
+                    break;
+                }
+            }
+        }
+
+        if(!fProcessMatch)
+        {
+            //
+            // process that we created is not listening 
+            // on the port we specified.
+            //
+            fReady = FALSE;
+            pStruErrorMessage->SafeSnwprintf(
+                ASPNETCORE_EVENT_PROCESS_START_WRONGPORT_ERROR_MSG,
+                m_struAppFullPath.QueryStr(),
+                m_pszRootApplicationPath.QueryStr(),
+                pStruCommandline->QueryStr(),
+                m_dwPort,
+                hr);
+            hr = HRESULT_FROM_WIN32(ERROR_CREATE_FAILED);
+            goto Finished;
+        }
+    }
+
+    if (!fReady)
+    {
+        //
+        // hr is already set by CheckIfServerIsUp
+        //
+        if (dwTimeDifference >= m_dwStartupTimeLimitInMS)
+        {
+            hr = HRESULT_FROM_WIN32(ERROR_TIMEOUT);
+            pStruErrorMessage->SafeSnwprintf(
+                ASPNETCORE_EVENT_PROCESS_START_NOTREADY_ERROR_MSG,
+                m_struAppFullPath.QueryStr(),
+                m_pszRootApplicationPath.QueryStr(),
+                pStruCommandline->QueryStr(),
+                m_dwPort,
+                hr);
+        }
+        goto Finished;
+    }
+
+    if (iChildProcessIndex >= 0)
+    {
+        //
+        // final check to make sure child process listening on HTTP is still UP
+        // This is needed because, the child process might have crashed/exited between
+        // the previous call to checkIfServerIsUp and RegisterProcessWait
+        // and we would not know about it.
+        // 
+
+        hr = CheckIfServerIsUp(m_dwPort, &dwActualProcessId, &fReady);
+
+        if ((FAILED(hr) || fReady == FALSE))
+        {
+            pStruErrorMessage->SafeSnwprintf(
+                ASPNETCORE_EVENT_PROCESS_START_NOTREADY_ERROR_MSG,
+                m_struAppFullPath.QueryStr(),
+                m_pszRootApplicationPath.QueryStr(),
+                pStruCommandline->QueryStr(),
+                m_dwPort,
+                hr);
+            goto Finished;
+        }
+    }
+
+    //
+    // ready to mark the server process ready but before this, 
+    // create and initialize the FORWARDER_CONNECTION 
+    //
+    if (m_pForwarderConnection != NULL)
+    {
+        m_pForwarderConnection->DereferenceForwarderConnection();
+        m_pForwarderConnection = NULL;
+    }
+
+    if (m_pForwarderConnection == NULL)
+    {
+        m_pForwarderConnection = new FORWARDER_CONNECTION();
+        if (m_pForwarderConnection == NULL)
+        {
+            hr = E_OUTOFMEMORY;
+            goto Finished;
+        }
+
+        hr = m_pForwarderConnection->Initialize(m_dwPort);
+        if (FAILED(hr))
+        {
+            goto Finished;
+        }
+    }
+
+    if (!g_fNsiApiNotSupported)
+    {
+        m_hListeningProcessHandle = OpenProcess(SYNCHRONIZE | PROCESS_TERMINATE | PROCESS_DUP_HANDLE,
+                                                FALSE, 
+                                                m_dwListeningProcessId);
+    }
+
+    //
+    // mark server process as Ready
+    //
+    m_fReady = TRUE;
+
+Finished:
+    return hr;
+}
+
+HRESULT
+SERVER_PROCESS::StartProcess(
+    IHttpContext *context
+)
+{
+    HRESULT                 hr = S_OK;
+    PROCESS_INFORMATION     processInformation = {0};
+    STARTUPINFOW            startupInfo = {0};
+    BOOL                    fDonePrepareCommandLine = FALSE;
+    DWORD                   dwCreationFlags = 0;
+
+    STACK_STRU(             strEventMsg, 256);
+    STRU                    strFullProcessPath;
+    STRU                    struRelativePath;
+    STRU                    struApplicationId;
+    STRU                    struCommandLine;
+
+    LPCWSTR                 apsz[1];
+    
+    MULTISZ                 mszNewEnvironment;
+    ENVIRONMENT_VAR_HASH    *pHashTable = NULL;
+
+    GetStartupInfoW(&startupInfo);
+
+    //
+    // setup stdout and stderr handles to our stdout handle only if
+    // the handle is valid.
+    //
+    SetupStdHandles(context, &startupInfo);
+    
+    if (FAILED(hr = InitEnvironmentVariablesTable(&pHashTable)))
+    {
+        goto Finished;
+    }
+
+    //
+    // setup the the port that the backend process will listen on
+    //
+    if (FAILED (hr= SetupListenPort(pHashTable)))
+    {
+        goto Finished;
+    }
+
+    //
+    // get app path
+    //
+    if (FAILED(hr = SetupAppPath(context, pHashTable)))
+    {
+        goto Finished;
+    }
+
+    //
+    // generate new guid for each process
+    //
+    if (FAILED(hr = SetupAppToken(pHashTable)))
+    {
+        goto Finished;
+    }
+
+    //
+    // setup environment variables for new process
+    //
+    if (FAILED(hr = OutputEnvironmentVariables(&mszNewEnvironment, pHashTable)))
+    {
+        goto Finished;
+    }
+
+    //
+    // generate process command line.
+    //
+    if (FAILED(hr = SetupCommandLine(&struCommandLine)))
+    {
+        goto Finished;
+    }
+
+    fDonePrepareCommandLine = TRUE;
+
+    dwCreationFlags = CREATE_NO_WINDOW |
+        CREATE_UNICODE_ENVIRONMENT |
+        CREATE_SUSPENDED  |
+        CREATE_NEW_PROCESS_GROUP;
+
+    if (!CreateProcessW(
+            NULL,                   // applicationName     
+            struCommandLine.QueryStr(),
+            NULL,                   // processAttr
+            NULL,                   // threadAttr
+            TRUE,                   // inheritHandles
+            dwCreationFlags,
+            mszNewEnvironment.QueryStr(),
+            m_pszRootApplicationPath.QueryStr(), // currentDir
+            &startupInfo,
+            &processInformation) )
+    {
+        hr = HRESULT_FROM_WIN32(GetLastError());
+        // don't the check return code as we already in error report
+        strEventMsg.SafeSnwprintf(
+            ASPNETCORE_EVENT_PROCESS_START_ERROR_MSG,
+            m_struAppFullPath.QueryStr(),
+            m_pszRootApplicationPath.QueryStr(),
+            struCommandLine.QueryStr(),
+            hr,
+            0);
+        goto Finished;
+    }
+
+    m_hProcessHandle = processInformation.hProcess;
+    m_dwProcessId = processInformation.dwProcessId;
+
+    if (m_hJobObject != NULL)
+    {
+        if (!AssignProcessToJobObject(m_hJobObject, m_hProcessHandle))
+        {
+            hr = HRESULT_FROM_WIN32(GetLastError());
+            if (hr != HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED))
+            {
+                goto Finished;
+            }
+        }
+    }
+
+    if (ResumeThread( processInformation.hThread ) == -1)
+    {
+        hr = HRESULT_FROM_WIN32( GetLastError() );
+        goto Finished;
+    }    
+
+    //
+    // need to make sure the server is up and listening on the port specified.
+    //
+    if (FAILED(hr = PostStartCheck(&struCommandLine, &strEventMsg)))
+    {
+        goto Finished;
+    }
+
+
+    if (SUCCEEDED(strEventMsg.SafeSnwprintf(
+        ASPNETCORE_EVENT_PROCESS_START_SUCCESS_MSG,
+        m_struAppFullPath.QueryStr(),
+        m_dwProcessId,
+        m_dwPort)))
+    {
+        apsz[0] = strEventMsg.QueryStr();
+
+        //
+        // not checking return code because if ReportEvent
+        // fails, we cannot do anything.
+        //
+        if (FORWARDING_HANDLER::QueryEventLog() != NULL)
+        {
+            ReportEventW(FORWARDING_HANDLER::QueryEventLog(),
+                EVENTLOG_INFORMATION_TYPE,
+                0,
+                ASPNETCORE_EVENT_PROCESS_START_SUCCESS,
+                NULL,
+                1,
+                0,
+                apsz,
+                NULL);
+        }
+    }
+
+Finished:
+    if (processInformation.hThread != NULL)
+    {
+        CloseHandle(processInformation.hThread);
+        processInformation.hThread = NULL;
+    }
+
+    if (pHashTable != NULL)
+    {
+        pHashTable->Clear();
+        delete pHashTable;
+        pHashTable = NULL;
+    }
+
+    if ( FAILED(hr) )
+    {
+        if (strEventMsg.IsEmpty())
+        {
+            if (!fDonePrepareCommandLine)
+                strEventMsg.SafeSnwprintf(
+                m_struAppFullPath.QueryStr(),
+                ASPNETCORE_EVENT_PROCESS_START_INTERNAL_ERROR_MSG,
+                hr);
+            else
+                strEventMsg.SafeSnwprintf(
+                ASPNETCORE_EVENT_PROCESS_START_POSTCREATE_ERROR_MSG,
+                m_struAppFullPath.QueryStr(),
+                m_pszRootApplicationPath.QueryStr(),
+                struCommandLine.QueryStr(),
+                hr);
+        }
+
+        apsz[0] = strEventMsg.QueryStr();
+
+        // not checking return code because if ReportEvent
+        // fails, we cannot do anything.
+        //
+        if (FORWARDING_HANDLER::QueryEventLog() != NULL)
+        {
+            ReportEventW(FORWARDING_HANDLER::QueryEventLog(),
+                EVENTLOG_ERROR_TYPE,
+                0,
+                ASPNETCORE_EVENT_PROCESS_START_ERROR,
+                NULL,
+                1,
+                0,
+                apsz,
+                NULL);
+        }
+    }
+
+    if ( FAILED( hr ) || m_fReady == FALSE)
+    {
+        if (m_hStdoutHandle != NULL)
+        {
+            if ( m_hStdoutHandle != INVALID_HANDLE_VALUE )
+            {
+                CloseHandle( m_hStdoutHandle );
+            }
+            m_hStdoutHandle = NULL;
+        }
+
+        if ( m_fStdoutLogEnabled )
+        {
+            m_Timer.CancelTimer();
+        }
+
+        if (m_hListeningProcessHandle != NULL)
+        {
+            if( m_hListeningProcessHandle != INVALID_HANDLE_VALUE )
+            {
+                CloseHandle( m_hListeningProcessHandle );
+            }
+            m_hListeningProcessHandle = NULL;
+        }
+
+        if ( m_hProcessWaitHandle != NULL )
+        {
+            UnregisterWait( m_hProcessWaitHandle );
+            m_hProcessWaitHandle = NULL;
+        }
+
+        StopProcess();
+
+        StopAllProcessesInJobObject();
+    }
+    return hr;
+}
+
+HRESULT
+SERVER_PROCESS::SetWindowsAuthToken(
+    HANDLE hToken,
+    LPHANDLE pTargetTokenHandle
+)
+{
+    HRESULT hr = S_OK;
+
+    if ( m_hListeningProcessHandle != NULL && m_hListeningProcessHandle != INVALID_HANDLE_VALUE )
+    {
+        if (!DuplicateHandle( GetCurrentProcess(),
+                             hToken,
+                             m_hListeningProcessHandle,
+                             pTargetTokenHandle,
+                             0,
+                             FALSE,
+                             DUPLICATE_SAME_ACCESS ))
+        {
+            hr = HRESULT_FROM_GETLASTERROR();
+            goto Finished;
+        }
+    }
+
+Finished:
+
+    return hr;
+}
+
+HRESULT
+SERVER_PROCESS::SetupStdHandles(
+    IHttpContext *context,
+    LPSTARTUPINFOW pStartupInfo
+)
+{
+    SECURITY_ATTRIBUTES     saAttr = {0};
+    HRESULT                 hr = S_OK;
+    SYSTEMTIME              systemTime;
+    STRU                    struLogFileName;
+    BOOL                    fStdoutLoggingFailed = FALSE;
+    STRU                    strEventMsg;
+    LPCWSTR                 apsz[1];
+    STRU                    struAbsLogFilePath;
+
+    DBG_ASSERT(pStartupInfo);
+
+    if ( m_fStdoutLogEnabled )
+    {
+        saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
+        saAttr.bInheritHandle = TRUE; 
+        saAttr.lpSecurityDescriptor = NULL;
+
+        if (m_hStdoutHandle != NULL)
+        {
+            if(!CloseHandle( m_hStdoutHandle ))
+            {
+                hr = HRESULT_FROM_GETLASTERROR();
+                goto Finished;
+            }
+
+            m_hStdoutHandle = NULL;
+        }
+
+        hr = PATH::ConvertPathToFullPath( m_struLogFile.QueryStr(), 
+                                          context->GetApplication()->GetApplicationPhysicalPath(),
+                                          &struAbsLogFilePath );
+        if (FAILED(hr))
+        {
+            goto Finished;
+        }
+
+        GetSystemTime(&systemTime);
+        hr = struLogFileName.SafeSnwprintf( L"%s_%d_%d%d%d%d%d%d.log", 
+                                            struAbsLogFilePath.QueryStr(), 
+                                            GetCurrentProcessId(),
+                                            systemTime.wYear,
+                                            systemTime.wMonth,
+                                            systemTime.wDay,
+                                            systemTime.wHour,
+                                            systemTime.wMinute,
+                                            systemTime.wSecond );
+        if (FAILED(hr))
+        {
+            goto Finished;
+        }
+
+        m_hStdoutHandle = CreateFileW( struLogFileName.QueryStr(),
+                                       FILE_WRITE_DATA,
+                                       FILE_SHARE_READ,
+                                       &saAttr,
+                                       CREATE_ALWAYS,
+                                       FILE_ATTRIBUTE_NORMAL,
+                                       NULL );
+        if ( m_hStdoutHandle == INVALID_HANDLE_VALUE )
+        {
+            fStdoutLoggingFailed = TRUE;
+            m_hStdoutHandle = NULL;
+
+            if( SUCCEEDED( strEventMsg.SafeSnwprintf( 
+                           ASPNETCORE_EVENT_INVALID_STDOUT_LOG_FILE_MSG,
+                           struLogFileName.QueryStr(), 
+                           HRESULT_FROM_GETLASTERROR() ) ) )
+            {
+                apsz[0] = strEventMsg.QueryStr();
+
+                //
+                // not checking return code because if ReportEvent
+                // fails, we cannot do anything.
+                //
+                if (FORWARDING_HANDLER::QueryEventLog() != NULL)
+                {
+                    ReportEventW(FORWARDING_HANDLER::QueryEventLog(),
+                        EVENTLOG_WARNING_TYPE,
+                        0,
+                        ASPNETCORE_EVENT_CONFIG_ERROR,
+                        NULL,
+                        1,
+                        0,
+                        apsz,
+                        NULL);
+                }
+            }
+        }
+
+        if( !fStdoutLoggingFailed )
+        {
+            pStartupInfo->dwFlags = STARTF_USESTDHANDLES;
+            pStartupInfo->hStdInput = INVALID_HANDLE_VALUE;
+            pStartupInfo->hStdError = m_hStdoutHandle;
+            pStartupInfo->hStdOutput = m_hStdoutHandle;
+
+            m_struFullLogFile.Copy( struLogFileName );
+
+            // start timer to open and close handles regularly.
+            m_Timer.InitializeTimer(SERVER_PROCESS::TimerCallback, this, 3000, 3000);
+        }
+    }
+
+    if( (!m_fStdoutLogEnabled || fStdoutLoggingFailed) && 
+        m_pProcessManager->QueryNULHandle() != NULL &&
+        m_pProcessManager->QueryNULHandle() != INVALID_HANDLE_VALUE )
+    {
+        pStartupInfo->dwFlags = STARTF_USESTDHANDLES;
+        pStartupInfo->hStdInput = INVALID_HANDLE_VALUE;
+        pStartupInfo->hStdError = m_pProcessManager->QueryNULHandle();
+        pStartupInfo->hStdOutput = m_pProcessManager->QueryNULHandle();
+    }
+
+Finished:
+
+    return hr;
+}
+
+VOID
+CALLBACK
+SERVER_PROCESS::TimerCallback(
+    IN PTP_CALLBACK_INSTANCE Instance,
+    IN PVOID Context,
+    IN PTP_TIMER Timer
+)
+{
+    Instance;
+    Timer;
+    SERVER_PROCESS*         pServerProcess = (SERVER_PROCESS*) Context;
+    HANDLE                  hStdoutHandle = NULL;
+    SECURITY_ATTRIBUTES     saAttr = {0};
+    HRESULT                 hr = S_OK;
+
+    saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
+    saAttr.bInheritHandle = TRUE; 
+    saAttr.lpSecurityDescriptor = NULL;
+
+    hStdoutHandle = CreateFileW( pServerProcess->QueryFullLogPath(),
+                                 FILE_READ_DATA,
+                                 FILE_SHARE_WRITE,
+                                 &saAttr,
+                                 OPEN_ALWAYS,
+                                 FILE_ATTRIBUTE_NORMAL,
+                                 NULL );
+    if( hStdoutHandle == INVALID_HANDLE_VALUE )
+    {
+        hr = HRESULT_FROM_GETLASTERROR();
+    }
+
+    CloseHandle( hStdoutHandle );
+}
+
+HRESULT
+SERVER_PROCESS::CheckIfServerIsUp(
+    _In_  DWORD       dwPort,
+    _Out_ DWORD     * pdwProcessId,
+    _Out_ BOOL      * pfReady
+)
+{
+    HRESULT                 hr = S_OK;
+    DWORD                   dwResult = 0;
+    MIB_TCPTABLE_OWNER_PID *pTCPInfo = NULL;
+    MIB_TCPROW_OWNER_PID   *pOwner = NULL;
+    DWORD                   dwSize = 0;
+    int                     iResult = 0;
+    SOCKADDR_IN             sockAddr;
+    SOCKET                  socketCheck = INVALID_SOCKET;
+
+    DBG_ASSERT(pfReady);
+    DBG_ASSERT(pdwProcessId);
+
+    *pfReady = FALSE;
+    //
+    // it's OK for us to return processID 0 in case we cannot detect the real one
+    //
+    *pdwProcessId = 0;
+
+    if (!g_fNsiApiNotSupported)
+    {
+        dwResult = GetExtendedTcpTable(NULL,
+                                       &dwSize,
+                                       FALSE,
+                                       AF_INET,
+                                       TCP_TABLE_OWNER_PID_LISTENER,
+                                       0);
+
+        if (dwResult != NO_ERROR && dwResult != ERROR_INSUFFICIENT_BUFFER)
+        {
+            hr = HRESULT_FROM_WIN32(dwResult);
+            goto Finished;
+        }
+
+        pTCPInfo = (MIB_TCPTABLE_OWNER_PID*)HeapAlloc(GetProcessHeap(), 0, dwSize);
+        if (pTCPInfo == NULL)
+        {
+            hr = E_OUTOFMEMORY;
+            goto Finished;
+        }
+
+        dwResult = GetExtendedTcpTable(pTCPInfo,
+                                       &dwSize,
+                                       FALSE,
+                                       AF_INET,
+                                       TCP_TABLE_OWNER_PID_LISTENER,
+                                       0);
+        if (dwResult != NO_ERROR)
+        {
+            hr = HRESULT_FROM_WIN32(dwResult);
+            goto Finished;
+        }
+
+        // iterate pTcpInfo struct to find PID/PORT entry
+        for (DWORD dwLoop = 0; dwLoop < pTCPInfo->dwNumEntries; dwLoop++)
+        {
+            pOwner = &pTCPInfo->table[dwLoop];
+            if (ntohs((USHORT)pOwner->dwLocalPort) == dwPort)
+            {
+                *pdwProcessId = pOwner->dwOwningPid;
+                *pfReady = TRUE;
+                break;
+            }
+        }
+    }
+    else
+    {
+        //
+        // We have to open socket to ping the service
+        //
+        socketCheck = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+
+        if (socketCheck == INVALID_SOCKET)
+        {
+            hr = HRESULT_FROM_WIN32(WSAGetLastError());
+            goto Finished;
+        }
+
+        sockAddr.sin_family = AF_INET;
+        if (!inet_pton(AF_INET, LOCALHOST, &(sockAddr.sin_addr)))
+        {
+            hr = HRESULT_FROM_WIN32(WSAGetLastError());
+            goto Finished;
+        }
+
+        //sockAddr.sin_addr.s_addr = inet_addr( LOCALHOST );
+        sockAddr.sin_port = htons((u_short)dwPort);
+
+        //
+        // Connect to server.
+        //
+        iResult = connect(socketCheck, (SOCKADDR *)&sockAddr, sizeof(sockAddr));
+        if (iResult == SOCKET_ERROR)
+        {
+            hr = HRESULT_FROM_WIN32(WSAGetLastError());
+            goto Finished;
+        }
+
+        *pfReady = TRUE;
+    }
+
+Finished:
+
+    if (socketCheck != INVALID_SOCKET)
+    {
+        iResult = closesocket(socketCheck);
+        if (iResult == SOCKET_ERROR)
+        {
+            hr = HRESULT_FROM_WIN32(WSAGetLastError());
+        }
+        socketCheck = INVALID_SOCKET;
+    }
+
+    if( pTCPInfo != NULL )
+    {
+        HeapFree( GetProcessHeap(), 0, pTCPInfo );
+        pTCPInfo = NULL;
+    }
+
+    return hr;
+}
+
+// send signal to the process to let it gracefully shutdown
+// if the process cannot shutdown within given time, terminate it
+VOID
+SERVER_PROCESS::SendSignal(
+    VOID
+)
+{
+    HRESULT hr      = S_OK;
+    HANDLE  hThread = NULL;
+
+    ReferenceServerProcess();
+
+    m_hShutdownHandle = OpenProcess(SYNCHRONIZE | PROCESS_TERMINATE, FALSE, m_dwProcessId);
+
+    if (m_hShutdownHandle == NULL)
+    {
+        // since we cannot open the process. let's terminate the process 
+        hr = HRESULT_FROM_WIN32(GetLastError());
+        goto Finished;
+    }
+
+    hThread = CreateThread(
+        NULL,       // default security attributes
+        0,          // default stack size
+        (LPTHREAD_START_ROUTINE)SendShutDownSignal,
+        this,       // thread function arguments
+        0,          // default creation flags
+        NULL);      // receive thread identifier
+
+    if (hThread == NULL)
+    {
+        hr = HRESULT_FROM_WIN32(GetLastError());
+        goto Finished;
+    }
+
+    if (WaitForSingleObject(m_hShutdownHandle, m_dwShutdownTimeLimitInMS) != WAIT_OBJECT_0)
+    {
+        hr = HRESULT_FROM_WIN32(ERROR_TIMEOUT);
+        goto Finished;
+    }
+
+
+Finished:
+    if (hThread != NULL)
+    {
+        // if the send shutdown message thread is still running, terminate it
+        DWORD dwThreadStatus = 0;
+        if (GetExitCodeThread(hThread, &dwThreadStatus)!= 0 && dwThreadStatus == STILL_ACTIVE)
+        {
+            TerminateThread(hThread, STATUS_CONTROL_C_EXIT);
+        }
+        CloseHandle(hThread);
+        hThread = NULL;
+    }
+
+    if (FAILED(hr))
+    {
+        TerminateBackendProcess();
+    }
+
+    if (m_hShutdownHandle != NULL && m_hShutdownHandle != INVALID_HANDLE_VALUE)
+    {
+        CloseHandle(m_hShutdownHandle);
+        m_hShutdownHandle = NULL;
+    }
+
+    DereferenceServerProcess();
+}
+
+//
+// StopProcess is only called if process crashes OR if the process
+// creation failed and calling this counts towards RapidFailCounts.
+//
+
+VOID
+SERVER_PROCESS::StopProcess(
+    VOID
+)
+{
+    m_fReady = FALSE;
+
+    m_pProcessManager->IncrementRapidFailCount();
+
+    for(INT i=0;i<MAX_ACTIVE_CHILD_PROCESSES; ++i)
+    {
+        if(m_hChildProcessHandles[i] != NULL)
+        {
+            if( m_hChildProcessHandles[i] != INVALID_HANDLE_VALUE )
+            {
+                TerminateProcess( m_hChildProcessHandles[i], 0 );
+                CloseHandle( m_hChildProcessHandles[i] );
+            }
+            m_hChildProcessHandles[i] = NULL;
+            m_dwChildProcessIds[i] = 0;
+        }
+    }
+
+    if( m_hProcessHandle != NULL )
+    {
+        if( m_hProcessHandle != INVALID_HANDLE_VALUE )
+        {
+            TerminateProcess( m_hProcessHandle, 0 );
+            CloseHandle( m_hProcessHandle );
+        }
+        m_hProcessHandle = NULL;
+    }
+}
+
+BOOL 
+SERVER_PROCESS::IsDebuggerIsAttached(
+    VOID
+)
+{
+    HRESULT                             hr = S_OK;
+    PJOBOBJECT_BASIC_PROCESS_ID_LIST    processList = NULL;
+    DWORD                               dwPid = 0;
+    DWORD                               dwWorkerProcessPid = 0;
+    DWORD                               cbNumBytes = 1024;
+    DWORD                               dwRetries = 0;
+    DWORD                               dwError = NO_ERROR;
+    BOOL                                fDebuggerPresent = FALSE;
+
+    dwWorkerProcessPid = GetCurrentProcessId();
+
+    do
+    {
+        dwError = NO_ERROR;
+
+        if( processList != NULL )
+        {
+            HeapFree(GetProcessHeap(), 0, processList);
+            processList = NULL;
+
+            // resize
+            cbNumBytes = cbNumBytes * 2;
+        }
+
+        processList = (PJOBOBJECT_BASIC_PROCESS_ID_LIST) HeapAlloc(
+                            GetProcessHeap(), 
+                            0, 
+                            cbNumBytes
+                            );
+        if( processList == NULL )
+        {
+            hr = E_OUTOFMEMORY;
+            goto Finished;
+        }
+
+        RtlZeroMemory( processList, cbNumBytes );
+
+        if( !QueryInformationJobObject( 
+                m_hJobObject, 
+                JobObjectBasicProcessIdList, 
+                processList, 
+                cbNumBytes, 
+                NULL) )
+        {
+            dwError = GetLastError();
+            if( dwError != ERROR_MORE_DATA )
+            {
+                hr = HRESULT_FROM_WIN32(dwError);
+                goto Finished;
+            }
+        }
+
+    } while( dwRetries++ < 5 && 
+             processList != NULL && 
+             ( processList->NumberOfAssignedProcesses > processList->NumberOfProcessIdsInList || 
+               processList->NumberOfProcessIdsInList == 0 ) );
+
+    if( dwError == ERROR_MORE_DATA )
+    {
+        hr = E_OUTOFMEMORY;
+        // some error
+        goto Finished;
+    }
+
+    if( processList == NULL || 
+        ( processList->NumberOfAssignedProcesses > processList->NumberOfProcessIdsInList || 
+        processList->NumberOfProcessIdsInList == 0 ) )
+    {
+        hr = HRESULT_FROM_WIN32(ERROR_PROCESS_ABORTED);
+        // some error
+        goto Finished;
+    }
+
+    if( processList->NumberOfProcessIdsInList > MAX_ACTIVE_CHILD_PROCESSES )
+    {
+        hr = HRESULT_FROM_WIN32( ERROR_CREATE_FAILED );
+        goto Finished;
+    }
+ 
+    for( DWORD i=0; i<processList->NumberOfProcessIdsInList; i++ )
+    {
+        dwPid = (DWORD)processList->ProcessIdList[i];
+        if( dwPid != dwWorkerProcessPid )
+        {
+            HANDLE hProcess = OpenProcess( 
+                                            PROCESS_QUERY_INFORMATION | SYNCHRONIZE | PROCESS_TERMINATE | PROCESS_DUP_HANDLE,
+                                            FALSE, 
+                                            dwPid 
+                                        );
+
+            BOOL returnValue = CheckRemoteDebuggerPresent( hProcess, &fDebuggerPresent );
+            if (hProcess != NULL)
+            {
+                CloseHandle(hProcess);
+                hProcess = NULL;
+            }
+
+            if( ! returnValue )
+            {
+                goto Finished;
+            }
+
+            if( fDebuggerPresent )
+            {
+                break;
+            }
+        }
+    }
+
+Finished:
+
+    if( processList != NULL )
+    {
+        HeapFree(GetProcessHeap(), 0, processList);
+    }
+
+    return fDebuggerPresent;
+}
+
+HRESULT 
+SERVER_PROCESS::GetChildProcessHandles(
+    VOID
+)
+{
+    HRESULT                             hr = S_OK;
+    PJOBOBJECT_BASIC_PROCESS_ID_LIST    processList = NULL;
+    DWORD                               dwPid = 0;
+    DWORD                               dwWorkerProcessPid = 0;
+    DWORD                               cbNumBytes = 1024;
+    DWORD                               dwRetries = 0;
+    DWORD                               dwError = NO_ERROR;
+
+    dwWorkerProcessPid = GetCurrentProcessId();
+
+    do
+    {
+        dwError = NO_ERROR;
+
+        if( processList != NULL )
+        {
+            HeapFree(GetProcessHeap(), 0, processList);
+            processList = NULL;
+
+            // resize
+            cbNumBytes = cbNumBytes * 2;
+        }
+
+        processList = (PJOBOBJECT_BASIC_PROCESS_ID_LIST) HeapAlloc(
+                            GetProcessHeap(), 
+                            0, 
+                            cbNumBytes
+                            );
+        if( processList == NULL )
+        {
+            hr = E_OUTOFMEMORY;
+            goto Finished;
+        }
+
+        RtlZeroMemory( processList, cbNumBytes );
+
+        if( !QueryInformationJobObject( 
+                m_hJobObject, 
+                JobObjectBasicProcessIdList, 
+                processList, 
+                cbNumBytes, 
+                NULL) )
+        {
+            dwError = GetLastError();
+            if( dwError != ERROR_MORE_DATA )
+            {
+                hr = HRESULT_FROM_WIN32(dwError);
+                goto Finished;
+            }
+        }
+
+    } while( dwRetries++ < 5 && 
+             processList != NULL && 
+             ( processList->NumberOfAssignedProcesses > processList->NumberOfProcessIdsInList || processList->NumberOfProcessIdsInList == 0 ) );
+
+    if( dwError == ERROR_MORE_DATA )
+    {
+        hr = E_OUTOFMEMORY;
+        // some error
+        goto Finished;
+    }
+
+    if( processList == NULL || ( processList->NumberOfAssignedProcesses > processList->NumberOfProcessIdsInList || processList->NumberOfProcessIdsInList == 0 ) )
+    {
+        hr = HRESULT_FROM_WIN32(ERROR_PROCESS_ABORTED);
+        // some error
+        goto Finished;
+    }
+
+    if( processList->NumberOfProcessIdsInList > MAX_ACTIVE_CHILD_PROCESSES )
+    {
+        hr = HRESULT_FROM_WIN32( ERROR_CREATE_FAILED );
+        goto Finished;
+    }
+ 
+    for( DWORD i=0; i<processList->NumberOfProcessIdsInList; i++ )
+    {
+        dwPid = (DWORD)processList->ProcessIdList[i];
+        if( dwPid != m_dwProcessId &&
+            dwPid != dwWorkerProcessPid )
+        {
+            m_hChildProcessHandles[m_cChildProcess] = OpenProcess( 
+                                            PROCESS_QUERY_INFORMATION | SYNCHRONIZE | PROCESS_TERMINATE | PROCESS_DUP_HANDLE,
+                                            FALSE, 
+                                            dwPid 
+                                        );
+            m_dwChildProcessIds[m_cChildProcess] = dwPid;
+            m_cChildProcess ++;
+        }
+    }
+
+Finished:
+
+    if( processList != NULL )
+    {
+        HeapFree(GetProcessHeap(), 0, processList);
+    }
+
+    return hr;
+}
+
+HRESULT
+SERVER_PROCESS::StopAllProcessesInJobObject(
+        VOID
+)
+{
+    HRESULT                             hr = S_OK;
+    PJOBOBJECT_BASIC_PROCESS_ID_LIST    processList = NULL;
+    HANDLE                              hProcess = NULL;
+    DWORD                               dwWorkerProcessPid = 0;
+    DWORD                               cbNumBytes = 1024;
+    DWORD                               dwRetries = 0;
+
+    dwWorkerProcessPid = GetCurrentProcessId();
+
+    do
+    {
+        if( processList != NULL )
+        {
+            HeapFree(GetProcessHeap(), 0, processList);
+            processList = NULL;
+
+            // resize
+            cbNumBytes = cbNumBytes * 2;
+        }
+
+        processList = (PJOBOBJECT_BASIC_PROCESS_ID_LIST) HeapAlloc(
+                            GetProcessHeap(), 
+                            0, 
+                            cbNumBytes
+                            );
+        if( processList == NULL )
+        {
+            hr = E_OUTOFMEMORY;
+            goto Finished;
+        }
+
+        RtlZeroMemory( processList, cbNumBytes );
+
+        if( !QueryInformationJobObject( 
+                m_hJobObject, 
+                JobObjectBasicProcessIdList, 
+                processList, 
+                cbNumBytes, 
+                NULL) )
+        {
+            DWORD dwError = GetLastError();
+            if( dwError != ERROR_MORE_DATA )
+            {
+                hr = HRESULT_FROM_WIN32(dwError);
+                goto Finished;
+            }
+        }
+
+    } while( dwRetries++ < 5 && 
+             processList != NULL && 
+             ( processList->NumberOfAssignedProcesses > processList->NumberOfProcessIdsInList || processList->NumberOfProcessIdsInList == 0 ) );
+
+    if( processList == NULL || ( processList->NumberOfAssignedProcesses > processList->NumberOfProcessIdsInList || processList->NumberOfProcessIdsInList == 0 ) )
+    {
+        hr = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
+        // some error
+        goto Finished;
+    }
+ 
+    for( DWORD i=0; i<processList->NumberOfProcessIdsInList; i++ )
+    {
+        if( dwWorkerProcessPid != (DWORD)processList->ProcessIdList[i] )
+        {
+            hProcess = OpenProcess( PROCESS_TERMINATE, 
+                                    FALSE, 
+                                    (DWORD)processList->ProcessIdList[i] );
+            if( hProcess != NULL )
+            {
+                if( !TerminateProcess(hProcess, 1) )
+                {
+                    hr = HRESULT_FROM_GETLASTERROR();
+                }
+                else
+                {
+                    WaitForSingleObject( hProcess, INFINITE );
+                }
+
+                if( hProcess != NULL )
+                {
+                    CloseHandle( hProcess );
+                    hProcess = NULL;
+                }
+            }
+        }
+    }
+
+Finished:
+
+    if( processList != NULL )
+    {
+        HeapFree(GetProcessHeap(), 0, processList);
+    }
+
+    return hr;
+}
+
+SERVER_PROCESS::SERVER_PROCESS() : 
+    m_cRefs( 1 ),
+    m_hProcessHandle( NULL ),
+    m_hProcessWaitHandle( NULL ),
+    m_dwProcessId( 0 ),
+    m_cChildProcess( 0 ),
+    m_fReady( FALSE ),
+    m_lStopping( 0L ),
+    m_hStdoutHandle( NULL ),
+    m_fStdoutLogEnabled( FALSE ),
+    m_hJobObject( NULL ),
+    m_pForwarderConnection( NULL ),
+    m_dwListeningProcessId( 0 ),
+    m_hListeningProcessHandle( NULL ),
+    m_hShutdownHandle( NULL ),
+    m_randomGenerator( std::random_device()() )
+{
+    InterlockedIncrement(&g_dwActiveServerProcesses);
+
+    for(INT i=0;i<MAX_ACTIVE_CHILD_PROCESSES; ++i)
+    {
+        m_dwChildProcessIds[i] = 0;
+        m_hChildProcessHandles[i] = NULL;
+        m_hChildProcessWaitHandles[i] = NULL;
+    }
+}
+
+SERVER_PROCESS::~SERVER_PROCESS()
+{
+    if(m_hProcessWaitHandle != NULL)
+    {
+        UnregisterWait( m_hProcessWaitHandle );
+        m_hProcessWaitHandle = NULL;
+    }
+
+    for(INT i=0;i<MAX_ACTIVE_CHILD_PROCESSES;++i)
+    {
+        if(m_hChildProcessWaitHandles[i] != NULL)
+        {
+            UnregisterWait( m_hChildProcessWaitHandles[i] );
+            m_hChildProcessWaitHandles[i] = NULL;
+        }
+    }
+
+    if(m_hProcessHandle != NULL)
+    {
+        if(m_hProcessHandle != INVALID_HANDLE_VALUE)
+        {
+            CloseHandle( m_hProcessHandle );
+        }
+        m_hProcessHandle = NULL;
+    }
+
+    if(m_hListeningProcessHandle != NULL)
+    {
+        if(m_hListeningProcessHandle != INVALID_HANDLE_VALUE)
+        {
+            CloseHandle( m_hListeningProcessHandle );
+        }
+        m_hListeningProcessHandle = NULL;
+    }
+
+    for(INT i=0;i<MAX_ACTIVE_CHILD_PROCESSES;++i)
+    {
+        if(m_hChildProcessHandles[i] != NULL)
+        {
+            if(m_hChildProcessHandles[i] != INVALID_HANDLE_VALUE)
+            {
+                CloseHandle( m_hChildProcessHandles[i] );
+            }
+            m_hChildProcessHandles[i] = NULL;
+            m_dwChildProcessIds[i] = 0;
+        }
+    }
+
+    if( m_hStdoutHandle != NULL )
+    {
+        if(m_hStdoutHandle != INVALID_HANDLE_VALUE)
+        {
+            CloseHandle( m_hStdoutHandle );
+        }
+        m_hStdoutHandle = NULL;
+    }
+
+    if( m_fStdoutLogEnabled )
+    {
+        m_Timer.CancelTimer();
+    }
+
+    if( m_hJobObject != NULL )
+    {
+        if(m_hJobObject != INVALID_HANDLE_VALUE)
+        {
+            CloseHandle( m_hJobObject );
+        }
+        m_hJobObject = NULL;
+    }
+
+    if( m_pProcessManager != NULL )
+    {
+        m_pProcessManager->DereferenceProcessManager();
+        m_pProcessManager = NULL;
+    }
+
+    if(m_pForwarderConnection != NULL)
+    {
+        m_pForwarderConnection->DereferenceForwarderConnection();
+        m_pForwarderConnection = NULL;
+    }
+
+    m_pEnvironmentVarTable = NULL;
+    // no need to free m_pEnvironmentVarTable, as it references to
+    // the same hash table hold by configuration.
+    // the hashtable memory will be freed once onfiguration got recycled 
+
+    InterlockedDecrement(&g_dwActiveServerProcesses);
+}
+
+VOID 
+ProcessHandleCallback(
+    _In_ PVOID  pContext,
+    _In_ BOOL
+)
+{
+    SERVER_PROCESS *pServerProcess = (SERVER_PROCESS*) pContext;
+    pServerProcess->HandleProcessExit();
+}
+
+HRESULT
+SERVER_PROCESS::RegisterProcessWait(
+    PHANDLE                 phWaitHandle,
+    HANDLE                  hProcessToWaitOn
+)
+{
+    HRESULT     hr = S_OK;
+    NTSTATUS    status = 0;
+
+    _ASSERT( phWaitHandle != NULL && *phWaitHandle == NULL );
+
+    *phWaitHandle = NULL;
+
+    // wait thread will dereference.
+    ReferenceServerProcess();
+
+    status = RegisterWaitForSingleObject( 
+                phWaitHandle,
+                hProcessToWaitOn,
+                (WAITORTIMERCALLBACK)&ProcessHandleCallback,
+                this,
+                INFINITE,
+                WT_EXECUTEONLYONCE | WT_EXECUTEINWAITTHREAD 
+                );
+
+    if( status < 0 )
+    {
+        hr = HRESULT_FROM_NT( status );
+        goto Finished;
+    }
+
+Finished:
+
+    if( FAILED( hr ) ) 
+    {
+        *phWaitHandle = NULL;
+        DereferenceServerProcess();
+    }
+
+    return hr;
+}
+
+HRESULT
+SERVER_PROCESS::HandleProcessExit()
+{
+    HRESULT     hr = S_OK;
+    BOOL        fReady = FALSE;
+    DWORD       dwProcessId = 0;
+    if (InterlockedCompareExchange(&m_lStopping, 1L, 0L) == 0L)
+    {
+        CheckIfServerIsUp(m_dwPort, &dwProcessId, &fReady);
+
+        if (!fReady)
+        {
+            m_pProcessManager->ShutdownProcess(this);
+        }
+
+        DereferenceServerProcess();
+    }
+
+    return hr;
+}
+
+HRESULT
+SERVER_PROCESS::SendShutdownHttpMessage()
+{
+    HRESULT    hr = S_OK;
+    HINTERNET  hSession = NULL,
+               hConnect = NULL,
+               hRequest = NULL;
+
+    STACK_STRU(strHeaders, 256);
+    STRU       strAppToken;
+    STRU       strUrl;
+    DWORD      dwStatusCode = 0;
+    DWORD      dwSize = sizeof(dwStatusCode);
+
+    LPCWSTR   apsz[1];
+    STACK_STRU(strEventMsg, 256);
+
+    hSession = WinHttpOpen(L"",
+        WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
+        WINHTTP_NO_PROXY_NAME,
+        WINHTTP_NO_PROXY_BYPASS,
+        0);
+
+    if (hSession == NULL)
+    {
+        hr = HRESULT_FROM_WIN32(GetLastError());
+        goto Finished;
+    }
+
+    hConnect = WinHttpConnect(hSession,
+        L"127.0.0.1",
+        (USHORT)m_dwPort,
+        0);
+
+    if (hConnect == NULL)
+    {
+        hr = HRESULT_FROM_WIN32(GetLastError());
+        goto Finished;
+    }
+    if (m_struAppPath.QueryCCH() > 1) 
+    {
+        // app path size is 1 means site root, i.e., "/"
+        // we don't want to add duplicated '/' to the request url
+        // otherwise the request will fail
+        strUrl.Copy(m_struAppPath);
+    }
+    strUrl.Append(L"/iisintegration");
+
+    hRequest = WinHttpOpenRequest(hConnect,
+        L"POST",
+        strUrl.QueryStr(),
+        NULL,
+        WINHTTP_NO_REFERER,
+        NULL,
+        0);
+
+    if (hRequest == NULL)
+    {
+        hr = HRESULT_FROM_WIN32(GetLastError());
+        goto Finished;
+    }
+
+    // set timeout
+    if (!WinHttpSetTimeouts(hRequest,
+        m_dwShutdownTimeLimitInMS,  // dwResolveTimeout
+        m_dwShutdownTimeLimitInMS,  // dwConnectTimeout
+        m_dwShutdownTimeLimitInMS,  // dwSendTimeout
+        m_dwShutdownTimeLimitInMS)) // dwReceiveTimeout
+    {
+        hr = HRESULT_FROM_WIN32(GetLastError());
+        goto Finished;
+    }
+
+    // set up the shutdown headers
+    if (FAILED(hr = strHeaders.Append(L"MS-ASPNETCORE-EVENT:shutdown \r\n")) ||
+        FAILED(hr = strAppToken.Append(L"MS-ASPNETCORE-TOKEN:")) ||
+        FAILED(hr = strAppToken.AppendA(m_straGuid.QueryStr())) ||
+        FAILED(hr = strHeaders.Append(strAppToken.QueryStr())))
+    {
+        goto Finished;
+    }
+
+    if (!WinHttpSendRequest(hRequest,
+        strHeaders.QueryStr(),  // pwszHeaders
+        strHeaders.QueryCCH(),  // dwHeadersLength
+        WINHTTP_NO_REQUEST_DATA,
+        0,   // dwOptionalLength
+        0,   // dwTotalLength
+        0))  // dwContext
+    {
+        hr = HRESULT_FROM_WIN32(GetLastError());
+        goto Finished;
+    }
+
+    if (!WinHttpReceiveResponse(hRequest , NULL))
+    {
+        hr = HRESULT_FROM_WIN32(GetLastError());
+        goto Finished;
+    }
+
+    if (!WinHttpQueryHeaders(hRequest,
+        WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER,
+        WINHTTP_HEADER_NAME_BY_INDEX,
+        &dwStatusCode,
+        &dwSize,
+        WINHTTP_NO_HEADER_INDEX))
+    {
+        hr = HRESULT_FROM_WIN32(GetLastError());
+        goto Finished;
+    }
+
+    if (dwStatusCode != 202)
+    {
+        // not expected http status
+        hr = E_FAIL;
+    }
+
+    // log
+    if (SUCCEEDED(strEventMsg.SafeSnwprintf(
+        ASPNETCORE_EVENT_SENT_SHUTDOWN_HTTP_REQUEST_MSG,
+        m_dwProcessId,
+        dwStatusCode)))
+    {
+        apsz[0] = strEventMsg.QueryStr();
+        if (FORWARDING_HANDLER::QueryEventLog() != NULL)
+        {
+            ReportEventW(FORWARDING_HANDLER::QueryEventLog(),
+                EVENTLOG_INFORMATION_TYPE,
+                0,
+                ASPNETCORE_EVENT_SENT_SHUTDOWN_HTTP_REQUEST,
+                NULL,
+                1,
+                0,
+                apsz,
+                NULL);
+        }
+    }
+
+Finished:
+    if (hRequest)
+    {
+        WinHttpCloseHandle(hRequest);
+        hRequest = NULL;
+    }
+    if (hConnect)
+    {
+        WinHttpCloseHandle(hConnect);
+        hConnect = NULL;
+    }
+    if (hSession)
+    {
+        WinHttpCloseHandle(hSession);
+        hSession = NULL;
+    }
+    return hr;
+}
+
+//static
+VOID
+SERVER_PROCESS::SendShutDownSignal(
+    LPVOID lpParam
+)
+{
+    SERVER_PROCESS* pThis = static_cast<SERVER_PROCESS *>(lpParam);
+    DBG_ASSERT(pThis);
+    pThis->SendShutDownSignalInternal();
+}
+
+//
+// send shutdown message first, if fail then send
+// ctrl-c to the backend process to let it gracefully shutdown
+//
+VOID
+SERVER_PROCESS::SendShutDownSignalInternal(
+    VOID
+)
+{
+    ReferenceServerProcess();
+
+    if (FAILED(SendShutdownHttpMessage()))
+    {
+        //
+        // failed to send shutdown http message
+        // try send ctrl signal
+        //
+        HWND  hCurrentConsole = NULL;
+        BOOL  fFreeConsole = FALSE;
+        hCurrentConsole = GetConsoleWindow();
+        if (hCurrentConsole)
+        {
+            // free current console first, as we may have one, e.g., hostedwebcore case
+            fFreeConsole = FreeConsole();
+        }
+
+        if (AttachConsole(m_dwProcessId))
+        {
+            // call ctrl-break instead of ctrl-c as child process may ignore ctrl-c
+            if (!GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, m_dwProcessId))
+            {
+                // failed to send the ctrl signal. terminate the backend process immediately instead of waiting for timeout
+                TerminateBackendProcess();
+            }
+            FreeConsole();
+
+            if (fFreeConsole)
+            {
+                // IISExpress and hostedwebcore w3wp run as background process
+                // have to attach console back to ensure post app_offline scenario still works
+                AttachConsole(ATTACH_PARENT_PROCESS);
+            }
+        }
+        else
+        {
+            // terminate the backend process immediately instead of waiting for timeout
+            TerminateBackendProcess();
+        }
+    }
+
+    DereferenceServerProcess();
+}
+
+VOID
+SERVER_PROCESS::TerminateBackendProcess(
+    VOID
+)
+{
+    LPCWSTR   apsz[1];
+    STACK_STRU(strEventMsg, 256);
+
+    if (InterlockedCompareExchange(&m_lStopping, 1L, 0L) == 0L)
+    {
+        // backend process will be terminated, remove the waitcallback
+        if (m_hProcessWaitHandle != NULL)
+        {
+            UnregisterWait(m_hProcessWaitHandle);
+            m_hProcessWaitHandle = NULL;
+        }
+
+        // cannot gracefully shutdown or timeout, terminate the process
+        if (m_hProcessHandle != NULL && m_hProcessHandle != INVALID_HANDLE_VALUE)
+        {
+            TerminateProcess(m_hProcessHandle, 0);
+            m_hProcessHandle = NULL;
+        }
+
+        // as we skipped process exit callback (ProcessHandleCallback), 
+        // need to dereference the object otherwise memory leak
+        DereferenceServerProcess();
+
+        // log a warning for ungraceful shutdown
+        if (SUCCEEDED(strEventMsg.SafeSnwprintf(
+            ASPNETCORE_EVENT_GRACEFUL_SHUTDOWN_FAILURE_MSG,
+            m_dwProcessId)))
+        {
+            apsz[0] = strEventMsg.QueryStr();
+            if (FORWARDING_HANDLER::QueryEventLog() != NULL)
+            {
+                ReportEventW(FORWARDING_HANDLER::QueryEventLog(),
+                    EVENTLOG_WARNING_TYPE,
+                    0,
+                    ASPNETCORE_EVENT_GRACEFUL_SHUTDOWN_FAILURE,
+                    NULL,
+                    1,
+                    0,
+                    apsz,
+                    NULL);
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/src/websockethandler.cxx b/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/src/websockethandler.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..7adc14c9159f7d24c78ea93942d146b5cbb6a716
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/src/websockethandler.cxx
@@ -0,0 +1,1169 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+/*++
+
+Abstract:
+
+    Main Handler for websocket requests.
+
+    Initiates websocket connection to backend.
+    Uses WinHttp API's for backend connections,
+    and IIS Websocket API's for sending/receiving
+    websocket traffic.
+
+    Transfers data between the two IO endpoints.
+
+-----------------
+Read Loop Design
+-----------------
+When a read IO completes successfully on any endpoints, Asp.Net Core Module doesn't
+immediately issue the next read. The next read is initiated only after
+the read data is sent to the other endpoint. As soon as this send completes,
+we initiate the next IO. It should be noted that the send complete merely
+indicates the API completion from HTTP, and not necessarily over the network.
+
+This prevents the need for data buffering at the Asp.Net Core Module level.
+
+--*/
+
+#include "precomp.hxx"
+
+SRWLOCK WEBSOCKET_HANDLER::sm_RequestsListLock;
+
+LIST_ENTRY WEBSOCKET_HANDLER::sm_RequestsListHead;
+
+TRACE_LOG * WEBSOCKET_HANDLER::sm_pTraceLog;
+
+WEBSOCKET_HANDLER::WEBSOCKET_HANDLER():
+    _pHttpContext ( NULL ),
+    _pWebSocketContext ( NULL ),
+    _hWebSocketRequest( NULL ),
+    _pHandler ( NULL ),
+    _dwOutstandingIo ( 0 ),
+    _fCleanupInProgress ( FALSE ),
+    _fIndicateCompletionToIis ( FALSE ),
+    _fHandleClosed( FALSE ),
+    _fReceivedCloseMsg ( FALSE )
+{
+    DebugPrintf (ASPNETCORE_DEBUG_FLAG_INFO, "WEBSOCKET_HANDLER::WEBSOCKET_HANDLER");
+
+    InitializeCriticalSectionAndSpinCount(&_RequestLock, 1000);
+
+    InsertRequest();
+}
+
+WEBSOCKET_HANDLER::~WEBSOCKET_HANDLER()
+{
+    DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO, "WEBSOCKET_HANDLER::~WEBSOCKET_HANDLER");
+    RemoveRequest();
+    DeleteCriticalSection(&_RequestLock);
+}
+
+VOID
+WEBSOCKET_HANDLER::Terminate(
+    VOID
+    )
+{
+    DebugPrintf (ASPNETCORE_DEBUG_FLAG_INFO, "WEBSOCKET_HANDLER::Terminate");
+    if (!_fHandleClosed)
+    {
+        EnterCriticalSection(&_RequestLock);
+        _fCleanupInProgress = TRUE;
+        if (_pHttpContext != NULL)
+        {
+            _pHttpContext->CancelIo();
+            _pHttpContext = NULL;
+        }
+
+        if (_hWebSocketRequest != NULL)
+        {
+            WinHttpCloseHandle(_hWebSocketRequest);
+            _hWebSocketRequest = NULL;
+        }
+
+        _fHandleClosed = TRUE;
+        LeaveCriticalSection(&_RequestLock);
+    }
+}
+
+//static
+HRESULT
+WEBSOCKET_HANDLER::StaticInitialize(
+    BOOL   fEnableReferenceCountTracing
+    )
+/*++ 
+
+    Routine Description:
+
+    Initialize structures required for idle connection cleanup.
+
+--*/
+{
+    if (!g_fWebSocketSupported)
+    {
+        return S_OK;
+    }
+
+    if (fEnableReferenceCountTracing)
+    {
+        //
+        // If tracing is enabled, keep track of all websocket requests
+        // for debugging purposes.
+        //
+
+        InitializeListHead (&sm_RequestsListHead);
+        sm_pTraceLog = CreateRefTraceLog( 10000, 0 );
+    }
+
+    return S_OK;
+}
+
+//static
+VOID
+WEBSOCKET_HANDLER::StaticTerminate(
+    VOID
+    )
+{
+    if (!g_fWebSocketSupported)
+    {
+        return;
+    }
+
+    if (sm_pTraceLog)
+    {
+        DestroyRefTraceLog(sm_pTraceLog);
+        sm_pTraceLog = NULL;
+    }
+}
+
+VOID
+WEBSOCKET_HANDLER::InsertRequest(
+    VOID
+    )
+{
+    if (g_fEnableReferenceCountTracing)
+    {
+        AcquireSRWLockExclusive(&sm_RequestsListLock);
+
+        InsertTailList(&sm_RequestsListHead, &_listEntry);
+
+        ReleaseSRWLockExclusive( &sm_RequestsListLock);
+    }
+}
+
+//static 
+VOID
+WEBSOCKET_HANDLER::RemoveRequest(
+    VOID
+    )
+{
+    if (g_fEnableReferenceCountTracing)
+    {
+        AcquireSRWLockExclusive(&sm_RequestsListLock);
+
+        RemoveEntryList(&_listEntry);
+
+        ReleaseSRWLockExclusive( &sm_RequestsListLock);
+    }
+}
+
+VOID
+WEBSOCKET_HANDLER::IncrementOutstandingIo(
+    VOID
+    )
+{
+    LONG dwOutstandingIo = InterlockedIncrement(&_dwOutstandingIo);
+
+    if (sm_pTraceLog)
+    {
+        WriteRefTraceLog(sm_pTraceLog, dwOutstandingIo, this);
+    }
+}
+
+VOID
+WEBSOCKET_HANDLER::DecrementOutstandingIo(
+    VOID
+    )
+/*++
+    Routine Description:
+    Decrements outstanding IO count.
+
+    This indicates completion to IIS if all outstanding IO
+    has been completed, and a Cleanup was triggered for this
+    connection (denoted by _fIndicateCompletionToIis).
+
+--*/
+{
+    LONG dwOutstandingIo = InterlockedDecrement (&_dwOutstandingIo);
+
+    if (sm_pTraceLog)
+    {
+        WriteRefTraceLog(sm_pTraceLog, dwOutstandingIo, this);
+    }
+
+    if (dwOutstandingIo == 0 && _fIndicateCompletionToIis)
+    {
+        IndicateCompletionToIIS();
+    }
+}
+
+VOID
+WEBSOCKET_HANDLER::IndicateCompletionToIIS(
+    VOID
+    )
+/*++
+    Routine Description:
+    Indicates completion to IIS.
+
+    This returns a Pending Status, so that forwarding handler has a chance
+    to do book keeping when request is finally done.
+
+--*/
+{
+    DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO,
+        "WEBSOCKET_HANDLER::IndicateCompletionToIIS called %d", _dwOutstandingIo);
+    //
+    // close Websocket handle. This will triger a WinHttp callback
+    // on handle close, then let IIS pipeline continue.
+    // Make sure no pending IO as there is no IIS websocket cancelation,
+    // any unexpected callback will lead to AV. Revisit it once CanelOutGoingIO works
+    //
+    if (_hWebSocketRequest != NULL && _dwOutstandingIo == 0)
+    {
+        DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO,
+            "WEBSOCKET_HANDLER::IndicateCompletionToIIS");
+
+        _pHandler->SetStatus(FORWARDER_DONE);
+        _fHandleClosed = TRUE;
+        WinHttpCloseHandle(_hWebSocketRequest);
+        _hWebSocketRequest = NULL;
+    }
+}
+
+HRESULT
+WEBSOCKET_HANDLER::ProcessRequest(
+    FORWARDING_HANDLER *pHandler,
+    IHttpContext *pHttpContext,
+    HINTERNET     hRequest,
+    BOOL*         fHandleCreated
+)
+/*++
+
+Routine Description:
+
+    Entry point to WebSocket Handler:
+    
+    This routine is called after the 101 response was successfully sent to
+    the client. 
+    This routine get's a websocket handle to winhttp, 
+    websocket handle to IIS's websocket context, and initiates IO 
+    in these two endpoints.
+
+
+--*/
+{
+    HRESULT hr = S_OK;
+    //DWORD dwBuffSize = RECEIVE_BUFFER_SIZE;
+
+    _pHandler = pHandler;
+
+    EnterCriticalSection(&_RequestLock);
+
+    DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO,
+        "WEBSOCKET_HANDLER::ProcessRequest");
+
+    //
+    // Cache the points to IHttpContext3
+    //
+
+    hr = HttpGetExtendedInterface(g_pHttpServer, 
+            pHttpContext, 
+            &_pHttpContext);
+    if (FAILED (hr))
+    {
+        goto Finished;
+    }
+
+    //
+    // Get pointer to IWebSocketContext for IIS websocket IO.
+    //
+
+     _pWebSocketContext = (IWebSocketContext *) _pHttpContext->
+        GetNamedContextContainer()->GetNamedContext(IIS_WEBSOCKET);
+    if ( _pWebSocketContext == NULL )
+    {
+        hr = HRESULT_FROM_WIN32( ERROR_FILE_NOT_FOUND );
+        goto Finished;
+    }
+
+    //
+    // Get Handle to Winhttp's websocket context.
+    //
+
+    _hWebSocketRequest = WINHTTP_HELPER::sm_pfnWinHttpWebSocketCompleteUpgrade(
+        hRequest,
+        (DWORD_PTR) pHandler);
+
+    if (_hWebSocketRequest == NULL)
+    {
+        hr = HRESULT_FROM_WIN32(GetLastError());
+        goto Finished;
+    }
+
+    *fHandleCreated = TRUE;
+    //
+    // Resize the send & receive buffers to be more conservative (and avoid DoS attacks).
+    // NOTE: The two WinHTTP options below were added for WinBlue, so we can't
+    // rely on their existence.
+    //
+
+    //if (!WinHttpSetOption(_hWebSocketRequest,
+    //                      WINHTTP_OPTION_WEB_SOCKET_RECEIVE_BUFFER_SIZE,
+    //                      &dwBuffSize,
+    //                      sizeof(dwBuffSize)))
+    //{
+    //    DWORD dwRet = GetLastError();
+    //    if ( dwRet != ERROR_WINHTTP_INVALID_OPTION )
+    //    {
+    //        hr = HRESULT_FROM_WIN32(dwRet);
+    //        goto Finished;
+    //    }
+    //}
+
+    //if (!WinHttpSetOption(_hWebSocketRequest,
+    //                      WINHTTP_OPTION_WEB_SOCKET_SEND_BUFFER_SIZE,
+    //                      &dwBuffSize,
+    //                      sizeof(dwBuffSize)))
+    //{
+    //    DWORD dwRet = GetLastError();
+    //    if ( dwRet != ERROR_WINHTTP_INVALID_OPTION )
+    //    {
+    //        hr = HRESULT_FROM_WIN32(dwRet);
+    //        goto Finished;
+    //    }
+    //}
+
+    //
+    // Initiate Read on IIS
+    //
+
+    hr = DoIisWebSocketReceive();
+    if (FAILED(hr))
+    {
+        goto Finished;
+    }
+
+    //
+    // Initiate Read on WinHttp
+    //
+
+    hr = DoWinHttpWebSocketReceive();
+    if (FAILED(hr))
+    {
+        goto Finished;
+    }
+
+Finished:
+    LeaveCriticalSection(&_RequestLock);
+
+    if (FAILED (hr))
+    {
+        DebugPrintf (ASPNETCORE_DEBUG_FLAG_ERROR,
+            "Process Request Failed with HR=%08x", hr);
+    }
+
+    return hr;
+}
+
+HRESULT
+WEBSOCKET_HANDLER::DoIisWebSocketReceive(
+    VOID
+)
+/*++
+
+Routine Description:
+
+    Initiates a websocket receive on the IIS Websocket Context.
+
+
+--*/
+{
+    HRESULT hr = S_OK;
+
+    DWORD   dwBufferSize = RECEIVE_BUFFER_SIZE;
+    BOOL    fUtf8Encoded;
+    BOOL    fFinalFragment;
+    BOOL    fClose;
+
+    DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO,
+        "WEBSOCKET_HANDLER::DoIisWebSocketReceive");
+
+    IncrementOutstandingIo();
+
+    hr = _pWebSocketContext->ReadFragment(
+            &_IisReceiveBuffer,
+            &dwBufferSize,
+            TRUE,
+            &fUtf8Encoded,
+            &fFinalFragment,
+            &fClose,
+            OnReadIoCompletion,
+            this,
+            NULL);
+    if (FAILED(hr))
+    {
+        DecrementOutstandingIo();
+
+        DebugPrintf(ASPNETCORE_DEBUG_FLAG_ERROR,
+            "WEBSOCKET_HANDLER::DoIisWebSocketSend failed with %08x", hr);
+
+    }
+
+    return hr;
+}
+
+HRESULT
+WEBSOCKET_HANDLER::DoWinHttpWebSocketReceive(
+    VOID
+)
+/*++
+
+Routine Description:
+
+    Initiates a websocket receive on WinHttp
+
+
+--*/
+{
+    HRESULT hr = S_OK;
+    DWORD   dwError = NO_ERROR;
+
+    DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO,
+        "WEBSOCKET_HANDLER::DoWinHttpWebSocketReceive");
+
+    IncrementOutstandingIo();
+
+    dwError = WINHTTP_HELPER::sm_pfnWinHttpWebSocketReceive(
+                _hWebSocketRequest,
+                &_WinHttpReceiveBuffer,
+                RECEIVE_BUFFER_SIZE,
+                NULL,
+                NULL);
+
+    if (dwError != NO_ERROR)
+    {
+        DecrementOutstandingIo();
+
+        hr = HRESULT_FROM_WIN32(dwError);
+
+        DebugPrintf(ASPNETCORE_DEBUG_FLAG_ERROR,
+            "WEBSOCKET_HANDLER::DoWinHttpWebSocketReceive failed with %08x", hr);
+
+    }
+
+    return hr;
+}
+
+HRESULT
+WEBSOCKET_HANDLER::DoIisWebSocketSend(
+    DWORD cbData,
+    WINHTTP_WEB_SOCKET_BUFFER_TYPE  eBufferType
+)
+/*++
+
+Routine Description:
+
+    Initiates a websocket send on IIS
+
+--*/
+{
+    HRESULT hr = S_OK;
+
+    BOOL    fUtf8Encoded = FALSE;
+    BOOL    fFinalFragment = FALSE;
+    BOOL    fClose = FALSE;
+
+    DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO,
+        "WEBSOCKET_HANDLER::DoIisWebSocketSend  %d", eBufferType);
+
+    if (eBufferType == WINHTTP_WEB_SOCKET_CLOSE_BUFFER_TYPE)
+    {
+        //
+        // Query Close Status from WinHttp
+        //
+
+        DWORD dwError = NO_ERROR;
+        USHORT uStatus;
+        DWORD  dwReceived = 0;
+        STACK_STRU(strCloseReason, 128);
+
+        dwError = WINHTTP_HELPER::sm_pfnWinHttpWebSocketQueryCloseStatus(
+                    _hWebSocketRequest,
+                    &uStatus,
+                    &_WinHttpReceiveBuffer,
+                    RECEIVE_BUFFER_SIZE,
+                    &dwReceived);
+
+        if (dwError != NO_ERROR)
+        {
+            hr = HRESULT_FROM_WIN32(dwError);
+            goto Finished;
+        }
+
+        //
+        // Convert close reason to WCHAR
+        //
+
+        hr = strCloseReason.CopyA((PCSTR)&_WinHttpReceiveBuffer,
+            dwReceived);
+        if (FAILED(hr))
+        {
+            goto Finished;
+        }
+
+        IncrementOutstandingIo();
+
+        //
+        // Backend end may start close hand shake first
+        // Need to inidcate no more receive should be called on WinHttp connection
+        //
+        _fReceivedCloseMsg = TRUE;
+        _fIndicateCompletionToIis = TRUE;
+
+        //
+        // Send close to IIS.
+        //
+
+        hr = _pWebSocketContext->SendConnectionClose(
+            TRUE,
+            uStatus,
+            uStatus == 1005 ? NULL : strCloseReason.QueryStr(),
+            OnWriteIoCompletion,
+            this,
+            NULL);
+    }
+    else
+    {
+        //
+        // Get equivalant flags for IIS API from buffer type.
+        //
+
+        WINHTTP_HELPER::GetFlagsFromBufferType(eBufferType,
+            &fUtf8Encoded,
+            &fFinalFragment,
+            &fClose);
+
+        IncrementOutstandingIo();
+
+        //
+        // Do the Send.
+        //
+
+        hr = _pWebSocketContext->WriteFragment(
+                &_WinHttpReceiveBuffer,
+                &cbData,
+                TRUE,
+                fUtf8Encoded,
+                fFinalFragment,
+                OnWriteIoCompletion,
+                this,
+                NULL);
+
+    }
+
+    if (FAILED(hr))
+    {
+        DecrementOutstandingIo();
+    }
+
+Finished:
+    if (FAILED(hr))
+    {
+        DebugPrintf(ASPNETCORE_DEBUG_FLAG_ERROR,
+            "WEBSOCKET_HANDLER::DoIisWebSocketSend failed with %08x", hr);
+    }
+
+    return hr;
+}
+
+HRESULT
+WEBSOCKET_HANDLER::DoWinHttpWebSocketSend(
+    DWORD cbData,
+    WINHTTP_WEB_SOCKET_BUFFER_TYPE  eBufferType
+)
+/*++
+
+Routine Description:
+
+    Initiates a websocket send on WinHttp
+
+--*/
+{
+    DWORD       dwError = NO_ERROR;
+    HRESULT     hr = S_OK;
+
+    DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO,
+        "WEBSOCKET_HANDLER::DoWinHttpWebSocketSend, %d", eBufferType);
+
+    if (eBufferType == WINHTTP_WEB_SOCKET_CLOSE_BUFFER_TYPE)
+    {
+        USHORT  uStatus;
+        LPCWSTR pszReason;
+        STACK_STRA(strCloseReason, 128);
+
+        //
+        // Get Close status from IIS.
+        //
+
+        hr = _pWebSocketContext->GetCloseStatus(&uStatus, 
+                &pszReason);
+
+        if (FAILED(hr))
+        {
+            goto Finished;
+        }
+
+        //
+        // Convert status to UTF8
+        //
+
+        hr = strCloseReason.CopyWToUTF8Unescaped(pszReason);
+        if (FAILED(hr))
+        {
+            goto Finished;
+        }
+
+        IncrementOutstandingIo();
+
+        //
+        // Send Close.
+        //
+
+        dwError = WINHTTP_HELPER::sm_pfnWinHttpWebSocketShutdown(
+            _hWebSocketRequest,
+            uStatus,
+            strCloseReason.QueryCCH() == 0 ? NULL : (PVOID) strCloseReason.QueryStr(),
+            strCloseReason.QueryCCH());
+
+        if (dwError == ERROR_IO_PENDING)
+        {
+            //
+            // Call will complete asynchronously, return.
+            // ignore error.
+            //
+
+            DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO,
+                "WEBSOCKET_HANDLER::DoWinhttpWebSocketSend IO_PENDING");
+
+            dwError = NO_ERROR;
+        }
+        else
+        {
+            if (dwError == NO_ERROR)
+            {
+                //
+                // Call completed synchronously.
+                //
+
+                DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO,
+                "WEBSOCKET_HANDLER::DoWinhttpWebSocketSend Shutdown successful.");
+            }
+        }
+    }
+    else
+    {
+        IncrementOutstandingIo();
+
+        dwError = WINHTTP_HELPER::sm_pfnWinHttpWebSocketSend(
+                        _hWebSocketRequest,
+                        eBufferType,
+                        cbData == 0 ? NULL : &_IisReceiveBuffer,
+                        cbData
+                        );
+    }
+
+    if (dwError != NO_ERROR)
+    {
+        hr = HRESULT_FROM_WIN32(dwError);
+        DecrementOutstandingIo();
+        goto Finished;
+    }
+
+Finished:
+    if (FAILED(hr))
+    {
+        DebugPrintf(ASPNETCORE_DEBUG_FLAG_ERROR,
+            "WEBSOCKET_HANDLER::DoWinHttpWebSocketSend failed with %08x", hr);
+    }
+
+    return hr;
+}
+
+//static
+VOID
+WINAPI
+WEBSOCKET_HANDLER::OnReadIoCompletion(
+    HRESULT     hrError,
+    VOID *      pvCompletionContext,
+    DWORD       cbIO,
+    BOOL        fUTF8Encoded,
+    BOOL        fFinalFragment,
+    BOOL        fClose
+    )
+/*++
+
+ Routine Description:
+
+     Completion routine for Read's from IIS pipeline.
+
+--*/
+{
+    WEBSOCKET_HANDLER *     pHandler = (WEBSOCKET_HANDLER *) 
+                            pvCompletionContext;
+
+    pHandler->OnIisReceiveComplete(
+        hrError,
+        cbIO,
+        fUTF8Encoded,
+        fFinalFragment,
+        fClose
+        );
+}
+
+//static
+VOID
+WINAPI
+WEBSOCKET_HANDLER::OnWriteIoCompletion(
+    HRESULT     hrError,
+    VOID *      pvCompletionContext,
+    DWORD       cbIO,
+    BOOL        fUTF8Encoded,
+    BOOL        fFinalFragment,
+    BOOL        fClose
+    )
+/*++
+ Routine Description:
+
+     Completion routine for Write's from IIS pipeline.
+
+--*/
+{
+    WEBSOCKET_HANDLER *     pHandler = (WEBSOCKET_HANDLER *) 
+                            pvCompletionContext;
+
+    UNREFERENCED_PARAMETER(fUTF8Encoded);
+    UNREFERENCED_PARAMETER(fFinalFragment);
+    UNREFERENCED_PARAMETER(fClose);
+
+    pHandler->OnIisSendComplete(
+        hrError,
+        cbIO
+        );
+}
+
+
+HRESULT
+WEBSOCKET_HANDLER::OnWinHttpSendComplete(
+    WINHTTP_WEB_SOCKET_STATUS *
+    )
+/*++
+
+Routine Description:
+    Completion callback executed when a send to backend
+    server completes.
+
+    If the send was successful, issue the next read
+    on the client's endpoint.
+
+++*/
+{
+    HRESULT                 hr = S_OK;
+    BOOL                    fLocked = FALSE;
+    CleanupReason           cleanupReason = CleanupReasonUnknown;
+
+    DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO,
+        "WEBSOCKET_HANDLER::OnWinHttpSendComplete");
+
+    if (_fCleanupInProgress)
+    {
+        goto Finished;
+    }
+
+    EnterCriticalSection (&_RequestLock);
+
+    fLocked = TRUE;
+
+    if (_fCleanupInProgress)
+    {
+        goto Finished;
+    }
+    //
+    // Data was successfully sent to backend.
+    // Initiate next receive from IIS.
+    //
+
+    hr = DoIisWebSocketReceive();
+    if (FAILED(hr))
+    {
+        goto Finished;
+    }
+
+Finished:
+    if (fLocked) 
+    {
+        LeaveCriticalSection(&_RequestLock);
+    }
+
+    if (FAILED (hr))
+    {
+        Cleanup (cleanupReason);
+
+        DebugPrintf (ASPNETCORE_DEBUG_FLAG_ERROR,
+            "WEBSOCKET_HANDLER::OnWinsockSendComplete failed with HR=%08x", hr);
+    }
+
+    //
+    // The handler object can be gone after this call.
+    // do not reference it after this statement.
+    //
+
+    DecrementOutstandingIo();
+
+    return hr;
+}
+
+HRESULT
+WEBSOCKET_HANDLER::OnWinHttpShutdownComplete(
+    VOID
+    )
+{
+    DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO,
+        "WEBSOCKET_HANDLER::OnWinHttpShutdownComplete --%p", _pHandler);
+
+    DecrementOutstandingIo();
+
+    return S_OK;
+}
+
+HRESULT
+WEBSOCKET_HANDLER::OnWinHttpIoError(
+    WINHTTP_WEB_SOCKET_ASYNC_RESULT *pCompletionStatus
+)
+{
+    HRESULT hr = HRESULT_FROM_WIN32(pCompletionStatus->AsyncResult.dwError);
+
+    DebugPrintf(ASPNETCORE_DEBUG_FLAG_ERROR,
+        "WEBSOCKET_HANDLER::OnWinHttpIoError HR = %08x, Operation = %d",
+        hr, pCompletionStatus->AsyncResult.dwResult);
+
+    Cleanup(ServerDisconnect);
+
+    DecrementOutstandingIo();
+
+    return hr;
+}
+
+HRESULT
+WEBSOCKET_HANDLER::OnWinHttpReceiveComplete(
+    WINHTTP_WEB_SOCKET_STATUS * pCompletionStatus
+    )
+/*++
+
+Routine Description:
+
+    Completion callback executed when a receive completes
+    on the backend server winhttp endpoint.
+
+    Issue send on the Client(IIS) if the receive was
+    successful.
+
+    If the receive completed with zero bytes, that 
+    indicates that the server has disconnected the connection.
+    Issue cleanup for the websocket handler.
+--*/
+{
+    HRESULT  hr = S_OK;
+    BOOL     fLocked = FALSE;
+    CleanupReason cleanupReason = CleanupReasonUnknown;
+
+    DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO,
+        "WEBSOCKET_HANDLER::OnWinHttpReceiveComplete, %d", _fCleanupInProgress);
+
+    if (_fCleanupInProgress)
+    {
+        goto Finished;
+    }
+
+    EnterCriticalSection(&_RequestLock);
+
+    fLocked = TRUE;
+    if (_fCleanupInProgress)
+    {
+        goto Finished;
+    }
+    hr = DoIisWebSocketSend(
+            pCompletionStatus->dwBytesTransferred,
+            pCompletionStatus->eBufferType
+            );
+
+    if (FAILED (hr))
+    {
+        cleanupReason = ClientDisconnect;
+        goto Finished;
+    }
+
+Finished:
+    if (fLocked) 
+    {
+        LeaveCriticalSection(&_RequestLock);
+    }
+    if (FAILED (hr))
+    {
+        Cleanup (cleanupReason);
+
+        DebugPrintf (ASPNETCORE_DEBUG_FLAG_ERROR,
+            "WEBSOCKET_HANDLER::OnWinsockReceiveComplete failed with HR=%08x", hr);
+    }
+
+    //
+    // The handler object can be gone after this call.
+    // do not reference it after this statement.
+    //
+
+    DecrementOutstandingIo();
+
+    return hr;
+}
+
+HRESULT
+WEBSOCKET_HANDLER::OnIisSendComplete(
+    HRESULT  hrCompletion,
+    DWORD    cbIo
+    )
+/*++
+Routine Description:
+
+    Completion callback executed when a send
+    completes from the client.
+
+    If send was successful,issue read on the 
+    server endpoint, to continue the readloop.
+
+--*/
+{
+    HRESULT         hr = S_OK;
+    BOOL            fLocked = FALSE;
+    CleanupReason   cleanupReason = CleanupReasonUnknown;
+
+    UNREFERENCED_PARAMETER(cbIo);
+
+    DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO, "WEBSOCKET_HANDLER::OnIisSendComplete");
+
+    if (FAILED(hrCompletion))
+    {
+        hr = hrCompletion;
+        cleanupReason = ClientDisconnect;
+        goto Finished;
+    }
+
+    if (_fCleanupInProgress)
+    {
+        goto Finished;
+    }
+    EnterCriticalSection(&_RequestLock);
+    fLocked = TRUE;
+    if (_fCleanupInProgress)
+    {
+        goto Finished;
+    }
+
+    //
+    // Only call read if no close hand shake was received from backend
+    //
+    //if (!_fReceivedCloseMsg)
+    //{
+        //
+        // Write Completed, initiate next read from backend server.
+        //
+        hr = DoWinHttpWebSocketReceive();
+        if (FAILED(hr))
+        {
+            cleanupReason = ServerDisconnect;
+            goto Finished;
+        }
+    //}
+
+Finished:
+    if (fLocked)
+    {
+        LeaveCriticalSection(&_RequestLock);
+    }
+    if (FAILED (hr))
+    {
+        Cleanup (cleanupReason);
+
+        DebugPrintf (ASPNETCORE_DEBUG_FLAG_ERROR,
+            "WEBSOCKET_HANDLER::OnIisSendComplete failed with HR=%08x", hr);
+    }
+
+    //
+    // The handler object can be gone after this call.
+    // do not reference it after this statement.
+    //
+
+    DecrementOutstandingIo();
+
+    return hr;
+}
+
+HRESULT
+WEBSOCKET_HANDLER::OnIisReceiveComplete(
+    HRESULT     hrCompletion,
+    DWORD       cbIO,
+    BOOL        fUTF8Encoded,
+    BOOL        fFinalFragment,
+    BOOL        fClose
+    )
+/*++
+Routine Description:
+
+    Completion routine executed when a receive completes
+    from the client (IIS endpoint).
+
+    If the receive was successful, initiate a send on
+    the backend server (winhttp) endpoint.
+
+    If the receive failed, initiate cleanup.
+
+--*/
+{
+    HRESULT    hr = S_OK;
+    BOOL       fLocked = FALSE;
+    CleanupReason cleanupReason = CleanupReasonUnknown;
+    WINHTTP_WEB_SOCKET_BUFFER_TYPE  BufferType;
+
+    DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO,
+        "WEBSOCKET_HANDLER::OnIisReceiveComplete");
+
+    if (FAILED(hrCompletion))
+    {
+        cleanupReason = ClientDisconnect;
+        hr = hrCompletion;
+        goto Finished;
+    }
+
+    if (_fCleanupInProgress)
+    {
+        goto Finished;
+    }
+
+    EnterCriticalSection(&_RequestLock);
+    fLocked = TRUE;
+
+    if (_fCleanupInProgress)
+    {
+        goto Finished;
+    }
+    //
+    // Get Buffer Type from flags.
+    //
+
+    WINHTTP_HELPER::GetBufferTypeFromFlags(fUTF8Encoded,
+        fFinalFragment,
+        fClose,
+        &BufferType);
+
+    //
+    // Initiate Send.
+    //
+
+    hr =  DoWinHttpWebSocketSend(cbIO, BufferType);
+    if (FAILED (hr))
+    {
+        cleanupReason = ServerDisconnect;
+        goto Finished;
+    }
+
+Finished:
+    if (fLocked)
+    {
+        LeaveCriticalSection(&_RequestLock);
+    }
+    if (FAILED (hr))
+    {
+        Cleanup (cleanupReason);
+
+        DebugPrintf (ASPNETCORE_DEBUG_FLAG_ERROR,
+            "WEBSOCKET_HANDLER::OnIisReceiveComplete failed with HR=%08x", hr);
+    }
+
+    //
+    // The handler object can be gone after this call.
+    // do not reference it after this statement.
+    //
+
+    DecrementOutstandingIo();
+
+    return hr;
+}
+
+VOID
+WEBSOCKET_HANDLER::Cleanup(
+    CleanupReason reason
+)
+/*++
+
+Routine Description:
+
+    Cleanup function for the websocket handler.
+
+    Initiates cancelIo on the two IO endpoints:
+    IIS, WinHttp client.
+
+Arguments:
+    CleanupReason
+--*/
+{
+    BOOL    fLocked = FALSE;
+    DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO,
+        "WEBSOCKET_HANDLER::Cleanup Initiated with reason %d", reason);
+
+    if (_fCleanupInProgress)
+    {
+        goto Finished;
+    }
+
+    EnterCriticalSection(&_RequestLock);
+    fLocked = TRUE;
+
+    if (_fCleanupInProgress)
+    {
+        goto Finished;
+    }
+
+    _fCleanupInProgress = TRUE;
+
+    _fIndicateCompletionToIis = TRUE;
+    //
+    // We need cancel IO for fast error handling
+    // Reivist the code once CanelOutstandingIO api is available
+    //
+    /*if (_pWebSocketContext != NULL) 
+    {
+        _pWebSocketContext->CancelOutstandingIO();
+    }*/
+    _pHttpContext->CancelIo();
+
+    //
+    // Don't close the handle here,
+    // as it trigger a WinHttp callback and let IIS pipeline continue
+    // Handle should be closed only in IndicateCompletionToIIS
+    IndicateCompletionToIIS();
+Finished:
+    if (fLocked)
+    {
+        LeaveCriticalSection(&_RequestLock);
+    }
+
+}
diff --git a/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/src/winhttphelper.cxx b/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/src/winhttphelper.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..8407c45830a28fd546e09e942702d06f29f514cc
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV1/AspNetCore/src/winhttphelper.cxx
@@ -0,0 +1,176 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#include "precomp.hxx"
+
+PFN_WINHTTP_WEBSOCKET_COMPLETE_UPGRADE
+WINHTTP_HELPER::sm_pfnWinHttpWebSocketCompleteUpgrade;
+
+PFN_WINHTTP_WEBSOCKET_SEND
+WINHTTP_HELPER::sm_pfnWinHttpWebSocketSend;
+
+PFN_WINHTTP_WEBSOCKET_RECEIVE
+WINHTTP_HELPER::sm_pfnWinHttpWebSocketReceive;
+
+PFN_WINHTTP_WEBSOCKET_SHUTDOWN
+WINHTTP_HELPER::sm_pfnWinHttpWebSocketShutdown;
+
+PFN_WINHTTP_WEBSOCKET_QUERY_CLOSE_STATUS
+WINHTTP_HELPER::sm_pfnWinHttpWebSocketQueryCloseStatus;
+
+//static
+HRESULT
+WINHTTP_HELPER::StaticInitialize(
+    VOID
+)
+{
+    HRESULT hr = S_OK;
+
+    if (!g_fWebSocketSupported)
+    {
+        return S_OK;
+    }
+
+    //
+    // Initialize the function pointers for WinHttp Websocket API's.
+    //
+
+    HMODULE  hWinHttp = GetModuleHandleA("winhttp.dll");
+    if (hWinHttp == NULL)
+    {
+        hr = HRESULT_FROM_WIN32(GetLastError());
+        goto Finished;
+    }
+
+    sm_pfnWinHttpWebSocketCompleteUpgrade = (PFN_WINHTTP_WEBSOCKET_COMPLETE_UPGRADE) 
+        GetProcAddress(hWinHttp, "WinHttpWebSocketCompleteUpgrade");
+    if (sm_pfnWinHttpWebSocketCompleteUpgrade == NULL)
+    {
+        hr = HRESULT_FROM_WIN32(GetLastError());
+        goto Finished;
+    }
+
+    sm_pfnWinHttpWebSocketQueryCloseStatus = (PFN_WINHTTP_WEBSOCKET_QUERY_CLOSE_STATUS)
+        GetProcAddress(hWinHttp, "WinHttpWebSocketQueryCloseStatus");
+    if (sm_pfnWinHttpWebSocketQueryCloseStatus == NULL)
+    {
+        hr = HRESULT_FROM_WIN32(GetLastError());
+        goto Finished;
+    }
+
+    sm_pfnWinHttpWebSocketReceive = (PFN_WINHTTP_WEBSOCKET_RECEIVE)
+        GetProcAddress(hWinHttp, "WinHttpWebSocketReceive");
+    if (sm_pfnWinHttpWebSocketReceive == NULL)
+    {
+        hr = HRESULT_FROM_WIN32(GetLastError());
+        goto Finished;
+    }
+
+    sm_pfnWinHttpWebSocketSend = (PFN_WINHTTP_WEBSOCKET_SEND)
+        GetProcAddress(hWinHttp, "WinHttpWebSocketSend");
+    if (sm_pfnWinHttpWebSocketSend == NULL)
+    {
+        hr = HRESULT_FROM_WIN32(GetLastError());
+        goto Finished;
+    }
+
+    sm_pfnWinHttpWebSocketShutdown = (PFN_WINHTTP_WEBSOCKET_SHUTDOWN)
+        GetProcAddress(hWinHttp, "WinHttpWebSocketShutdown");
+    if (sm_pfnWinHttpWebSocketShutdown == NULL)
+    {
+        hr = HRESULT_FROM_WIN32(GetLastError());
+        goto Finished;
+    }
+
+Finished:
+    return hr;
+}
+
+
+//static
+VOID
+WINHTTP_HELPER::GetFlagsFromBufferType(
+    __in  WINHTTP_WEB_SOCKET_BUFFER_TYPE   BufferType,
+    __out BOOL *                           pfUtf8Encoded,
+    __out BOOL *                           pfFinalFragment,
+    __out BOOL *                           pfClose
+)
+{
+    switch (BufferType)
+    {
+    case WINHTTP_WEB_SOCKET_BINARY_MESSAGE_BUFFER_TYPE:
+        *pfUtf8Encoded = FALSE;
+        *pfFinalFragment = TRUE;
+        *pfClose = FALSE;
+
+        break;
+
+    case WINHTTP_WEB_SOCKET_BINARY_FRAGMENT_BUFFER_TYPE:
+        *pfUtf8Encoded = FALSE;
+        *pfFinalFragment = FALSE;
+        *pfClose = FALSE;
+
+        break;
+
+    case WINHTTP_WEB_SOCKET_UTF8_MESSAGE_BUFFER_TYPE:
+        *pfUtf8Encoded = TRUE;
+        *pfFinalFragment = TRUE;
+        *pfClose = FALSE;
+
+        break;
+
+    case WINHTTP_WEB_SOCKET_UTF8_FRAGMENT_BUFFER_TYPE:
+        *pfUtf8Encoded = TRUE;
+        *pfFinalFragment = FALSE;
+        *pfClose = FALSE;
+
+        break;
+
+    case WINHTTP_WEB_SOCKET_CLOSE_BUFFER_TYPE:
+        *pfUtf8Encoded = FALSE;
+        *pfFinalFragment = FALSE;
+        *pfClose = TRUE;
+
+        break;
+    }
+}
+
+//static
+VOID
+WINHTTP_HELPER::GetBufferTypeFromFlags(
+    __in  BOOL                             fUtf8Encoded,
+    __in  BOOL                             fFinalFragment,
+    __in  BOOL                             fClose,
+    __out WINHTTP_WEB_SOCKET_BUFFER_TYPE*  pBufferType
+)
+{
+    if (fClose)
+    {
+        *pBufferType = WINHTTP_WEB_SOCKET_CLOSE_BUFFER_TYPE;
+    }
+    else
+    if (fUtf8Encoded)
+    {
+        if (fFinalFragment)
+        {
+            *pBufferType = WINHTTP_WEB_SOCKET_UTF8_MESSAGE_BUFFER_TYPE;
+        }
+        else
+        {
+            *pBufferType = WINHTTP_WEB_SOCKET_UTF8_FRAGMENT_BUFFER_TYPE;
+        }
+    }
+    else
+    {
+        if (fFinalFragment)
+        {
+            *pBufferType = WINHTTP_WEB_SOCKET_BINARY_MESSAGE_BUFFER_TYPE;
+        }
+        else
+        {
+            *pBufferType = WINHTTP_WEB_SOCKET_BINARY_FRAGMENT_BUFFER_TYPE;
+        }
+    }
+
+    return;
+}
\ No newline at end of file
diff --git a/src/IISIntegration/src/AspNetCoreModuleV1/IISLib/IISLib.vcxproj b/src/IISIntegration/src/AspNetCoreModuleV1/IISLib/IISLib.vcxproj
new file mode 100644
index 0000000000000000000000000000000000000000..bb8795992b774a2fdcbd3be71cdf76c95145e17c
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV1/IISLib/IISLib.vcxproj
@@ -0,0 +1,201 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|Win32">
+      <Configuration>Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Debug|x64">
+      <Configuration>Debug</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|x64">
+      <Configuration>Release</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{4787A64F-9A3E-4867-A55A-70CB4B2B2FFE}</ProjectGuid>
+    <Keyword>Win32Proj</Keyword>
+    <RootNamespace>IISLib</RootNamespace>
+    <ProjectName>IISLib</ProjectName>
+    <WindowsTargetPlatformVersion>10.0.15063.0</WindowsTargetPlatformVersion>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+    <ConfigurationType>StaticLibrary</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <PlatformToolset>v141</PlatformToolset>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+    <ConfigurationType>StaticLibrary</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <PlatformToolset>v141</PlatformToolset>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+    <ConfigurationType>StaticLibrary</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <PlatformToolset>v141</PlatformToolset>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+    <ConfigurationType>StaticLibrary</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <PlatformToolset>v141</PlatformToolset>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <OutDir>$(MSBuildProjectDirectory)\bin\$(Configuration)\$(Platform)\</OutDir>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <OutDir>$(MSBuildProjectDirectory)\bin\$(Configuration)\$(Platform)\</OutDir>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <OutDir>$(MSBuildProjectDirectory)\bin\$(Configuration)\$(Platform)\</OutDir>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <OutDir>$(MSBuildProjectDirectory)\bin\$(Configuration)\$(Platform)\</OutDir>
+  </PropertyGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>
+      </PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <SDLCheck>true</SDLCheck>
+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+      <ShowIncludes>false</ShowIncludes>
+      <TreatWarningAsError>true</TreatWarningAsError>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <ClCompile>
+      <PrecompiledHeader>
+      </PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <SDLCheck>true</SDLCheck>
+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+      <ShowIncludes>false</ShowIncludes>
+      <TreatWarningAsError>true</TreatWarningAsError>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <PrecompiledHeader>
+      </PrecompiledHeader>
+      <Optimization>MaxSpeed</Optimization>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+      <ShowIncludes>false</ShowIncludes>
+      <TreatWarningAsError>true</TreatWarningAsError>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <PrecompiledHeader>
+      </PrecompiledHeader>
+      <Optimization>MaxSpeed</Optimization>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+      <ShowIncludes>false</ShowIncludes>
+      <TreatWarningAsError>true</TreatWarningAsError>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemGroup>
+    <ClInclude Include="acache.h" />
+    <ClInclude Include="ahutil.h" />
+    <ClInclude Include="base64.h" />
+    <ClInclude Include="buffer.h" />
+    <ClInclude Include="datetime.h" />
+    <ClInclude Include="dbgutil.h" />
+    <ClInclude Include="hashfn.h" />
+    <ClInclude Include="hashtable.h" />
+    <ClInclude Include="listentry.h" />
+    <ClInclude Include="macros.h" />
+    <ClInclude Include="multisz.h" />
+    <ClInclude Include="multisza.h" />
+    <ClInclude Include="ntassert.h" />
+    <ClInclude Include="percpu.h" />
+    <ClInclude Include="precomp.h" />
+    <ClInclude Include="prime.h" />
+    <ClInclude Include="pudebug.h" />
+    <ClInclude Include="reftrace.h" />
+    <ClInclude Include="rwlock.h" />
+    <ClInclude Include="stringa.h" />
+    <ClInclude Include="stringu.h" />
+    <ClInclude Include="tracelog.h" />
+    <ClInclude Include="treehash.h" />
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="acache.cxx" />
+    <ClCompile Include="ahutil.cpp" />
+    <ClCompile Include="base64.cpp" />
+    <ClCompile Include="multisz.cpp" />
+    <ClCompile Include="multisza.cpp" />
+    <ClCompile Include="reftrace.c" />
+    <ClCompile Include="stringa.cpp" />
+    <ClCompile Include="stringu.cpp" />
+    <ClCompile Include="tracelog.c" />
+    <ClCompile Include="util.cxx" />
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  </ImportGroup>
+</Project>
\ No newline at end of file
diff --git a/src/IISIntegration/src/AspNetCoreModuleV1/IISLib/acache.cxx b/src/IISIntegration/src/AspNetCoreModuleV1/IISLib/acache.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..d68813edbc929d410559ec5ec949ea2953f367c2
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV1/IISLib/acache.cxx
@@ -0,0 +1,443 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#include "precomp.h"
+
+LONG    ALLOC_CACHE_HANDLER::sm_nFillPattern = 0xACA50000;
+HANDLE  ALLOC_CACHE_HANDLER::sm_hHeap;
+
+//
+// This class is used to implement the free list.  We cast the free'd
+// memory block to a FREE_LIST_HEADER*.  The signature is used to guard against
+// double deletion.  We also fill memory with a pattern.
+//
+class FREE_LIST_HEADER
+{
+public:
+    SLIST_ENTRY     ListEntry;
+    DWORD           dwSignature;
+
+    enum
+    {
+        FREE_SIGNATURE = (('A') | ('C' << 8) | ('a' << 16) | (('$' << 24) | 0x80)),
+    };
+};
+
+ALLOC_CACHE_HANDLER::ALLOC_CACHE_HANDLER(
+    VOID
+) : m_nThreshold(0),
+    m_cbSize(0),
+    m_pFreeLists(NULL),
+    m_nTotal(0)
+{
+}
+
+ALLOC_CACHE_HANDLER::~ALLOC_CACHE_HANDLER(
+    VOID
+)
+{
+    if (m_pFreeLists != NULL)
+    {
+        CleanupLookaside();
+        m_pFreeLists->Dispose();
+        m_pFreeLists = NULL;
+    }
+}
+
+HRESULT
+ALLOC_CACHE_HANDLER::Initialize(
+    DWORD       cbSize,
+    LONG        nThreshold
+)
+{
+    HRESULT hr = S_OK;
+
+    m_nThreshold = nThreshold;
+    if ( m_nThreshold > 0xffff)
+    {
+        //
+        // This will be compared against QueryDepthSList return value (USHORT).
+        //
+        m_nThreshold = 0xffff;
+    }
+
+    if ( IsPageheapEnabled() )
+    {
+        //
+        // Disable acache.
+        //
+        m_nThreshold = 0;
+    }
+
+    //
+    // Make sure the block is big enough to hold a FREE_LIST_HEADER.
+    //
+    m_cbSize = cbSize;
+    m_cbSize = max(m_cbSize, sizeof(FREE_LIST_HEADER));
+    
+    //
+    // Round up the block size to a multiple of the size of a LONG (for
+    // the fill pattern in Free()).
+    //
+    m_cbSize = (m_cbSize + sizeof(LONG) - 1) & ~(sizeof(LONG) - 1);
+
+#if defined(_MSC_VER) && _MSC_VER >= 1600 // VC10
+    auto Init = [] (SLIST_HEADER* pHead)
+    {
+        InitializeSListHead(pHead);
+    };
+#else
+    class Functor
+    {
+    public:
+        void operator()(SLIST_HEADER* pHead)
+        {
+            InitializeSListHead(pHead);
+        }
+    } Init;
+#endif
+    
+    hr = PER_CPU<SLIST_HEADER>::Create(Init,
+                                       &m_pFreeLists );
+    if (FAILED(hr))
+    {
+        goto Finished;
+    }
+
+    m_nFillPattern = InterlockedIncrement(&sm_nFillPattern);
+
+Finished:
+
+    return hr;
+}
+
+// static
+HRESULT
+ALLOC_CACHE_HANDLER::StaticInitialize(
+    VOID
+)
+{
+    //
+    // Since the memory allocated is fixed size,
+    // a heap is not really needed, allocations can be done
+    // using VirtualAllocEx[Numa]. For now use Windows Heap.
+    //
+    // Be aware that creating one private heap consumes more
+    // virtual address space for the worker process.
+    //
+    sm_hHeap = GetProcessHeap();
+    return S_OK;
+}
+
+
+// static
+VOID
+ALLOC_CACHE_HANDLER::StaticTerminate(
+    VOID
+)
+{
+    sm_hHeap = NULL;
+}
+
+VOID
+ALLOC_CACHE_HANDLER::CleanupLookaside(
+    VOID
+)
+/*++
+  Description:
+    This function cleans up the lookaside list by removing storage space.
+
+  Arguments:
+    None.
+
+  Returns:
+     None
+--*/
+{
+    //
+    // Free up all the entries in the list.
+    // Don't use InterlockedFlushSList, in order to work
+    // memory must be 16 bytes aligned and currently it is 64.
+    //
+
+#if defined(_MSC_VER) && _MSC_VER >= 1600 // VC10
+    auto Predicate = [=] (SLIST_HEADER * pListHeader)
+    {
+        PSLIST_ENTRY pl;
+        LONG NodesToDelete = QueryDepthSList( pListHeader );
+
+        pl = InterlockedPopEntrySList( pListHeader );
+        while ( pl != NULL && --NodesToDelete >= 0 )
+        {
+            InterlockedDecrement( &m_nTotal);
+
+            ::HeapFree( sm_hHeap, 0, pl );
+
+            pl = InterlockedPopEntrySList(pListHeader);
+        }
+    };
+#else
+    class Functor
+    {
+    public:
+        explicit Functor(ALLOC_CACHE_HANDLER * pThis) : _pThis(pThis)
+        {
+        }
+        void operator()(SLIST_HEADER * pListHeader)
+        {
+            PSLIST_ENTRY pl;
+            LONG NodesToDelete = QueryDepthSList( pListHeader );
+
+            pl = InterlockedPopEntrySList( pListHeader );
+            while ( pl != NULL && --NodesToDelete >= 0 )
+            {
+                InterlockedDecrement( &_pThis->m_nTotal);
+
+                ::HeapFree( sm_hHeap, 0, pl );
+
+                pl = InterlockedPopEntrySList(pListHeader);
+            }
+        }
+    private:
+        ALLOC_CACHE_HANDLER * _pThis;
+    } Predicate(this);
+#endif
+
+    m_pFreeLists ->ForEach(Predicate);
+}
+
+LPVOID
+ALLOC_CACHE_HANDLER::Alloc(
+    VOID
+)
+{
+    LPVOID pMemory = NULL;
+
+    if ( m_nThreshold > 0 )
+    {
+        SLIST_HEADER * pListHeader = m_pFreeLists ->GetLocal();
+        pMemory = (LPVOID) InterlockedPopEntrySList(pListHeader);  // get the real object
+
+        if (pMemory != NULL)
+        {
+            FREE_LIST_HEADER* pfl = (FREE_LIST_HEADER*) pMemory;
+            //
+            // If the signature is wrong then somebody's been scribbling
+            // on memory that they've freed.
+            //
+            DBG_ASSERT(pfl->dwSignature == FREE_LIST_HEADER::FREE_SIGNATURE);
+        }
+    }
+
+    if ( pMemory == NULL )
+    {
+        //
+        // No free entry. Need to alloc a new object.
+        //
+        pMemory = (LPVOID) ::HeapAlloc( sm_hHeap,
+                                        0,
+                                        m_cbSize );
+
+        if ( pMemory != NULL )
+        {
+            //
+            // Update counters.
+            //
+            m_nTotal++;
+        }
+    }
+
+    if ( pMemory == NULL )
+    {
+        SetLastError( ERROR_NOT_ENOUGH_MEMORY );
+    }
+    else
+    {
+        FREE_LIST_HEADER* pfl = (FREE_LIST_HEADER*) pMemory;
+        pfl->dwSignature = 0; // clear; just in case caller never overwrites
+    }
+
+    return pMemory;
+}
+
+VOID
+ALLOC_CACHE_HANDLER::Free(
+    __in LPVOID pMemory
+)
+{
+    //
+    // Assume that this is allocated using the Alloc() function.
+    //
+    DBG_ASSERT(NULL != pMemory);
+
+    //
+    // Use a signature to check against double deletions.
+    //
+    FREE_LIST_HEADER* pfl = (FREE_LIST_HEADER*) pMemory;
+    DBG_ASSERT(pfl->dwSignature != FREE_LIST_HEADER::FREE_SIGNATURE);
+
+    //
+    // Start filling the space beyond the portion overlaid by the initial
+    // FREE_LIST_HEADER.  Fill at most 6 DWORDS.
+    //
+    LONG* pl = (LONG*) (pfl+1);
+
+    for (LONG cb = (LONG)min(6 * sizeof(LONG),m_cbSize) - sizeof(FREE_LIST_HEADER);
+         cb > 0;
+         cb -= sizeof(LONG))
+    {
+        *pl++ = m_nFillPattern;
+    }
+
+    //
+    // Now, set the signature.
+    //
+    pfl->dwSignature = FREE_LIST_HEADER::FREE_SIGNATURE;
+
+    //
+    // Store the items in the alloc cache.
+    //
+    SLIST_HEADER * pListHeader = m_pFreeLists ->GetLocal();
+
+    if ( QueryDepthSList(pListHeader) >= m_nThreshold )
+    {
+        //
+        // Threshold for free entries is exceeded. Free the object to
+        // process pool.
+        //
+        ::HeapFree( sm_hHeap, 0, pMemory );
+    }
+    else
+    {
+        //
+        // Store the given pointer in the single linear list
+        //
+        InterlockedPushEntrySList(pListHeader, &pfl->ListEntry);
+    }
+}
+
+DWORD
+ALLOC_CACHE_HANDLER::QueryDepthForAllSLists(
+    VOID
+)
+/*++
+
+Description:
+    
+    Aggregates the total count of elements in all lists.
+    
+Arguments:
+    
+    None.
+
+Return Value:
+
+    Total count (snapshot).
+
+--*/
+{
+    DWORD Count = 0;
+
+    if (m_pFreeLists  != NULL)
+    {
+#if defined(_MSC_VER) && _MSC_VER >= 1600 // VC10
+        auto Predicate = [&Count] (SLIST_HEADER * pListHeader)
+        {
+            Count += QueryDepthSList(pListHeader);
+        };
+#else
+        class Functor
+        {
+        public:
+            explicit Functor(DWORD& Count) : _Count(Count)
+            {
+            }
+            void operator()(SLIST_HEADER * pListHeader)
+            {
+                _Count += QueryDepthSList(pListHeader);
+            }
+        private:
+            DWORD& _Count;
+        } Predicate(Count);
+#endif
+        //
+        // [&Count] means that the method can modify local variable Count.
+        //
+        m_pFreeLists ->ForEach(Predicate);
+    }
+
+    return Count;
+}
+
+// static
+BOOL
+ALLOC_CACHE_HANDLER::IsPageheapEnabled(
+    VOID
+)
+{
+    BOOL        fRet = FALSE;
+    BOOL        fLockedHeap = FALSE;
+    HMODULE     hModule = NULL;
+    HANDLE      hHeap = NULL;
+    PROCESS_HEAP_ENTRY heapEntry = {0};
+
+    //
+    // If verifier.dll is loaded - we are running under app verifier == pageheap is enabled
+    //
+    hModule = GetModuleHandle( L"verifier.dll" );
+    if ( hModule != NULL )
+    {
+        hModule = NULL;
+        fRet = TRUE;
+        goto Finished;
+    }
+
+    //
+    // Create a heap for calling heapwalk 
+    // otherwise HeapWalk turns off lookasides for a useful heap
+    //
+    hHeap = ::HeapCreate( 0, 0, 0 );
+    if ( hHeap == NULL )
+    {
+        fRet = FALSE;
+        goto Finished;
+    }
+    
+    fRet = ::HeapLock( hHeap );
+    if ( !fRet )
+    {
+        goto Finished;
+    }
+    fLockedHeap = TRUE;
+
+    //
+    // If HeapWalk is unsupported -> then running page heap
+    //
+    fRet = ::HeapWalk( hHeap, &heapEntry );
+    if ( !fRet )
+    {
+        if ( GetLastError() == ERROR_INVALID_FUNCTION )
+        {
+            fRet = TRUE;
+            goto Finished;
+        }
+    }
+
+    fRet = FALSE;
+
+Finished:
+
+    if ( fLockedHeap )
+    {
+        fLockedHeap = FALSE;
+        DBG_REQUIRE( ::HeapUnlock( hHeap ) );
+    }
+
+    if ( hHeap )
+    {
+        DBG_REQUIRE( ::HeapDestroy( hHeap ) );
+        hHeap = NULL;
+    }
+
+    return fRet;
+}
\ No newline at end of file
diff --git a/src/IISIntegration/src/AspNetCoreModuleV1/IISLib/acache.h b/src/IISIntegration/src/AspNetCoreModuleV1/IISLib/acache.h
new file mode 100644
index 0000000000000000000000000000000000000000..048df2b507d63b8194f42cd4cfbe5e948c4082f8
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV1/IISLib/acache.h
@@ -0,0 +1,115 @@
+// 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 "percpu.h"
+
+class ALLOC_CACHE_HANDLER
+{
+public:
+
+    ALLOC_CACHE_HANDLER(
+        VOID
+    );
+
+    ~ALLOC_CACHE_HANDLER(
+        VOID
+    );
+
+    HRESULT
+    Initialize(
+        DWORD       cbSize,
+        LONG        nThreshold
+    );
+
+    LPVOID
+    Alloc(
+        VOID
+    );
+
+    VOID
+    Free(
+        __in LPVOID pMemory
+    );
+
+
+private:
+
+    VOID
+    CleanupLookaside(
+        VOID
+    );
+
+    DWORD
+    QueryDepthForAllSLists(
+        VOID
+    );
+
+    LONG                    m_nThreshold;
+    DWORD                   m_cbSize;
+
+    PER_CPU<SLIST_HEADER> * m_pFreeLists;
+
+    //
+    // Total heap allocations done over the lifetime.
+    // Note that this is not interlocked, it is just a hint for debugging.
+    //
+    volatile LONG           m_nTotal;
+
+    LONG                    m_nFillPattern;
+
+public:
+
+    static
+    HRESULT
+    StaticInitialize(
+        VOID
+    );
+    
+    static
+    VOID
+    StaticTerminate(
+        VOID
+    );
+
+    static
+    BOOL
+    IsPageheapEnabled();
+
+private:
+
+    static LONG             sm_nFillPattern;
+    static HANDLE           sm_hHeap;
+};
+
+
+// You can use ALLOC_CACHE_HANDLER as a per-class allocator
+// in your C++ classes.  Add the following to your class definition:
+//
+//  protected:
+//      static ALLOC_CACHE_HANDLER* sm_palloc;
+//  public:
+//      static void*  operator new(size_t s)
+//      {
+//        IRTLASSERT(s == sizeof(C));
+//        IRTLASSERT(sm_palloc != NULL);
+//        return sm_palloc->Alloc();
+//      }
+//      static void   operator delete(void* pv)
+//      {
+//        IRTLASSERT(pv != NULL);
+//        if (sm_palloc != NULL)
+//            sm_palloc->Free(pv);
+//      }
+//
+// Obviously, you must initialize sm_palloc before you can allocate
+// any objects of this class.
+//
+// Note that if you derive a class from this base class, the derived class
+// must also provide its own operator new and operator delete.  If not, the
+// base class's allocator will be called, but the size of the derived
+// object will almost certainly be larger than that of the base object.
+// Furthermore, the allocator will not be used for arrays of objects
+// (override operator new[] and operator delete[]), but this is a
+// harder problem since the allocator works with one fixed size.
diff --git a/src/IISIntegration/src/AspNetCoreModuleV1/IISLib/ahutil.cpp b/src/IISIntegration/src/AspNetCoreModuleV1/IISLib/ahutil.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..dae2027f335661f762a808d08f23c596235f8579
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV1/IISLib/ahutil.cpp
@@ -0,0 +1,1671 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#include "precomp.h"
+
+HRESULT
+SetElementProperty(
+    IN          IAppHostElement *   pElement,
+    IN          CONST WCHAR *       szPropName,
+    IN          CONST VARIANT *     varPropValue
+    )
+{
+    HRESULT hr = NOERROR;
+
+    CComPtr<IAppHostProperty>   pPropElement;
+
+    BSTR bstrPropName = SysAllocString( szPropName );
+
+    if( !bstrPropName )
+    {
+        hr = E_OUTOFMEMORY;
+        DBGERROR_HR( hr );
+        goto exit;
+    }
+
+    hr = pElement->GetPropertyByName( bstrPropName,
+                                      &pPropElement );
+    if( FAILED(hr) )
+    {
+        DBGERROR_HR( hr );
+        goto exit;
+    }
+
+    hr = pPropElement->put_Value( *varPropValue );
+    if( FAILED(hr) )
+    {
+        DBGERROR_HR( hr );
+        goto exit;
+    }
+
+exit:
+
+    if( bstrPropName )
+    {
+        SysFreeString( bstrPropName );
+        bstrPropName = NULL;
+    }
+
+    return hr;
+}
+
+HRESULT
+SetElementStringProperty(
+    IN          IAppHostElement *   pElement,
+    IN          CONST WCHAR *       szPropName,
+    IN          CONST WCHAR *       szPropValue
+    )
+{
+    HRESULT hr;
+    VARIANT varPropValue;
+    VariantInit(&varPropValue);
+
+    hr = VariantAssign(&varPropValue, szPropValue);
+
+    if (FAILED(hr))
+    {
+        DBGERROR_HR(hr);
+        goto exit;
+    }
+
+    hr = SetElementProperty(pElement, szPropName, &varPropValue);
+
+    if (FAILED(hr))
+    {
+        DBGERROR_HR(hr);
+        goto exit;
+    }
+
+exit:
+
+    VariantClear(&varPropValue);
+    return hr;
+}
+
+HRESULT
+GetElementStringProperty(
+    IN          IAppHostElement *   pElement,
+    IN          CONST WCHAR *       szPropName,
+    OUT         BSTR *              pbstrPropValue
+    )
+{
+    HRESULT hr = S_OK;
+    BSTR bstrPropName = SysAllocString( szPropName );
+    IAppHostProperty* pProperty = NULL;
+
+    *pbstrPropValue = NULL;
+
+    if (!bstrPropName)
+    {
+        hr = E_OUTOFMEMORY;
+        DBGERROR_HR( hr );
+        goto exit;
+    }
+
+    hr = pElement->GetPropertyByName( bstrPropName, &pProperty );
+    if (FAILED(hr))
+    {
+        DBGERROR_HR( hr );
+        goto exit;
+    }
+
+    hr = pProperty->get_StringValue( pbstrPropValue );
+    if (FAILED(hr))
+    {
+        DBGERROR_HR( hr );
+        goto exit;
+    }
+
+exit:
+
+    if (pProperty)
+    {
+        pProperty->Release();
+    }
+
+    if (bstrPropName)
+    {
+        SysFreeString( bstrPropName );
+    }
+
+    return hr;
+}
+
+
+HRESULT
+GetElementStringProperty(
+    IN          IAppHostElement *   pElement,
+    IN          CONST WCHAR *       szPropName,
+    OUT         STRU *              pstrPropValue
+    )
+{
+    HRESULT hr = S_OK;
+    BSTR bstrPropName = SysAllocString( szPropName );
+    IAppHostProperty* pProperty = NULL;
+    BSTR bstrPropValue = NULL;
+
+    if (!bstrPropName)
+    {
+        hr = E_OUTOFMEMORY;
+        DBGERROR_HR( hr );
+        goto exit;
+    }
+
+    hr = pElement->GetPropertyByName( bstrPropName, &pProperty );
+    if (FAILED(hr))
+    {
+        DBGERROR_HR( hr );
+        goto exit;
+    }
+
+    hr = pProperty->get_StringValue( &bstrPropValue );
+    if (FAILED(hr))
+    {
+        DBGERROR_HR( hr );
+        goto exit;
+    }
+
+    hr = pstrPropValue->Copy(bstrPropValue);
+    if (FAILED(hr))
+    {
+        DBGERROR_HR( hr );
+        goto exit;
+    }
+
+exit:
+
+    if (pProperty)
+    {
+        pProperty->Release();
+    }
+
+    if (bstrPropValue)
+    {
+        SysFreeString( bstrPropValue );
+    }
+
+    if (bstrPropName)
+    {
+        SysFreeString( bstrPropName );
+    }
+
+    return hr;
+}
+
+HRESULT
+GetElementChildByName(
+    IN IAppHostElement *    pElement,
+    IN LPCWSTR              pszElementName,
+    OUT IAppHostElement **  ppChildElement
+)
+{
+    BSTR bstrElementName = SysAllocString(pszElementName);
+    if (bstrElementName == NULL)
+    {
+        return E_OUTOFMEMORY;
+    }
+    HRESULT hr = pElement->GetElementByName(bstrElementName,
+                                            ppChildElement);
+    SysFreeString(bstrElementName);
+    return hr;
+}
+
+HRESULT
+GetElementBoolProperty(
+    IN IAppHostElement * pElement,
+    IN LPCWSTR           pszPropertyName,
+    OUT bool *           pBool
+)
+{
+    BOOL fValue;
+    HRESULT hr = GetElementBoolProperty(pElement,
+                                        pszPropertyName,
+                                        &fValue);
+    if (SUCCEEDED(hr))
+    {
+        *pBool = !!fValue;
+    }
+    return hr;
+}
+
+HRESULT
+GetElementBoolProperty(
+    IN IAppHostElement * pElement,
+    IN LPCWSTR           pszPropertyName,
+    OUT BOOL *           pBool
+)
+{
+    HRESULT hr = S_OK;
+    BSTR    bstrPropertyName = NULL;
+    IAppHostProperty * pProperty = NULL;
+    VARIANT            varValue;
+
+    VariantInit( &varValue );
+
+    bstrPropertyName = SysAllocString( pszPropertyName );
+    if ( bstrPropertyName == NULL )
+    {
+        hr = E_OUTOFMEMORY;
+        DBGERROR_HR(hr);
+        goto exit;
+    }
+
+    // Now ask for the property and if it succeeds it is returned directly back.
+    hr = pElement->GetPropertyByName( bstrPropertyName, &pProperty );
+    if ( FAILED ( hr ) )
+    {
+       goto exit;
+    }
+
+    // Now let's get the property and then extract it from the Variant.
+    hr = pProperty->get_Value( &varValue );
+    if ( FAILED ( hr ) )
+    {
+         goto exit;
+    }
+
+    hr = VariantChangeType( &varValue, &varValue, 0, VT_BOOL );
+    if ( FAILED ( hr ) )
+    {
+         goto exit;
+    }
+
+    // extract the value
+    *pBool = ( V_BOOL( &varValue ) == VARIANT_TRUE );
+
+exit:
+
+    VariantClear( &varValue );
+
+    if ( bstrPropertyName != NULL )
+    {
+        SysFreeString( bstrPropertyName );
+        bstrPropertyName = NULL;
+    }
+
+    if ( pProperty != NULL )
+    {
+        pProperty->Release();
+        pProperty = NULL;
+    }
+
+    return hr;
+
+}
+
+HRESULT
+GetElementDWORDProperty(
+    IN  IAppHostElement * pSitesCollectionEntry,
+    IN  LPCWSTR           pwszName,
+    OUT DWORD *           pdwValue
+)
+{
+    HRESULT            hr = S_OK;
+    IAppHostProperty * pProperty = NULL;
+    BSTR               bstrName = NULL;
+    VARIANT            varValue;
+
+    VariantInit( &varValue );
+
+    bstrName = SysAllocString( pwszName );
+    if ( bstrName == NULL )
+    {
+        hr = E_OUTOFMEMORY;
+        DBGERROR_HR(hr);
+        goto error;
+    }
+
+    hr = pSitesCollectionEntry->GetPropertyByName( bstrName,
+                                                   &pProperty );
+    if ( FAILED ( hr ) )
+    {
+        goto error;
+    }
+
+    hr = pProperty->get_Value( &varValue );
+    if ( FAILED ( hr ) )
+    {
+         goto error;
+    }
+
+    hr = VariantChangeType( &varValue, &varValue, 0, VT_UI4 );
+    if ( FAILED ( hr ) )
+    {
+         goto error;
+    }
+
+    // extract the value
+    *pdwValue = varValue.ulVal;
+
+error:
+
+    VariantClear( &varValue );
+
+    if ( pProperty != NULL )
+    {
+        pProperty->Release();
+        pProperty = NULL;
+    }
+
+    if ( bstrName != NULL )
+    {
+        SysFreeString( bstrName );
+        bstrName = NULL;
+    }
+
+    return hr;
+}
+
+HRESULT
+GetElementLONGLONGProperty(
+    IN  IAppHostElement * pSitesCollectionEntry,
+    IN  LPCWSTR           pwszName,
+    OUT LONGLONG *        pllValue
+)
+{
+    HRESULT            hr = S_OK;
+    IAppHostProperty * pProperty = NULL;
+    BSTR               bstrName = NULL;
+    VARIANT            varValue;
+
+    VariantInit( &varValue );
+
+    bstrName = SysAllocString( pwszName );
+    if ( bstrName == NULL )
+    {
+        hr = E_OUTOFMEMORY;
+        DBGERROR_HR(hr);
+        goto error;
+    }
+
+    hr = pSitesCollectionEntry->GetPropertyByName( bstrName,
+                                                   &pProperty );
+    if ( FAILED ( hr ) )
+    {
+        goto error;
+    }
+
+    hr = pProperty->get_Value( &varValue );
+    if ( FAILED ( hr ) )
+    {
+         goto error;
+    }
+
+    hr = VariantChangeType( &varValue, &varValue, 0, VT_I8 );
+    if ( FAILED ( hr ) )
+    {
+         goto error;
+    }
+
+    // extract the value
+    *pllValue = varValue.ulVal;
+
+error:
+
+    VariantClear( &varValue );
+
+    if ( pProperty != NULL )
+    {
+        pProperty->Release();
+        pProperty = NULL;
+    }
+
+    if ( bstrName != NULL )
+    {
+        SysFreeString( bstrName );
+        bstrName = NULL;
+    }
+
+    return hr;
+}
+
+HRESULT
+GetElementRawTimeSpanProperty(
+    IN IAppHostElement * pElement,
+    IN LPCWSTR           pszPropertyName,
+    OUT ULONGLONG *      pulonglong
+)
+{
+    HRESULT hr = S_OK;
+    BSTR    bstrPropertyName = NULL;
+    IAppHostProperty * pProperty = NULL;
+    VARIANT            varValue;
+
+    VariantInit( &varValue );
+
+    bstrPropertyName = SysAllocString( pszPropertyName );
+    if ( bstrPropertyName == NULL )
+    {
+        hr = HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
+        goto Finished;
+    }
+
+    // Now ask for the property and if it succeeds it is returned directly back
+    hr = pElement->GetPropertyByName( bstrPropertyName, &pProperty );
+    if ( FAILED ( hr ) )
+    {
+       goto Finished;
+    }
+
+    // Now let's get the property and then extract it from the Variant.
+    hr = pProperty->get_Value( &varValue );
+    if ( FAILED ( hr ) )
+    {
+         goto Finished;
+    }
+
+    hr = VariantChangeType( &varValue, &varValue, 0, VT_UI8 );
+    if ( FAILED ( hr ) )
+    {
+         goto Finished;
+    }
+
+    // extract the value
+    *pulonglong = varValue.ullVal;
+
+
+Finished:
+
+    VariantClear( &varValue );
+
+    if ( bstrPropertyName != NULL )
+    {
+        SysFreeString( bstrPropertyName );
+        bstrPropertyName = NULL;
+    }
+
+    if ( pProperty != NULL )
+    {
+        pProperty->Release();
+        pProperty = NULL;
+    }
+
+    return hr;
+
+} // end of Config_GetRawTimeSpanProperty
+
+HRESULT
+DeleteElementFromCollection(
+    IAppHostElementCollection           *pCollection,
+    CONST WCHAR *                       szKeyName,
+    CONST WCHAR *                       szKeyValue,
+    ULONG                               BehaviorFlags,
+    BOOL *                              pfDeleted
+    )
+{
+    HRESULT hr = NOERROR;
+    ULONG index;
+
+    VARIANT varIndex;
+    VariantInit( &varIndex );
+
+    *pfDeleted = FALSE;
+
+    hr = FindElementInCollection(
+             pCollection,
+             szKeyName,
+             szKeyValue,
+             BehaviorFlags,
+             &index
+             );
+
+    if (FAILED(hr))
+    {
+        DBGERROR_HR(hr);
+        goto exit;
+    }
+
+    if (hr == S_FALSE)
+    {
+        //
+        // Not found.
+        //
+
+        goto exit;
+    }
+
+    varIndex.vt = VT_UI4;
+    varIndex.ulVal = index;
+
+    hr = pCollection->DeleteElement( varIndex );
+
+    if( FAILED(hr) )
+    {
+        DBGERROR_HR(hr);
+        goto exit;
+    }
+
+    *pfDeleted = TRUE;
+
+exit:
+
+    return hr;
+}
+
+HRESULT
+DeleteAllElementsFromCollection(
+    IAppHostElementCollection           *pCollection,
+    CONST WCHAR *                       szKeyName,
+    CONST WCHAR *                       szKeyValue,
+    ULONG                               BehaviorFlags,
+    UINT *                              pNumDeleted
+    )
+{
+    HRESULT hr = S_OK;
+    UINT numDeleted = 0;
+    BOOL fDeleted = TRUE;
+
+    while (fDeleted)
+    {
+        hr = DeleteElementFromCollection(
+                 pCollection,
+                 szKeyName,
+                 szKeyValue,
+                 BehaviorFlags,
+                 &fDeleted
+                 );
+
+        if (hr == S_FALSE)
+        {
+            hr = S_OK;
+            break;
+        }
+
+        if (FAILED(hr))
+        {
+            DBGERROR_HR(hr);
+            break;
+        }
+
+        if (fDeleted)
+        {
+            numDeleted++;
+        }
+    }
+
+    *pNumDeleted = numDeleted;
+    return hr;
+}
+
+BOOL
+FindCompareCaseSensitive(
+    CONST WCHAR * szLookupValue,
+    CONST WCHAR * szKeyValue
+    )
+{
+    return !wcscmp(szLookupValue, szKeyValue);
+}
+
+BOOL
+FindCompareCaseInsensitive(
+    CONST WCHAR * szLookupValue,
+    CONST WCHAR * szKeyValue
+    )
+{
+    return !_wcsicmp(szLookupValue, szKeyValue);
+}
+
+typedef
+BOOL
+(*PFN_FIND_COMPARE_PROC)(
+    CONST WCHAR *szLookupValue,
+    CONST WCHAR *szKeyValue
+    );
+
+HRESULT
+FindElementInCollection(
+    IAppHostElementCollection           *pCollection,
+    CONST WCHAR *                       szKeyName,
+    CONST WCHAR *                       szKeyValue,
+    ULONG                               BehaviorFlags,
+    OUT   ULONG *                       pIndex
+    )
+{
+    HRESULT hr = NOERROR;
+
+    CComPtr<IAppHostElement>        pElement;
+    CComPtr<IAppHostProperty>       pKeyProperty;
+
+    VARIANT varIndex;
+    VariantInit( &varIndex );
+
+    VARIANT varKeyValue;
+    VariantInit( &varKeyValue );
+
+    DWORD   count;
+    DWORD   i;
+
+    BSTR bstrKeyName = NULL;
+    PFN_FIND_COMPARE_PROC compareProc;
+
+    compareProc = (BehaviorFlags & FIND_ELEMENT_CASE_INSENSITIVE)
+                      ? &FindCompareCaseInsensitive
+                      : &FindCompareCaseSensitive;
+
+    bstrKeyName = SysAllocString( szKeyName );
+    if( !bstrKeyName )
+    {
+        hr = E_OUTOFMEMORY;
+        DBGERROR_HR(hr);
+        goto exit;
+    }
+
+    hr = pCollection->get_Count( &count );
+    if( FAILED(hr) )
+    {
+        DBGERROR_HR(hr);
+        goto exit;
+    }
+
+    for( i = 0; i < count; i++ )
+    {
+        varIndex.vt = VT_UI4;
+        varIndex.ulVal = i;
+
+        hr = pCollection->get_Item( varIndex,
+                                    &pElement );
+        if( FAILED(hr) )
+        {
+            DBGERROR_HR(hr);
+            goto tryNext;
+        }
+
+        hr = pElement->GetPropertyByName( bstrKeyName,
+                                          &pKeyProperty );
+        if( FAILED(hr) )
+        {
+            DBGERROR_HR(hr);
+            goto tryNext;
+        }
+
+        hr = pKeyProperty->get_Value( &varKeyValue );
+
+        if( FAILED(hr) )
+        {
+            DBGERROR_HR(hr);
+            goto tryNext;
+        }
+
+        if ((compareProc)(szKeyValue, varKeyValue.bstrVal))
+        {
+            *pIndex = i;
+            break;
+        }
+
+tryNext:
+
+        pElement.Release();
+        pKeyProperty.Release();
+
+        VariantClear( &varKeyValue );
+    }
+
+    if (i >= count)
+    {
+        hr = S_FALSE;
+    }
+
+exit:
+
+    SysFreeString( bstrKeyName );
+    VariantClear( &varKeyValue );
+
+    return hr;
+}
+
+HRESULT
+VariantAssign(
+    IN OUT      VARIANT *       pv,
+    IN          CONST WCHAR *   sz
+    )
+{
+    if( !pv || !sz )
+    {
+        return E_INVALIDARG;
+    }
+
+    HRESULT hr = NOERROR;
+
+    BSTR bstr = SysAllocString( sz );
+    if( !bstr )
+    {
+        hr = E_OUTOFMEMORY;
+        DBGERROR_HR( hr );
+        goto exit;
+    }
+
+    hr = VariantClear( pv );
+    if( FAILED(hr) )
+    {
+        DBGERROR_HR( hr );
+        goto exit;
+    }
+
+    pv->vt = VT_BSTR;
+    pv->bstrVal = bstr;
+    bstr = NULL;
+
+exit:
+
+    SysFreeString( bstr );
+
+    return hr;
+}
+
+HRESULT
+GetLocationFromFile(
+    IN      IAppHostAdminManager *      pAdminMgr,
+    IN      CONST WCHAR *               szConfigPath,
+    IN      CONST WCHAR *               szLocationPath,
+    OUT     IAppHostConfigLocation **   ppLocation,
+    OUT     BOOL *                      pFound
+    )
+{
+    HRESULT hr = NOERROR;
+
+    CComPtr<IAppHostConfigLocationCollection>   pLocationCollection;
+    CComPtr<IAppHostConfigLocation>             pLocation;
+
+    BSTR bstrLocationPath = NULL;
+
+    *ppLocation = NULL;
+    *pFound = FALSE;
+
+    hr = GetLocationCollection( pAdminMgr,
+                                szConfigPath,
+                                &pLocationCollection );
+
+    if( FAILED(hr) )
+    {
+        DBGERROR_HR(hr);
+        goto exit;
+    }
+
+    DWORD count;
+    DWORD i;
+    VARIANT varIndex;
+    VariantInit( &varIndex );
+
+    hr = pLocationCollection->get_Count( &count );
+    if( FAILED(hr) )
+    {
+        DBGERROR_HR(hr);
+        goto exit;
+    }
+
+    for( i = 0; i < count; i++ )
+    {
+        varIndex.vt = VT_UI4;
+        varIndex.ulVal = i;
+
+        hr = pLocationCollection->get_Item( varIndex,
+                                            &pLocation );
+        if( FAILED(hr) )
+        {
+            DBGERROR_HR(hr);
+            goto exit;
+        }
+
+        hr = pLocation->get_Path( &bstrLocationPath );
+        if( FAILED(hr) )
+        {
+            DBGERROR_HR(hr);
+            goto exit;
+        }
+
+        if( 0 == wcscmp ( szLocationPath, bstrLocationPath ) )
+        {
+            *pFound = TRUE;
+            *ppLocation = pLocation.Detach();
+            break;
+        }
+
+
+        pLocation.Release();
+
+        SysFreeString( bstrLocationPath );
+        bstrLocationPath = NULL;
+    }
+
+exit:
+
+    SysFreeString( bstrLocationPath );
+
+    return hr;
+}
+
+HRESULT
+GetSectionFromLocation(
+    IN      IAppHostConfigLocation *            pLocation,
+    IN      CONST WCHAR *                       szSectionName,
+    OUT     IAppHostElement **                  ppSectionElement,
+    OUT     BOOL *                              pFound
+    )
+{
+    HRESULT hr = NOERROR;
+
+    CComPtr<IAppHostElement>    pSectionElement;
+
+    DWORD count;
+    DWORD i;
+
+    VARIANT varIndex;
+    VariantInit( &varIndex );
+
+    BSTR bstrSectionName = NULL;
+
+    *pFound = FALSE;
+    *ppSectionElement = NULL;
+
+    hr = pLocation->get_Count( &count );
+    if( FAILED(hr) )
+    {
+        DBGERROR_HR(hr);
+        goto exit;
+    }
+
+    for( i = 0; i < count; i++ )
+    {
+        varIndex.vt = VT_UI4;
+        varIndex.ulVal = i;
+
+
+        hr = pLocation->get_Item( varIndex,
+                                  &pSectionElement );
+        if( FAILED(hr) )
+        {
+            DBGERROR_HR(hr);
+            goto exit;
+        }
+
+        hr = pSectionElement->get_Name( &bstrSectionName );
+        if( FAILED(hr) )
+        {
+            DBGERROR_HR(hr);
+            goto exit;
+        }
+
+        if( 0 == wcscmp ( szSectionName, bstrSectionName ) )
+        {
+            *pFound = TRUE;
+            *ppSectionElement = pSectionElement.Detach();
+            break;
+        }
+
+        pSectionElement.Release();
+
+        SysFreeString( bstrSectionName );
+        bstrSectionName = NULL;
+    }
+
+exit:
+
+    SysFreeString( bstrSectionName );
+
+    return hr;
+}
+
+
+HRESULT
+GetAdminElement(
+    IN      IAppHostAdminManager *      pAdminMgr,
+    IN      CONST WCHAR *               szConfigPath,
+    IN      CONST WCHAR *               szElementName,
+    OUT     IAppHostElement **          pElement
+)
+{
+    HRESULT hr = S_OK;
+    BSTR bstrConfigPath = NULL;
+    BSTR bstrElementName = NULL;
+
+    bstrConfigPath = SysAllocString(szConfigPath);
+    bstrElementName = SysAllocString(szElementName);
+
+    if (bstrConfigPath == NULL || bstrElementName == NULL)
+    {
+        hr = E_OUTOFMEMORY;
+        DBGERROR_HR(hr);
+        goto exit;
+    }
+
+    hr = pAdminMgr->GetAdminSection( bstrElementName,
+                                     bstrConfigPath,
+                                     pElement );
+
+    if (FAILED(hr))
+    {
+        DBGERROR_HR(hr);
+        goto exit;
+    }
+
+exit:
+
+    if ( bstrElementName != NULL )
+    {
+        SysFreeString(bstrElementName);
+        bstrElementName = NULL;
+    }
+    if ( bstrConfigPath != NULL )
+    {
+        SysFreeString(bstrConfigPath);
+        bstrConfigPath = NULL;
+    }
+
+    return hr;
+}
+
+
+HRESULT
+ClearAdminElement(
+    IN      IAppHostAdminManager *      pAdminMgr,
+    IN      CONST WCHAR *               szConfigPath,
+    IN      CONST WCHAR *               szElementName
+    )
+{
+    HRESULT hr;
+    CComPtr<IAppHostElement> pElement;
+
+    hr = GetAdminElement(
+             pAdminMgr,
+             szConfigPath,
+             szElementName,
+             &pElement
+             );
+
+    if (FAILED(hr))
+    {
+        if (hr == HRESULT_FROM_WIN32(ERROR_NOT_FOUND))
+        {
+            hr = S_OK;
+        }
+        else
+        {
+            DBGERROR_HR(hr);
+        }
+
+        goto exit;
+    }
+
+    hr = pElement->Clear();
+
+    if (FAILED(hr))
+    {
+        DBGERROR_HR(hr);
+        goto exit;
+    }
+
+exit:
+
+    return hr;
+}
+
+
+HRESULT
+ClearElementFromAllSites(
+    IN      IAppHostAdminManager *      pAdminMgr,
+    IN      CONST WCHAR *               szConfigPath,
+    IN      CONST WCHAR *               szElementName
+    )
+{
+    HRESULT hr;
+    CComPtr<IAppHostElementCollection> pSitesCollection;
+    CComPtr<IAppHostElement> pSiteElement;
+    CComPtr<IAppHostChildElementCollection> pChildCollection;
+    ENUM_INDEX index;
+    BOOL found;
+
+    //
+    // Enumerate the sites, remove the specified elements.
+    //
+
+    hr = GetSitesCollection(
+             pAdminMgr,
+             szConfigPath,
+             &pSitesCollection
+             );
+
+    if (FAILED(hr))
+    {
+        DBGERROR_HR(hr);
+        goto exit;
+    }
+
+    for (hr = FindFirstElement(pSitesCollection, &index, &pSiteElement) ;
+         SUCCEEDED(hr) ;
+         hr = FindNextElement(pSitesCollection, &index, &pSiteElement))
+    {
+        if (hr == S_FALSE)
+        {
+            hr = S_OK;
+            break;
+        }
+
+        hr = pSiteElement->get_ChildElements(&pChildCollection);
+
+        if (FAILED(hr))
+        {
+            DBGERROR_HR(hr);
+            goto exit;
+        }
+
+        if (pChildCollection)
+        {
+            hr = ClearChildElementsByName(
+                    pChildCollection,
+                    szElementName,
+                    &found
+                    );
+
+            if (FAILED(hr))
+            {
+                DBGERROR_HR(hr);
+                goto exit;
+            }
+        }
+
+        pSiteElement.Release();
+    }
+
+exit:
+
+    return hr;
+
+}
+
+
+HRESULT
+ClearElementFromAllLocations(
+    IN      IAppHostAdminManager *      pAdminMgr,
+    IN      CONST WCHAR *               szConfigPath,
+    IN      CONST WCHAR *               szElementName
+    )
+{
+    HRESULT hr;
+    CComPtr<IAppHostConfigLocationCollection> pLocationCollection;
+    CComPtr<IAppHostConfigLocation> pLocation;
+    CComPtr<IAppHostChildElementCollection> pChildCollection;
+    ENUM_INDEX index;
+
+    //
+    // Enum the <location> tags, remove the specified elements.
+    //
+
+    hr = GetLocationCollection(
+            pAdminMgr,
+            szConfigPath,
+            &pLocationCollection
+            );
+
+    if (FAILED(hr))
+    {
+        DBGERROR_HR(hr);
+        goto exit;
+    }
+
+    for (hr = FindFirstLocation(pLocationCollection, &index, &pLocation) ;
+         SUCCEEDED(hr) ;
+         hr = FindNextLocation(pLocationCollection, &index, &pLocation))
+    {
+        if (hr == S_FALSE)
+        {
+            hr = S_OK;
+            break;
+        }
+
+        hr = ClearLocationElements(pLocation, szElementName);
+
+        if (FAILED(hr))
+        {
+            DBGERROR_HR(hr);
+            goto exit;
+        }
+
+        pLocation.Release();
+    }
+
+exit:
+
+    return hr;
+
+}
+
+HRESULT
+ClearLocationElements(
+    IN      IAppHostConfigLocation *    pLocation,
+    IN      CONST WCHAR *               szElementName
+    )
+{
+    HRESULT hr;
+    CComPtr<IAppHostElement> pElement;
+    ENUM_INDEX index;
+    BOOL matched;
+
+    for (hr = FindFirstLocationElement(pLocation, &index, &pElement) ;
+         SUCCEEDED(hr) ;
+         hr = FindNextLocationElement(pLocation, &index, &pElement))
+    {
+        if (hr == S_FALSE)
+        {
+            hr = S_OK;
+            break;
+        }
+
+        hr = CompareElementName(pElement, szElementName, &matched);
+
+        if (FAILED(hr))
+        {
+            DBGERROR_HR(hr);
+            goto exit;
+        }
+
+        if (matched)
+        {
+            pElement->Clear();
+        }
+
+        pElement.Release();
+    }
+
+exit:
+
+    return hr;
+}
+
+HRESULT
+CompareElementName(
+    IN      IAppHostElement *           pElement,
+    IN      CONST WCHAR *               szNameToMatch,
+    OUT     BOOL *                      pMatched
+    )
+{
+    HRESULT hr;
+    BSTR bstrElementName = NULL;
+
+    *pMatched = FALSE;  // until proven otherwise
+
+    hr = pElement->get_Name(&bstrElementName);
+
+    if (FAILED(hr))
+    {
+        DBGERROR_HR(hr);
+        goto exit;
+    }
+
+    if( 0 == wcscmp ( szNameToMatch, bstrElementName ) )
+    {
+        *pMatched = TRUE;
+    }
+
+exit:
+
+    SysFreeString(bstrElementName);
+    return hr;
+}
+
+
+HRESULT
+ClearChildElementsByName(
+    IN      IAppHostChildElementCollection *    pCollection,
+    IN      CONST WCHAR *                       szElementName,
+    OUT     BOOL *                              pFound
+    )
+{
+    HRESULT hr;
+    CComPtr<IAppHostElement> pElement;
+    ENUM_INDEX index;
+    BOOL matched;
+
+    *pFound = FALSE;
+
+    for (hr = FindFirstChildElement(pCollection, &index, &pElement) ;
+         SUCCEEDED(hr) ;
+         hr = FindNextChildElement(pCollection, &index, &pElement))
+    {
+        if (hr == S_FALSE)
+        {
+            hr = S_OK;
+            break;
+        }
+
+        hr = CompareElementName(pElement, szElementName, &matched);
+
+        if (FAILED(hr))
+        {
+            DBGERROR_HR(hr);
+            goto exit;
+        }
+
+        if (matched)
+        {
+            hr = pElement->Clear();
+
+            if (FAILED(hr))
+            {
+                DBGERROR_HR(hr);
+                goto exit;
+            }
+
+            *pFound = TRUE;
+        }
+
+        pElement.Release();
+    }
+
+exit:
+
+    return hr;
+}
+
+
+HRESULT
+GetSitesCollection(
+    IN      IAppHostAdminManager *              pAdminMgr,
+    IN      CONST WCHAR *                       szConfigPath,
+    OUT     IAppHostElementCollection **        pSitesCollection
+    )
+{
+    HRESULT hr;
+    CComPtr<IAppHostElement> pSitesElement;
+    BSTR bstrConfigPath;
+    BSTR bstrSitesSectionName;
+
+    bstrConfigPath = SysAllocString(szConfigPath);
+    bstrSitesSectionName = SysAllocString(L"system.applicationHost/sites");
+    *pSitesCollection = NULL;
+
+    if (bstrConfigPath == NULL || bstrSitesSectionName == NULL)
+    {
+        hr = E_OUTOFMEMORY;
+        DBGERROR_HR(hr);
+        goto exit;
+    }
+
+    //
+    // Chase down the sites collection.
+    //
+
+    hr = pAdminMgr->GetAdminSection( bstrSitesSectionName,
+                                     bstrConfigPath,
+                                     &pSitesElement );
+
+    if (FAILED(hr))
+    {
+        DBGERROR_HR(hr);
+        goto exit;
+    }
+
+    hr = pSitesElement->get_Collection(pSitesCollection);
+
+    if (FAILED(hr))
+    {
+        DBGERROR_HR(hr);
+        goto exit;
+    }
+
+exit:
+
+    SysFreeString(bstrSitesSectionName);
+    SysFreeString(bstrConfigPath);
+    return hr;
+}
+
+
+HRESULT
+GetLocationCollection(
+    IN      IAppHostAdminManager *              pAdminMgr,
+    IN      CONST WCHAR *                       szConfigPath,
+    OUT     IAppHostConfigLocationCollection ** pLocationCollection
+    )
+{
+    HRESULT hr;
+    BSTR bstrConfigPath;
+    CComPtr<IAppHostConfigManager>      pConfigMgr;
+    CComPtr<IAppHostConfigFile>         pConfigFile;
+
+    bstrConfigPath = SysAllocString(szConfigPath);
+    *pLocationCollection = NULL;
+
+    if (bstrConfigPath == NULL)
+    {
+        hr = E_OUTOFMEMORY;
+        DBGERROR_HR(hr);
+        goto exit;
+    }
+
+    hr = pAdminMgr->get_ConfigManager(&pConfigMgr);
+
+    if (FAILED(hr))
+    {
+        DBGERROR_HR(hr);
+        goto exit;
+    }
+
+    hr = pConfigMgr->GetConfigFile(bstrConfigPath, &pConfigFile);
+
+    if (FAILED(hr))
+    {
+        DBGERROR_HR(hr);
+        goto exit;
+    }
+
+    hr = pConfigFile->get_Locations(pLocationCollection);
+
+    if (FAILED(hr))
+    {
+        DBGERROR_HR(hr);
+        goto exit;
+    }
+
+exit:
+
+    SysFreeString(bstrConfigPath);
+    return hr;
+}
+
+
+HRESULT
+FindFirstElement(
+    IN      IAppHostElementCollection *         pCollection,
+    OUT     ENUM_INDEX *                        pIndex,
+    OUT     IAppHostElement **                  pElement
+    )
+{
+    HRESULT hr;
+
+    hr = pCollection->get_Count(&pIndex->Count);
+
+    if (FAILED(hr))
+    {
+        DBGERROR_HR(hr);
+        return hr;
+    }
+
+    VariantInit(&pIndex->Index);
+    pIndex->Index.vt = VT_UI4;
+    pIndex->Index.ulVal = 0;
+
+    return FindNextElement(pCollection, pIndex, pElement);
+}
+
+HRESULT
+FindNextElement(
+    IN      IAppHostElementCollection *         pCollection,
+    IN OUT  ENUM_INDEX *                        pIndex,
+    OUT     IAppHostElement **                  pElement
+    )
+{
+    HRESULT hr;
+
+    *pElement = NULL;
+
+    if (pIndex->Index.ulVal >= pIndex->Count)
+    {
+        return S_FALSE;
+    }
+
+    hr = pCollection->get_Item(pIndex->Index, pElement);
+
+    if (SUCCEEDED(hr))
+    {
+        pIndex->Index.ulVal++;
+    }
+
+    return hr;
+}
+
+HRESULT
+FindFirstChildElement(
+    IN      IAppHostChildElementCollection *    pCollection,
+    OUT     ENUM_INDEX *                        pIndex,
+    OUT     IAppHostElement **                  pElement
+    )
+{
+    HRESULT hr;
+
+    hr = pCollection->get_Count(&pIndex->Count);
+
+    if (FAILED(hr))
+    {
+        DBGERROR_HR(hr);
+        return hr;
+    }
+
+    VariantInit(&pIndex->Index);
+    pIndex->Index.vt = VT_UI4;
+    pIndex->Index.ulVal = 0;
+
+    return FindNextChildElement(pCollection, pIndex, pElement);
+}
+
+HRESULT
+FindNextChildElement(
+    IN      IAppHostChildElementCollection *    pCollection,
+    IN OUT  ENUM_INDEX *                        pIndex,
+    OUT     IAppHostElement **                  pElement
+    )
+{
+    HRESULT hr;
+
+    *pElement = NULL;
+
+    if (pIndex->Index.ulVal >= pIndex->Count)
+    {
+        return S_FALSE;
+    }
+
+    hr = pCollection->get_Item(pIndex->Index, pElement);
+
+    if (SUCCEEDED(hr))
+    {
+        pIndex->Index.ulVal++;
+    }
+
+    return hr;
+}
+
+HRESULT
+FindFirstLocation(
+    IN      IAppHostConfigLocationCollection *  pCollection,
+    OUT     ENUM_INDEX *                        pIndex,
+    OUT     IAppHostConfigLocation **           pLocation
+    )
+{
+    HRESULT hr;
+
+    hr = pCollection->get_Count(&pIndex->Count);
+
+    if (FAILED(hr))
+    {
+        DBGERROR_HR(hr);
+        return hr;
+    }
+
+    VariantInit(&pIndex->Index);
+    pIndex->Index.vt = VT_UI4;
+    pIndex->Index.ulVal = 0;
+
+    return FindNextLocation(pCollection, pIndex, pLocation);
+}
+
+HRESULT
+FindNextLocation(
+    IN      IAppHostConfigLocationCollection *  pCollection,
+    IN OUT  ENUM_INDEX *                        pIndex,
+    OUT     IAppHostConfigLocation **           pLocation
+    )
+{
+    HRESULT hr;
+
+    *pLocation = NULL;
+
+    if (pIndex->Index.ulVal >= pIndex->Count)
+    {
+        return S_FALSE;
+    }
+
+    hr = pCollection->get_Item(pIndex->Index, pLocation);
+
+    if (SUCCEEDED(hr))
+    {
+        pIndex->Index.ulVal++;
+    }
+
+    return hr;
+}
+
+HRESULT
+FindFirstLocationElement(
+    IN      IAppHostConfigLocation *            pLocation,
+    OUT     ENUM_INDEX *                        pIndex,
+    OUT     IAppHostElement **                  pElement
+    )
+{
+    HRESULT hr;
+
+    hr = pLocation->get_Count(&pIndex->Count);
+
+    if (FAILED(hr))
+    {
+        DBGERROR_HR(hr);
+        return hr;
+    }
+
+    VariantInit(&pIndex->Index);
+    pIndex->Index.vt = VT_UI4;
+    pIndex->Index.ulVal = 0;
+
+    return FindNextLocationElement(pLocation, pIndex, pElement);
+}
+
+HRESULT
+FindNextLocationElement(
+    IN      IAppHostConfigLocation *            pLocation,
+    IN OUT  ENUM_INDEX *                        pIndex,
+    OUT     IAppHostElement **                  pElement
+    )
+{
+    HRESULT hr;
+
+    *pElement = NULL;
+
+    if (pIndex->Index.ulVal >= pIndex->Count)
+    {
+        return S_FALSE;
+    }
+
+    hr = pLocation->get_Item(pIndex->Index, pElement);
+
+    if (SUCCEEDED(hr))
+    {
+        pIndex->Index.ulVal++;
+    }
+
+    return hr;
+}
+
+HRESULT
+GetSharedConfigEnabled(
+    BOOL * pfIsSharedConfig
+)
+/*++
+
+Routine Description:
+   Search the configuration for the shared configuration property.
+
+Arguments:
+
+    pfIsSharedConfig - true if shared configuration is enabled
+
+Return Value:
+    HRESULT
+
+--*/
+{
+    HRESULT                 hr = S_OK;
+    IAppHostAdminManager    *pAdminManager = NULL;
+
+    BSTR                    bstrSectionName = NULL;
+    BSTR                    bstrConfigPath = NULL;
+
+    IAppHostElement *       pConfigRedirSection = NULL;
+
+
+    bstrSectionName = SysAllocString( L"configurationRedirection" );
+
+    if ( bstrSectionName == NULL )
+    {
+        hr = E_OUTOFMEMORY;
+        DBGERROR_HR(hr);
+        goto exit;
+    }
+
+    bstrConfigPath = SysAllocString( L"MACHINE/REDIRECTION" );
+    if ( bstrConfigPath == NULL )
+    {
+        hr = E_OUTOFMEMORY;
+        DBGERROR_HR(hr);
+        goto exit;
+    }
+
+    hr = CoCreateInstance( CLSID_AppHostAdminManager,
+                           NULL,
+                           CLSCTX_INPROC_SERVER,
+                           IID_IAppHostAdminManager,
+                           (VOID **)&pAdminManager );
+    if( FAILED(hr) )
+    {
+        DBGERROR_HR(hr);
+        goto exit;
+    }
+
+    hr = pAdminManager->GetAdminSection( bstrSectionName,
+                                         bstrConfigPath,
+                                         &pConfigRedirSection );
+    if( FAILED(hr) )
+    {
+        DBGERROR_HR(hr);
+        goto exit;
+    }
+
+    hr = GetElementBoolProperty( pConfigRedirSection,
+                                 L"enabled",
+                                 pfIsSharedConfig );
+
+    if ( FAILED( hr ) )
+    {
+        DBGERROR_HR(hr);
+        goto exit;
+    }
+
+    pConfigRedirSection->Release();
+    pConfigRedirSection = NULL;
+
+
+exit:
+
+    //
+    // dump config exception to setup log file (if available)
+    //
+
+    if ( pConfigRedirSection != NULL )
+    {
+        pConfigRedirSection->Release();
+    }
+
+    if ( pAdminManager != NULL )
+    {
+        pAdminManager->Release();
+    }
+
+    if ( bstrConfigPath != NULL )
+    {
+        SysFreeString( bstrConfigPath );
+    }
+
+    if ( bstrSectionName != NULL )
+    {
+        SysFreeString( bstrSectionName );
+    }
+
+    return hr;
+}
diff --git a/src/IISIntegration/src/AspNetCoreModuleV1/IISLib/ahutil.h b/src/IISIntegration/src/AspNetCoreModuleV1/IISLib/ahutil.h
new file mode 100644
index 0000000000000000000000000000000000000000..5694b21b7ec261870b79d0f42d95c2028ec00c79
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV1/IISLib/ahutil.h
@@ -0,0 +1,258 @@
+// 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<Windows.h>
+
+HRESULT
+SetElementProperty(
+    IN          IAppHostElement *   pElement,
+    IN          CONST WCHAR *       szPropName,
+    IN          CONST VARIANT *     varPropValue
+    );
+
+HRESULT
+SetElementStringProperty(
+    IN          IAppHostElement *   pElement,
+    IN          CONST WCHAR *       szPropName,
+    IN          CONST WCHAR *       szPropValue
+    );
+
+HRESULT
+GetElementStringProperty(
+    IN          IAppHostElement *   pElement,
+    IN          CONST WCHAR *       szPropName,
+    OUT         BSTR *              pbstrPropValue
+    );
+
+HRESULT
+GetElementStringProperty(
+    IN          IAppHostElement *   pElement,
+    IN          CONST WCHAR *       szPropName,
+    OUT         STRU *              pstrPropValue
+    );
+
+HRESULT
+GetElementBoolProperty(
+    IN IAppHostElement * pElement,
+    IN LPCWSTR           pszPropertyName,
+    OUT BOOL *           pBool
+    );
+
+HRESULT
+GetElementBoolProperty(
+    IN IAppHostElement * pElement,
+    IN LPCWSTR           pszPropertyName,
+    OUT bool *           pBool
+    );
+
+HRESULT
+GetElementChildByName(
+    IN IAppHostElement *    pElement,
+    IN LPCWSTR              pszElementName,
+    OUT IAppHostElement **  ppChildElement
+    );
+
+HRESULT
+GetElementDWORDProperty(
+    IN IAppHostElement * pElement,
+    IN LPCWSTR           pszPropertyName,
+    OUT DWORD *          pdwValue
+    );
+
+HRESULT
+GetElementLONGLONGProperty(
+    IN IAppHostElement * pElement,
+    IN LPCWSTR           pszPropertyName,
+    OUT LONGLONG *       pllValue
+);
+
+
+HRESULT
+GetElementRawTimeSpanProperty(
+    IN IAppHostElement * pElement,
+    IN LPCWSTR           pszPropertyName,
+    OUT ULONGLONG *      pulonglong
+    );
+
+#define FIND_ELEMENT_CASE_SENSITIVE     0x00000000
+#define FIND_ELEMENT_CASE_INSENSITIVE   0x00000001
+
+HRESULT
+DeleteElementFromCollection(
+    IAppHostElementCollection           *pCollection,
+    CONST WCHAR *                       szKeyName,
+    CONST WCHAR *                       szKeyValue,
+    ULONG                               BehaviorFlags,
+    BOOL *                              pfDeleted
+    );
+
+HRESULT
+DeleteAllElementsFromCollection(
+    IAppHostElementCollection           *pCollection,
+    CONST WCHAR *                       szKeyName,
+    CONST WCHAR *                       szKeyValue,
+    ULONG                               BehaviorFlags,
+    UINT *                              pNumDeleted
+    );
+
+HRESULT
+FindElementInCollection(
+    IAppHostElementCollection           *pCollection,
+    CONST WCHAR *                       szKeyName,
+    CONST WCHAR *                       szKeyValue,
+    ULONG                               BehaviorFlags,
+    OUT   ULONG *                       pIndex
+    );
+
+HRESULT
+VariantAssign(
+    IN OUT      VARIANT *       pv,
+    IN          CONST WCHAR *   sz
+    );
+
+HRESULT
+GetLocationFromFile(
+    IN      IAppHostAdminManager *      pAdminMgr,
+    IN      CONST WCHAR *               szConfigPath,
+    IN      CONST WCHAR *               szLocationPath,
+    OUT     IAppHostConfigLocation **   ppLocation,
+    OUT     BOOL *                      pFound
+    );
+
+HRESULT
+GetSectionFromLocation(
+    IN      IAppHostConfigLocation *            pLocation,
+    IN      CONST WCHAR *                       szSectionName,
+    OUT     IAppHostElement **                  ppSectionElement,
+    OUT     BOOL *                              pFound
+    );
+
+HRESULT
+GetAdminElement(
+    IN      IAppHostAdminManager *      pAdminMgr,
+    IN      CONST WCHAR *               szConfigPath,
+    IN      CONST WCHAR *               szElementName,
+    OUT     IAppHostElement **          pElement
+    );
+
+HRESULT
+ClearAdminElement(
+    IN      IAppHostAdminManager *      pAdminMgr,
+    IN      CONST WCHAR *               szConfigPath,
+    IN      CONST WCHAR *               szElementName
+    );
+
+HRESULT
+ClearElementFromAllSites(
+    IN      IAppHostAdminManager *      pAdminMgr,
+    IN      CONST WCHAR *               szConfigPath,
+    IN      CONST WCHAR *               szElementName
+    );
+
+HRESULT
+ClearElementFromAllLocations(
+    IN      IAppHostAdminManager *      pAdminMgr,
+    IN      CONST WCHAR *               szConfigPath,
+    IN      CONST WCHAR *               szElementName
+    );
+
+HRESULT
+ClearLocationElements(
+    IN      IAppHostConfigLocation *    pLocation,
+    IN      CONST WCHAR *               szElementName
+    );
+
+HRESULT
+CompareElementName(
+    IN      IAppHostElement *           pElement,
+    IN      CONST WCHAR *               szNameToMatch,
+    OUT     BOOL *                      pMatched
+    );
+
+HRESULT
+ClearChildElementsByName(
+    IN      IAppHostChildElementCollection *    pCollection,
+    IN      CONST WCHAR *                       szElementName,
+    OUT     BOOL *                              pFound
+    );
+
+HRESULT
+GetSitesCollection(
+    IN      IAppHostAdminManager *              pAdminMgr,
+    IN      CONST WCHAR *                       szConfigPath,
+    OUT     IAppHostElementCollection **        pSitesCollection
+    );
+
+HRESULT
+GetLocationCollection(
+    IN      IAppHostAdminManager *              pAdminMgr,
+    IN      CONST WCHAR *                       szConfigPath,
+    OUT     IAppHostConfigLocationCollection ** pLocationCollection
+    );
+
+struct ENUM_INDEX
+{
+    VARIANT Index;
+    ULONG Count;
+};
+
+HRESULT
+FindFirstElement(
+    IN      IAppHostElementCollection *         pCollection,
+    OUT     ENUM_INDEX *                        pIndex,
+    OUT     IAppHostElement **                  pElement
+    );
+
+HRESULT
+FindNextElement(
+    IN      IAppHostElementCollection *         pCollection,
+    IN OUT  ENUM_INDEX *                        pIndex,
+    OUT     IAppHostElement **                  pElement
+    );
+
+HRESULT
+FindFirstChildElement(
+    IN      IAppHostChildElementCollection *    pCollection,
+    OUT     ENUM_INDEX *                        pIndex,
+    OUT     IAppHostElement **                  pElement
+    );
+
+HRESULT
+FindNextChildElement(
+    IN      IAppHostChildElementCollection *    pCollection,
+    IN OUT  ENUM_INDEX *                        pIndex,
+    OUT     IAppHostElement **                  pElement
+    );
+
+HRESULT
+FindFirstLocation(
+    IN      IAppHostConfigLocationCollection *  pCollection,
+    OUT     ENUM_INDEX *                        pIndex,
+    OUT     IAppHostConfigLocation **           pLocation
+    );
+
+HRESULT
+FindNextLocation(
+    IN      IAppHostConfigLocationCollection *  pCollection,
+    IN OUT  ENUM_INDEX *                        pIndex,
+    OUT     IAppHostConfigLocation **           pLocation
+    );
+
+HRESULT
+FindFirstLocationElement(
+    IN      IAppHostConfigLocation *            pLocation,
+    OUT     ENUM_INDEX *                        pIndex,
+    OUT     IAppHostElement **                  pElement
+    );
+
+HRESULT
+FindNextLocationElement(
+    IN      IAppHostConfigLocation *            pLocation,
+    IN OUT  ENUM_INDEX *                        pIndex,
+    OUT     IAppHostElement **                  pElement
+    );
+
+HRESULT GetSharedConfigEnabled(
+    BOOL * pfIsSharedConfig
+);
\ No newline at end of file
diff --git a/src/IISIntegration/src/AspNetCoreModuleV1/IISLib/base64.cpp b/src/IISIntegration/src/AspNetCoreModuleV1/IISLib/base64.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..b8b6a0bf742e5ef5aaf36bfd8eb50b9927c945f8
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV1/IISLib/base64.cpp
@@ -0,0 +1,482 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#include "precomp.h"
+
+DWORD
+Base64Encode(
+    __in_bcount(cbDecodedBufferSize)    VOID *  pDecodedBuffer,
+    IN      DWORD       cbDecodedBufferSize,
+    __out_ecount_opt(cchEncodedStringSize) PWSTR    pszEncodedString,
+    IN      DWORD       cchEncodedStringSize,
+    __out_opt DWORD *   pcchEncoded
+    )
+/*++
+
+Routine Description:
+
+    Decode a base64-encoded string.
+
+Arguments:
+
+    pDecodedBuffer (IN) - buffer to encode.
+    cbDecodedBufferSize (IN) - size of buffer to encode.
+    cchEncodedStringSize (IN) - size of the buffer for the encoded string.
+    pszEncodedString (OUT) = the encoded string.
+    pcchEncoded (OUT) - size in characters of the encoded string.
+
+Return Values:
+
+    0 - success.
+    E_OUTOFMEMORY
+
+--*/
+{
+    static WCHAR rgchEncodeTable[64] = {
+        'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
+        'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
+        'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
+        'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
+        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
+    };
+
+    DWORD   ib;
+    DWORD   ich;
+    DWORD   cchEncoded;
+    BYTE    b0, b1, b2;
+    BYTE *  pbDecodedBuffer = (BYTE *) pDecodedBuffer;
+
+    // Calculate encoded string size.
+    cchEncoded = 1 + (cbDecodedBufferSize + 2) / 3 * 4;
+
+    if (NULL != pcchEncoded) {
+        *pcchEncoded = cchEncoded;
+    }
+
+    if (cchEncodedStringSize == 0 && pszEncodedString == NULL) {
+        return ERROR_SUCCESS;
+    }
+
+    if (cchEncodedStringSize < cchEncoded) {
+        // Given buffer is too small to hold encoded string.
+        return ERROR_INSUFFICIENT_BUFFER;
+    }
+
+    // Encode data byte triplets into four-byte clusters.
+    ib = ich = 0;
+    while (ib < cbDecodedBufferSize) {
+        b0 = pbDecodedBuffer[ib++];
+        b1 = (ib < cbDecodedBufferSize) ? pbDecodedBuffer[ib++] : 0;
+        b2 = (ib < cbDecodedBufferSize) ? pbDecodedBuffer[ib++] : 0;
+
+        //
+        // The checks below for buffer overflow seems redundant to me.
+        // But it's the only way I can find to keep OACR quiet so it
+        // will have to do.
+        //
+
+        pszEncodedString[ich++] = rgchEncodeTable[b0 >> 2];
+        if ( ich >= cchEncodedStringSize )
+        {
+            DBG_ASSERT( FALSE );
+            return ERROR_BUFFER_OVERFLOW;
+        }
+
+        pszEncodedString[ich++] = rgchEncodeTable[((b0 << 4) & 0x30) | ((b1 >> 4) & 0x0f)];
+        if ( ich >= cchEncodedStringSize )
+        {
+            DBG_ASSERT( FALSE );
+            return ERROR_BUFFER_OVERFLOW;
+        }
+
+        pszEncodedString[ich++] = rgchEncodeTable[((b1 << 2) & 0x3c) | ((b2 >> 6) & 0x03)];
+        if ( ich >= cchEncodedStringSize )
+        {
+            DBG_ASSERT( FALSE );
+            return ERROR_BUFFER_OVERFLOW;
+        }
+
+        pszEncodedString[ich++] = rgchEncodeTable[b2 & 0x3f];
+        if ( ich >= cchEncodedStringSize )
+        {
+            DBG_ASSERT( FALSE );
+            return ERROR_BUFFER_OVERFLOW;
+        }
+    }
+
+    // Pad the last cluster as necessary to indicate the number of data bytes
+    // it represents.
+    switch (cbDecodedBufferSize % 3) {
+      case 0:
+        break;
+      case 1:
+        pszEncodedString[ich - 2] = '=';
+        __fallthrough;
+      case 2:
+        pszEncodedString[ich - 1] = '=';
+        break;
+    }
+
+    // Null-terminate the encoded string.
+    pszEncodedString[ich++] = '\0';
+
+    DBG_ASSERT(ich == cchEncoded);
+
+    return ERROR_SUCCESS;
+}
+
+
+DWORD
+Base64Decode(
+    __in    PCWSTR      pszEncodedString,
+    __out_opt VOID *      pDecodeBuffer,
+    __in    DWORD       cbDecodeBufferSize,
+    __out_opt DWORD *   pcbDecoded
+    )
+/*++
+
+Routine Description:
+
+    Decode a base64-encoded string.
+
+Arguments:
+
+    pszEncodedString (IN) - base64-encoded string to decode.
+    cbDecodeBufferSize (IN) - size in bytes of the decode buffer.
+    pbDecodeBuffer (OUT) - holds the decoded data.
+    pcbDecoded (OUT) - number of data bytes in the decoded data (if success or
+        STATUS_BUFFER_TOO_SMALL).
+
+Return Values:
+
+    0 - success.
+    E_OUTOFMEMORY
+    E_INVALIDARG
+
+--*/
+{
+#define NA (255)
+#define DECODE(x) (((ULONG)(x) < sizeof(rgbDecodeTable)) ? rgbDecodeTable[x] : NA)
+
+    static BYTE rgbDecodeTable[128] = {
+       NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,  // 0-15
+       NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,  // 16-31
+       NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, 62, NA, NA, NA, 63,  // 32-47
+       52, 53, 54, 55, 56, 57, 58, 59, 60, 61, NA, NA, NA,  0, NA, NA,  // 48-63
+       NA,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,  // 64-79
+       15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, NA, NA, NA, NA, NA,  // 80-95
+       NA, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,  // 96-111
+       41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, NA, NA, NA, NA, NA,  // 112-127
+    };
+
+    DWORD   cbDecoded;
+    DWORD   cchEncodedSize;
+    DWORD   ich;
+    DWORD   ib;
+    BYTE    b0, b1, b2, b3;
+    BYTE *  pbDecodeBuffer = (BYTE *) pDecodeBuffer;
+
+    cchEncodedSize = (DWORD)wcslen(pszEncodedString);
+    if (NULL != pcbDecoded) {
+        *pcbDecoded = 0;
+    }
+
+    if ((0 == cchEncodedSize) || (0 != (cchEncodedSize % 4))) {
+        // Input string is not sized correctly to be base64.
+        return ERROR_INVALID_PARAMETER;
+    }
+
+    // Calculate decoded buffer size.
+    cbDecoded = (cchEncodedSize + 3) / 4 * 3;
+    if (pszEncodedString[cchEncodedSize-1] == '=') {
+        if (pszEncodedString[cchEncodedSize-2] == '=') {
+            // Only one data byte is encoded in the last cluster.
+            cbDecoded -= 2;
+        }
+        else {
+            // Only two data bytes are encoded in the last cluster.
+            cbDecoded -= 1;
+        }
+    }
+
+    if (NULL != pcbDecoded) {
+        *pcbDecoded = cbDecoded;
+    }
+
+    if (cbDecodeBufferSize == 0 && pDecodeBuffer == NULL) {
+        return ERROR_SUCCESS;
+    }
+
+    if (cbDecoded > cbDecodeBufferSize) {
+        // Supplied buffer is too small.
+        return ERROR_INSUFFICIENT_BUFFER;
+    }
+
+    // Decode each four-byte cluster into the corresponding three data bytes.
+    ich = ib = 0;
+    while (ich < cchEncodedSize) {
+        b0 = DECODE(pszEncodedString[ich]); ich++;
+        b1 = DECODE(pszEncodedString[ich]); ich++;
+        b2 = DECODE(pszEncodedString[ich]); ich++;
+        b3 = DECODE(pszEncodedString[ich]); ich++;
+
+        if ((NA == b0) || (NA == b1) || (NA == b2) || (NA == b3)) {
+            // Contents of input string are not base64.
+            return ERROR_INVALID_PARAMETER;
+        }
+
+        pbDecodeBuffer[ib++] = (b0 << 2) | (b1 >> 4);
+
+        if (ib < cbDecoded) {
+            pbDecodeBuffer[ib++] = (b1 << 4) | (b2 >> 2);
+
+            if (ib < cbDecoded) {
+                pbDecodeBuffer[ib++] = (b2 << 6) | b3;
+            }
+        }
+    }
+
+    DBG_ASSERT(ib == cbDecoded);
+
+    return ERROR_SUCCESS;
+}
+
+
+DWORD
+Base64Encode(
+    __in_bcount(cbDecodedBufferSize)    VOID *  pDecodedBuffer,
+    IN      DWORD       cbDecodedBufferSize,
+    __out_ecount_opt(cchEncodedStringSize) PSTR     pszEncodedString,
+    IN      DWORD       cchEncodedStringSize,
+    __out_opt DWORD *   pcchEncoded
+    )
+/*++
+
+Routine Description:
+
+    Decode a base64-encoded string.
+
+Arguments:
+
+    pDecodedBuffer (IN) - buffer to encode.
+    cbDecodedBufferSize (IN) - size of buffer to encode.
+    cchEncodedStringSize (IN) - size of the buffer for the encoded string.
+    pszEncodedString (OUT) = the encoded string.
+    pcchEncoded (OUT) - size in characters of the encoded string.
+
+Return Values:
+
+    0 - success.
+    E_OUTOFMEMORY
+
+--*/
+{
+    static CHAR rgchEncodeTable[64] = {
+        'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
+        'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
+        'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
+        'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
+        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
+    };
+
+    DWORD   ib;
+    DWORD   ich;
+    DWORD   cchEncoded;
+    BYTE    b0, b1, b2;
+    BYTE *  pbDecodedBuffer = (BYTE *) pDecodedBuffer;
+
+    // Calculate encoded string size.
+    cchEncoded = 1 + (cbDecodedBufferSize + 2) / 3 * 4;
+
+    if (NULL != pcchEncoded) {
+        *pcchEncoded = cchEncoded;
+    }
+
+    if (cchEncodedStringSize == 0 && pszEncodedString == NULL) {
+        return ERROR_SUCCESS;
+    }
+
+    if (cchEncodedStringSize < cchEncoded) {
+        // Given buffer is too small to hold encoded string.
+        return ERROR_INSUFFICIENT_BUFFER;
+    }
+
+    // Encode data byte triplets into four-byte clusters.
+    ib = ich = 0;
+    while (ib < cbDecodedBufferSize) {
+        b0 = pbDecodedBuffer[ib++];
+        b1 = (ib < cbDecodedBufferSize) ? pbDecodedBuffer[ib++] : 0;
+        b2 = (ib < cbDecodedBufferSize) ? pbDecodedBuffer[ib++] : 0;
+
+        //
+        // The checks below for buffer overflow seems redundant to me.
+        // But it's the only way I can find to keep OACR quiet so it
+        // will have to do.
+        //
+
+        pszEncodedString[ich++] = rgchEncodeTable[b0 >> 2];
+        if ( ich >= cchEncodedStringSize )
+        {
+            DBG_ASSERT( FALSE );
+            return ERROR_BUFFER_OVERFLOW;
+        }
+
+        pszEncodedString[ich++] = rgchEncodeTable[((b0 << 4) & 0x30) | ((b1 >> 4) & 0x0f)];
+        if ( ich >= cchEncodedStringSize )
+        {
+            DBG_ASSERT( FALSE );
+            return ERROR_BUFFER_OVERFLOW;
+        }
+
+        pszEncodedString[ich++] = rgchEncodeTable[((b1 << 2) & 0x3c) | ((b2 >> 6) & 0x03)];
+        if ( ich >= cchEncodedStringSize )
+        {
+            DBG_ASSERT( FALSE );
+            return ERROR_BUFFER_OVERFLOW;
+        }
+
+        pszEncodedString[ich++] = rgchEncodeTable[b2 & 0x3f];
+        if ( ich >= cchEncodedStringSize )
+        {
+            DBG_ASSERT( FALSE );
+            return ERROR_BUFFER_OVERFLOW;
+        }
+    }
+
+    // Pad the last cluster as necessary to indicate the number of data bytes
+    // it represents.
+    switch (cbDecodedBufferSize % 3) {
+      case 0:
+        break;
+      case 1:
+        pszEncodedString[ich - 2] = '=';
+        __fallthrough;
+      case 2:
+        pszEncodedString[ich - 1] = '=';
+        break;
+    }
+
+    // Null-terminate the encoded string.
+    pszEncodedString[ich++] = '\0';
+
+    DBG_ASSERT(ich == cchEncoded);
+
+    return ERROR_SUCCESS;
+}
+
+
+DWORD
+Base64Decode(
+    __in    PCSTR       pszEncodedString,
+    __out_opt   VOID *      pDecodeBuffer,
+    __in    DWORD       cbDecodeBufferSize,
+    __out_opt DWORD *   pcbDecoded
+    )
+/*++
+
+Routine Description:
+
+    Decode a base64-encoded string.
+
+Arguments:
+
+    pszEncodedString (IN) - base64-encoded string to decode.
+    cbDecodeBufferSize (IN) - size in bytes of the decode buffer.
+    pbDecodeBuffer (OUT) - holds the decoded data.
+    pcbDecoded (OUT) - number of data bytes in the decoded data (if success or
+        STATUS_BUFFER_TOO_SMALL).
+
+Return Values:
+
+    0 - success.
+    E_OUTOFMEMORY
+    E_INVALIDARG
+
+--*/
+{
+#define NA (255)
+#define DECODE(x) (((ULONG)(x) < sizeof(rgbDecodeTable)) ? rgbDecodeTable[x] : NA)
+
+    static BYTE rgbDecodeTable[128] = {
+       NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,  // 0-15
+       NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,  // 16-31
+       NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, 62, NA, NA, NA, 63,  // 32-47
+       52, 53, 54, 55, 56, 57, 58, 59, 60, 61, NA, NA, NA,  0, NA, NA,  // 48-63
+       NA,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,  // 64-79
+       15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, NA, NA, NA, NA, NA,  // 80-95
+       NA, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,  // 96-111
+       41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, NA, NA, NA, NA, NA,  // 112-127
+    };
+
+    DWORD   cbDecoded;
+    DWORD   cchEncodedSize;
+    DWORD   ich;
+    DWORD   ib;
+    BYTE    b0, b1, b2, b3;
+    BYTE *  pbDecodeBuffer = (BYTE *) pDecodeBuffer;
+
+    cchEncodedSize = (DWORD)strlen(pszEncodedString);
+    if (NULL != pcbDecoded) {
+        *pcbDecoded = 0;
+    }
+
+    if ((0 == cchEncodedSize) || (0 != (cchEncodedSize % 4))) {
+        // Input string is not sized correctly to be base64.
+        return ERROR_INVALID_PARAMETER;
+    }
+
+    // Calculate decoded buffer size.
+    cbDecoded = (cchEncodedSize + 3) / 4 * 3;
+    if (pszEncodedString[cchEncodedSize-1] == '=') {
+        if (pszEncodedString[cchEncodedSize-2] == '=') {
+            // Only one data byte is encoded in the last cluster.
+            cbDecoded -= 2;
+        }
+        else {
+            // Only two data bytes are encoded in the last cluster.
+            cbDecoded -= 1;
+        }
+    }
+
+    if (NULL != pcbDecoded) {
+        *pcbDecoded = cbDecoded;
+    }
+
+    if (cbDecodeBufferSize == 0 && pDecodeBuffer == NULL) {
+        return ERROR_SUCCESS;
+    }
+
+    if (cbDecoded > cbDecodeBufferSize) {
+        // Supplied buffer is too small.
+        return ERROR_INSUFFICIENT_BUFFER;
+    }
+
+    // Decode each four-byte cluster into the corresponding three data bytes.
+    ich = ib = 0;
+    while (ich < cchEncodedSize) {
+        b0 = DECODE(pszEncodedString[ich]); ich++;
+        b1 = DECODE(pszEncodedString[ich]); ich++;
+        b2 = DECODE(pszEncodedString[ich]); ich++;
+        b3 = DECODE(pszEncodedString[ich]); ich++;
+
+        if ((NA == b0) || (NA == b1) || (NA == b2) || (NA == b3)) {
+            // Contents of input string are not base64.
+            return ERROR_INVALID_PARAMETER;
+        }
+
+        pbDecodeBuffer[ib++] = (b0 << 2) | (b1 >> 4);
+
+        if (ib < cbDecoded) {
+            pbDecodeBuffer[ib++] = (b1 << 4) | (b2 >> 2);
+
+            if (ib < cbDecoded) {
+                pbDecodeBuffer[ib++] = (b2 << 6) | b3;
+            }
+        }
+    }
+
+    DBG_ASSERT(ib == cbDecoded);
+
+    return ERROR_SUCCESS;
+}
+
diff --git a/src/IISIntegration/src/AspNetCoreModuleV1/IISLib/base64.h b/src/IISIntegration/src/AspNetCoreModuleV1/IISLib/base64.h
new file mode 100644
index 0000000000000000000000000000000000000000..469b074d73cd6e5b5ad5341b9f6dc7c922aecd25
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV1/IISLib/base64.h
@@ -0,0 +1,42 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#ifndef _BASE64_H_
+#define _BASE64_H_
+
+DWORD
+Base64Encode(
+    __in_bcount( cbDecodedBufferSize ) VOID *   pDecodedBuffer,
+    IN      DWORD                               cbDecodedBufferSize,
+    __out_ecount_opt( cchEncodedStringSize ) PWSTR  pszEncodedString,
+    IN      DWORD                               cchEncodedStringSize,
+    __out_opt DWORD *                           pcchEncoded
+    );
+
+DWORD
+Base64Decode(
+    __in    PCWSTR                              pszEncodedString,
+    __out_opt   VOID *                              pDecodeBuffer,
+    __in    DWORD                               cbDecodeBufferSize,
+    __out_opt DWORD *                           pcbDecoded
+    );
+
+DWORD
+Base64Encode(
+    __in_bcount( cbDecodedBufferSize ) VOID *   pDecodedBuffer,
+    IN      DWORD                               cbDecodedBufferSize,
+    __out_ecount_opt( cchEncodedStringSize ) PSTR   pszEncodedString,
+    IN      DWORD                               cchEncodedStringSize,
+    __out_opt DWORD *                           pcchEncoded
+    );
+
+DWORD
+Base64Decode(
+    __in    PCSTR                               pszEncodedString,
+    __out_opt   VOID *                              pDecodeBuffer,
+    __in    DWORD                               cbDecodeBufferSize,
+    __out_opt DWORD *                           pcbDecoded
+    );
+
+#endif // _BASE64_HXX_
+
diff --git a/src/IISIntegration/src/AspNetCoreModuleV1/IISLib/buffer.h b/src/IISIntegration/src/AspNetCoreModuleV1/IISLib/buffer.h
new file mode 100644
index 0000000000000000000000000000000000000000..1d68155387beb1c924ca53ae18f33534da80be2b
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV1/IISLib/buffer.h
@@ -0,0 +1,271 @@
+// 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 <crtdbg.h>
+
+
+//
+// BUFFER_T class shouldn't be used directly. Use BUFFER specialization class instead.
+// The only BUFFER_T partners are STRU and STRA classes.
+// BUFFER_T cannot hold other but primitive types since it doesn't call
+// constructor and destructor.
+//
+// Note: Size is in bytes.
+//
+template<typename T, DWORD LENGTH>
+class BUFFER_T
+{
+public:
+
+    BUFFER_T()
+      : m_cbBuffer( sizeof(m_rgBuffer) ),
+        m_fHeapAllocated( false ),
+        m_pBuffer(m_rgBuffer)
+    /*++
+        Description:
+
+            Default constructor where the inline buffer is used.
+
+        Arguments:
+
+            None.
+
+        Returns:
+            
+            None.
+
+    --*/    
+    {
+    }
+
+    BUFFER_T(
+        __inout_bcount(cbInit) T* pbInit, 
+        __in DWORD cbInit
+    ) : m_pBuffer( pbInit ),
+        m_cbBuffer( cbInit ),
+        m_fHeapAllocated( false )
+    /*++
+        Description:
+
+            Instantiate BUFFER, initially using pbInit as buffer
+            This is useful for stack-buffers and inline-buffer class members 
+            (see STACK_BUFFER and INLINE_BUFFER_INIT below)
+
+            BUFFER does not free pbInit.
+
+        Arguments:
+
+            pbInit - Initial buffer to use.
+            cbInit - Size of pbInit in bytes (not in elements).
+
+        Returns:
+            
+            None.
+
+    --*/
+    {
+        _ASSERTE( NULL != pbInit );
+        _ASSERTE( cbInit > 0 );
+    }
+
+    ~BUFFER_T()
+    {
+        if( IsHeapAllocated() )
+        {
+            _ASSERTE( NULL != m_pBuffer );
+            HeapFree( GetProcessHeap(), 0, m_pBuffer );
+            m_pBuffer = NULL;
+            m_cbBuffer = 0;
+            m_fHeapAllocated = false;
+        }
+    }
+
+    T*
+    QueryPtr(
+        VOID
+    ) const
+    {
+        //
+        // Return pointer to data buffer.
+        //
+        return m_pBuffer;
+    }
+
+    DWORD 
+    QuerySize(
+        VOID
+    ) const  
+    { 
+        //
+        // Return number of bytes.
+        //
+        return m_cbBuffer; 
+    }
+
+    __success(return == true)
+    bool 
+    Resize(
+        const SIZE_T   cbNewSize,
+        const bool     fZeroMemoryBeyondOldSize = false
+    )
+    /*++
+        Description:
+
+            Resizes the buffer.
+
+        Arguments:
+
+            cbNewSize   - Size in bytes to grow to.
+            fZeroMemoryBeyondOldSize 
+                        - Whether to zero the region of memory of the
+                          new buffer beyond the original size.
+
+        Returns:
+            
+            TRUE on success, FALSE on failure.
+
+    --*/
+    {
+        PVOID pNewMem;
+
+        if ( cbNewSize <= m_cbBuffer )
+        {
+            return true;
+        }
+
+        if ( cbNewSize > MAXDWORD )
+        {
+            SetLastError( ERROR_INVALID_PARAMETER );
+            return false;
+        }
+
+        DWORD dwHeapAllocFlags = fZeroMemoryBeyondOldSize ? HEAP_ZERO_MEMORY : 0;
+
+        if( IsHeapAllocated() )
+        {
+            pNewMem = HeapReAlloc( GetProcessHeap(), dwHeapAllocFlags, m_pBuffer, cbNewSize );
+        }
+        else
+        {
+            pNewMem = HeapAlloc( GetProcessHeap(), dwHeapAllocFlags, cbNewSize );
+        }
+
+        if( pNewMem == NULL )
+        {
+            SetLastError( ERROR_NOT_ENOUGH_MEMORY );
+            return false;
+        }
+
+        if( !IsHeapAllocated() ) 
+        {
+            //
+            // First time this block is allocated. Copy over old contents.
+            //
+            memcpy_s( pNewMem, static_cast<DWORD>(cbNewSize), m_pBuffer, m_cbBuffer );
+            m_fHeapAllocated = true;
+        }
+
+        m_pBuffer = reinterpret_cast<T*>(pNewMem);
+        m_cbBuffer = static_cast<DWORD>(cbNewSize);
+
+        _ASSERTE( m_pBuffer != NULL );
+
+        return true;
+    }
+
+private:
+
+    bool 
+    IsHeapAllocated(
+        VOID
+    ) const 
+    {   
+        return m_fHeapAllocated; 
+    }
+
+    //
+    // The default inline buffer.
+    // This member should be at the beginning for alignment purposes.
+    //
+    T       m_rgBuffer[LENGTH];
+    
+    //
+    // Is m_pBuffer dynamically allocated?
+    //
+    bool    m_fHeapAllocated;
+
+    //
+    // Size of the buffer as requested by client in bytes.
+    //
+    DWORD   m_cbBuffer;
+
+    //
+    // Pointer to buffer.
+    //
+    __field_bcount_full(m_cbBuffer)
+    T*      m_pBuffer;
+};
+
+//
+// Resizes the buffer by 2 if the ideal size is bigger
+// than the buffer length. That give us lg(n) allocations.
+//
+// Use template inferring like:
+//
+//   BUFFER buff;
+//   hr = ResizeBufferByTwo(buff, 100);
+//
+template<typename T, DWORD LENGTH>
+HRESULT
+ResizeBufferByTwo(
+    BUFFER_T<T,LENGTH>& Buffer,
+    SIZE_T              cbIdealSize,
+    bool                fZeroMemoryBeyondOldSize = false
+)
+{
+    if (cbIdealSize > Buffer.QuerySize())
+    {
+        if (!Buffer.Resize(max(cbIdealSize, static_cast<SIZE_T>(Buffer.QuerySize() * 2)),
+                           fZeroMemoryBeyondOldSize))
+        {
+            return E_OUTOFMEMORY;
+        }
+    }
+    return S_OK;
+}
+    
+
+//
+//
+// Lots of code uses BUFFER class to store a bunch of different
+// structures, so m_rgBuffer needs to be 8 byte aligned when it is used
+// as an opaque buffer.
+//
+#define INLINED_BUFFER_LEN 32
+typedef BUFFER_T<BYTE, INLINED_BUFFER_LEN> BUFFER;
+
+//
+// Assumption of macros below for pointer alignment purposes
+//
+C_ASSERT( sizeof(VOID*) <= sizeof(ULONGLONG) );
+
+//
+//  Declare a BUFFER that will use stack memory of <size>
+//  bytes. If the buffer overflows then a heap buffer will be allocated.
+//
+#define STACK_BUFFER( _name, _size )    \
+    ULONGLONG   __aqw##_name[ ( ( (_size) + sizeof(ULONGLONG) - 1 ) / sizeof(ULONGLONG) ) ]; \
+    BUFFER      _name( (BYTE*)__aqw##_name, sizeof(__aqw##_name) )
+
+//
+// Macros for declaring and initializing a BUFFER that will use inline memory
+// of <size> bytes as a member of an object.
+//
+#define INLINE_BUFFER( _name, _size )   \
+    ULONGLONG   __aqw##_name[ ( ( (_size) + sizeof(ULONGLONG) - 1 ) / sizeof(ULONGLONG) ) ]; \
+    BUFFER      _name;
+
+#define INLINE_BUFFER_INIT( _name )     \
+    _name( (BYTE*)__aqw##_name, sizeof( __aqw##_name ) )
diff --git a/src/IISIntegration/src/AspNetCoreModuleV1/IISLib/datetime.h b/src/IISIntegration/src/AspNetCoreModuleV1/IISLib/datetime.h
new file mode 100644
index 0000000000000000000000000000000000000000..fd09b7a6a06b1aac51c3054fdc3c6e3e9362b125
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV1/IISLib/datetime.h
@@ -0,0 +1,14 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#ifndef _DATETIME_H_
+#define _DATETIME_H_
+
+BOOL
+StringTimeToFileTime(
+    PCSTR           pszTime,
+    ULONGLONG *     pulTime
+);
+
+#endif
+
diff --git a/src/IISIntegration/src/AspNetCoreModuleV1/IISLib/dbgutil.h b/src/IISIntegration/src/AspNetCoreModuleV1/IISLib/dbgutil.h
new file mode 100644
index 0000000000000000000000000000000000000000..45c26777a91cfc354f1db8e1d3493c6aad1b24b5
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV1/IISLib/dbgutil.h
@@ -0,0 +1,102 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#ifndef _DBGUTIL_H_
+#define _DBGUTIL_H_
+
+#include <crtdbg.h>
+
+//
+// TODO 
+//      Using _CrtDbg implementation. If hooking is desired
+//      wrappers should be provided here so that we can reimplement
+//      if neecessary.
+// 
+//      IF_DEBUG/DEBUG FLAGS
+//
+//      registry configuration
+//
+
+//
+// Debug error levels for DEBUG_FLAGS_VAR.
+//
+
+#define DEBUG_FLAG_INFO     0x00000001
+#define DEBUG_FLAG_WARN     0x00000002
+#define DEBUG_FLAG_ERROR    0x00000004
+
+//
+// Predefined error level values. These are backwards from the
+// windows definitions.
+//
+
+#define DEBUG_FLAGS_INFO    (DEBUG_FLAG_ERROR | DEBUG_FLAG_WARN | DEBUG_FLAG_INFO)
+#define DEBUG_FLAGS_WARN    (DEBUG_FLAG_ERROR | DEBUG_FLAG_WARN)
+#define DEBUG_FLAGS_ERROR   (DEBUG_FLAG_ERROR)
+#define DEBUG_FLAGS_ANY     (DEBUG_FLAG_INFO | DEBUG_FLAG_WARN | DEBUG_FLAG_ERROR)
+
+//
+// Global variables to control tracing. Generally per module
+//
+
+#ifndef DEBUG_FLAGS_VAR
+#define DEBUG_FLAGS_VAR g_dwDebugFlags
+#endif
+
+#ifndef DEBUG_LABEL_VAR
+#define DEBUG_LABEL_VAR g_szDebugLabel
+#endif
+
+extern PCSTR DEBUG_LABEL_VAR;
+extern DWORD DEBUG_FLAGS_VAR;
+
+//
+// Module should make this declaration globally.
+//
+
+#define DECLARE_DEBUG_PRINT_OBJECT( _pszLabel_ )                \
+    PCSTR DEBUG_LABEL_VAR = _pszLabel_;                 \
+    DWORD DEBUG_FLAGS_VAR = DEBUG_FLAGS_ANY;            \
+
+#define DECLARE_DEBUG_PRINT_OBJECT2( _pszLabel_, _dwLevel_ )    \
+    PCSTR DEBUG_LABEL_VAR = _pszLabel_;                 \
+    DWORD DEBUG_FLAGS_VAR = _dwLevel_;                  \
+
+//
+// This doesn't do anything now. Should be safe to call in dll main.
+//
+
+#define CREATE_DEBUG_PRINT_OBJECT
+
+//
+// Trace macros
+//
+
+#define DBG_CONTEXT     _CRT_WARN, __FILE__, __LINE__, DEBUG_LABEL_VAR
+
+#ifdef DEBUG
+#define DBGINFO(args)   \
+{if (DEBUG_FLAGS_VAR & DEBUG_FLAG_INFO) { _CrtDbgReport args; }}
+#define DBGWARN(args)   \
+{if (DEBUG_FLAGS_VAR & DEBUG_FLAG_WARN) { _CrtDbgReport args; }}
+#define DBGERROR(args)  \
+{if (DEBUG_FLAGS_VAR & DEBUG_FLAG_ERROR) { _CrtDbgReport args; }}
+#else
+#define DBGINFO
+#define DBGWARN
+#define DBGERROR
+#endif
+
+#define DBGPRINTF           DBGINFO
+
+//
+// Simple error traces
+//
+
+#define DBGERROR_HR( _hr_ ) \
+    DBGERROR((DBG_CONTEXT, "hr=0x%x\n", _hr_))
+
+#define DBGERROR_STATUS( _status_ ) \
+    DBGERROR((DBG_CONTEXT, "status=%d\n", _status_))
+
+#endif
diff --git a/src/IISIntegration/src/AspNetCoreModuleV1/IISLib/hashfn.h b/src/IISIntegration/src/AspNetCoreModuleV1/IISLib/hashfn.h
new file mode 100644
index 0000000000000000000000000000000000000000..a7bfeda2cfade8e065c99a404f2b609032e92d2b
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV1/IISLib/hashfn.h
@@ -0,0 +1,325 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#ifndef __HASHFN_H__
+#define __HASHFN_H__
+
+
+// Produce a scrambled, randomish number in the range 0 to RANDOM_PRIME-1.
+// Applying this to the results of the other hash functions is likely to
+// produce a much better distribution, especially for the identity hash
+// functions such as Hash(char c), where records will tend to cluster at
+// the low end of the hashtable otherwise.  LKRhash applies this internally
+// to all hash signatures for exactly this reason.
+
+inline DWORD
+HashScramble(DWORD dwHash)
+{
+    // Here are 10 primes slightly greater than 10^9
+    //  1000000007, 1000000009, 1000000021, 1000000033, 1000000087,
+    //  1000000093, 1000000097, 1000000103, 1000000123, 1000000181.
+
+    // default value for "scrambling constant"
+    const DWORD RANDOM_CONSTANT = 314159269UL;
+    // large prime number, also used for scrambling
+    const DWORD RANDOM_PRIME =   1000000007UL;
+
+    return (RANDOM_CONSTANT * dwHash) % RANDOM_PRIME ;
+}
+
+
+// Faster scrambling function suggested by Eric Jacobsen
+
+inline DWORD
+HashRandomizeBits(DWORD dw)
+{
+	return (((dw * 1103515245 + 12345) >> 16)
+            | ((dw * 69069 + 1) & 0xffff0000));
+}
+
+
+// Small prime number used as a multiplier in the supplied hash functions
+const DWORD HASH_MULTIPLIER = 101;
+
+#undef HASH_SHIFT_MULTIPLY
+
+#ifdef HASH_SHIFT_MULTIPLY
+# define HASH_MULTIPLY(dw)   (((dw) << 7) - (dw))
+#else
+# define HASH_MULTIPLY(dw)   ((dw) * HASH_MULTIPLIER)
+#endif
+
+// Fast, simple hash function that tends to give a good distribution.
+// Apply HashScramble to the result if you're using this for something
+// other than LKRhash.
+
+inline DWORD
+HashString(
+    const char* psz,
+    DWORD       dwHash = 0)
+{
+    // force compiler to use unsigned arithmetic
+    const unsigned char* upsz = (const unsigned char*) psz;
+
+    for ( ; *upsz; ++upsz)
+        dwHash = HASH_MULTIPLY(dwHash) + *upsz;
+
+    return dwHash;
+}
+
+inline DWORD
+HashString(
+    __in_ecount(cch) const char* psz,
+    __in DWORD cch,
+    __in DWORD dwHash
+)
+{
+    // force compiler to use unsigned arithmetic
+    const unsigned char* upsz = (const unsigned char*) psz;
+
+    for (DWORD Index = 0; 
+         Index < cch;
+         ++Index, ++upsz)
+    {
+        dwHash = HASH_MULTIPLY(dwHash) + *upsz;
+    }
+
+    return dwHash;
+}
+
+
+// Unicode version of above
+
+inline DWORD
+HashString(
+    const wchar_t* pwsz,
+    DWORD          dwHash = 0)
+{
+    for (  ;  *pwsz;  ++pwsz)
+        dwHash = HASH_MULTIPLY(dwHash) + *pwsz;
+
+    return dwHash;
+}
+
+// Based on length of the string instead of null-terminating character
+
+inline DWORD
+HashString(
+    __in_ecount(cch) const wchar_t* pwsz,
+    __in DWORD          cch,
+    __in DWORD          dwHash
+)
+{
+    for (DWORD Index = 0; 
+         Index < cch;
+         ++Index, ++pwsz)
+    {
+        dwHash = HASH_MULTIPLY(dwHash) + *pwsz;
+    }
+
+    return dwHash;
+}
+
+
+// Quick-'n'-dirty case-insensitive string hash function.
+// Make sure that you follow up with _stricmp or _mbsicmp.  You should
+// also cache the length of strings and check those first.  Caching
+// an uppercase version of a string can help too.
+// Again, apply HashScramble to the result if using with something other
+// than LKRhash.
+// Note: this is not really adequate for MBCS strings.
+
+inline DWORD
+HashStringNoCase(
+    const char* psz,
+    DWORD       dwHash = 0)
+{
+    const unsigned char* upsz = (const unsigned char*) psz;
+
+    for (  ;  *upsz;  ++upsz)
+        dwHash = HASH_MULTIPLY(dwHash)
+                    + (*upsz & 0xDF);  // strip off lowercase bit
+
+    return dwHash;
+}
+
+inline DWORD
+HashStringNoCase(
+    __in_ecount(cch)
+    const char* psz,
+    SIZE_T      cch,
+    DWORD       dwHash)
+{
+    const unsigned char* upsz = (const unsigned char*) psz;
+
+    for (SIZE_T Index = 0;
+         Index < cch;
+         ++Index, ++upsz)
+    {
+        dwHash = HASH_MULTIPLY(dwHash)
+                    + (*upsz & 0xDF);  // strip off lowercase bit
+    }
+    return dwHash;
+}
+
+
+// Unicode version of above
+
+inline DWORD
+HashStringNoCase(
+    const wchar_t* pwsz,
+    DWORD          dwHash = 0)
+{
+    for (  ;  *pwsz;  ++pwsz)
+        dwHash = HASH_MULTIPLY(dwHash) + (*pwsz & 0xFFDF);
+
+    return dwHash;
+}
+
+// Unicode version of above with length
+
+inline DWORD
+HashStringNoCase(
+    __in_ecount(cch)
+    const wchar_t* pwsz,
+    SIZE_T         cch,
+    DWORD          dwHash)
+{
+    for (SIZE_T Index = 0;
+         Index < cch;
+         ++Index, ++pwsz)
+    {
+        dwHash = HASH_MULTIPLY(dwHash) + (*pwsz & 0xFFDF);
+    }
+    return dwHash;
+}
+
+
+// HashBlob returns the hash of a blob of arbitrary binary data.
+// 
+// Warning: HashBlob is generally not the right way to hash a class object.
+// Consider:
+//     class CFoo {
+//     public:
+//         char   m_ch;
+//         double m_d;
+//         char*  m_psz;
+//     };
+// 
+//     inline DWORD Hash(const CFoo& rFoo)
+//     { return HashBlob(&rFoo, sizeof(CFoo)); }
+//
+// This is the wrong way to hash a CFoo for two reasons: (a) there will be
+// a 7-byte gap between m_ch and m_d imposed by the alignment restrictions
+// of doubles, which will be filled with random data (usually non-zero for
+// stack variables), and (b) it hashes the address (rather than the
+// contents) of the string m_psz.  Similarly,
+// 
+//     bool operator==(const CFoo& rFoo1, const CFoo& rFoo2)
+//     { return memcmp(&rFoo1, &rFoo2, sizeof(CFoo)) == 0; }
+//
+// does the wrong thing.  Much better to do this:
+//
+//     DWORD Hash(const CFoo& rFoo)
+//     {
+//         return HashString(rFoo.m_psz,
+//                           HASH_MULTIPLIER * Hash(rFoo.m_ch)
+//                              + Hash(rFoo.m_d));
+//     }
+//
+// Again, apply HashScramble if using with something other than LKRhash.
+
+inline DWORD
+HashBlob(
+    const void* pv,
+    size_t      cb,
+    DWORD       dwHash = 0)
+{
+    const BYTE * pb = static_cast<const BYTE *>(pv);
+
+    while (cb-- > 0)
+        dwHash = HASH_MULTIPLY(dwHash) + *pb++;
+
+    return dwHash;
+}
+
+
+
+//
+// Overloaded hash functions for all the major builtin types.
+// Again, apply HashScramble to result if using with something other than
+// LKRhash.
+//
+
+inline DWORD Hash(const char* psz)
+{ return HashString(psz); }
+
+inline DWORD Hash(const unsigned char* pusz)
+{ return HashString(reinterpret_cast<const char*>(pusz)); }
+
+inline DWORD Hash(const signed char* pssz)
+{ return HashString(reinterpret_cast<const char*>(pssz)); }
+
+inline DWORD Hash(const wchar_t* pwsz)
+{ return HashString(pwsz); }
+
+inline DWORD
+Hash(
+    const GUID* pguid,
+    DWORD       dwHash = 0)
+{
+    
+    return * reinterpret_cast<const DWORD *>(const_cast<GUID*>(pguid)) + dwHash;
+}
+
+// Identity hash functions: scalar values map to themselves
+inline DWORD Hash(char c)
+{ return c; }
+
+inline DWORD Hash(unsigned char uc)
+{ return uc; }
+
+inline DWORD Hash(signed char sc)
+{ return sc; }
+
+inline DWORD Hash(short sh)
+{ return sh; }
+
+inline DWORD Hash(unsigned short ush)
+{ return ush; }
+
+inline DWORD Hash(int i)
+{ return i; }
+
+inline DWORD Hash(unsigned int u)
+{ return u; }
+
+inline DWORD Hash(long l)
+{ return l; }
+
+inline DWORD Hash(unsigned long ul)
+{ return ul; }
+
+inline DWORD Hash(float f)
+{
+    // be careful of rounding errors when computing keys
+    union {
+        float f;
+        DWORD dw;
+    } u;
+    u.f = f;
+    return u.dw;
+}
+
+inline DWORD Hash(double dbl)
+{
+    // be careful of rounding errors when computing keys
+    union {
+        double dbl;
+        DWORD  dw[2];
+    } u;
+    u.dbl = dbl;
+    return u.dw[0] * HASH_MULTIPLIER + u.dw[1];
+}
+
+#endif // __HASHFN_H__
diff --git a/src/IISIntegration/src/AspNetCoreModuleV1/IISLib/hashtable.h b/src/IISIntegration/src/AspNetCoreModuleV1/IISLib/hashtable.h
new file mode 100644
index 0000000000000000000000000000000000000000..9319e5643d34c36c1ebb4989b5eb7adef8436ba4
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV1/IISLib/hashtable.h
@@ -0,0 +1,666 @@
+// 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 <crtdbg.h>
+#include "rwlock.h"
+#include "prime.h"
+
+template <class _Record>
+class HASH_NODE
+{
+    template <class _Record, class _Key>
+    friend class HASH_TABLE;
+
+    HASH_NODE(
+        _Record *       pRecord,
+        DWORD           dwHash
+    ) : _pNext (NULL),
+        _pRecord (pRecord),
+        _dwHash (dwHash)
+    {}
+
+    ~HASH_NODE()
+    {
+        _ASSERTE(_pRecord == NULL);
+    }
+
+ private:
+    // Next node in the hash table look-aside
+    HASH_NODE<_Record> *_pNext;
+
+    // actual record
+    _Record *           _pRecord;
+
+    // hash value
+    DWORD               _dwHash;
+};
+
+template <class _Record, class _Key>
+class HASH_TABLE
+{
+protected:
+    typedef BOOL
+    (PFN_DELETE_IF)(
+        _Record *           pRecord,
+        PVOID               pvContext
+    );
+
+    typedef VOID
+    (PFN_APPLY)(
+        _Record *           pRecord,
+        PVOID               pvContext
+    );
+
+public:
+    HASH_TABLE(
+        VOID
+    )
+      : _ppBuckets( NULL ),
+        _nBuckets( 0 ),
+        _nItems( 0 )
+    {
+    }
+
+    virtual
+    ~HASH_TABLE();
+
+    virtual
+    VOID
+    ReferenceRecord(
+        _Record *   pRecord
+    ) = 0;
+
+    virtual
+    VOID
+    DereferenceRecord(
+        _Record *   pRecord
+    ) = 0;
+
+    virtual
+    _Key
+    ExtractKey(
+        _Record *   pRecord
+    ) = 0;
+
+    virtual
+    DWORD
+    CalcKeyHash(
+        _Key        key
+    ) = 0;
+
+    virtual
+    BOOL
+    EqualKeys(
+        _Key        key1,
+        _Key        key2
+    ) = 0;
+
+    DWORD
+    Count(
+        VOID
+    ) const;
+
+    bool
+    IsInitialized(
+        VOID
+    ) const;
+
+    virtual
+    VOID
+    Clear();
+
+    HRESULT
+    Initialize(
+        DWORD           nBucketSize
+    );
+
+    virtual
+    VOID
+    FindKey(
+        _Key        key,
+        _Record **  ppRecord
+    );
+
+    virtual
+    HRESULT
+    InsertRecord(
+        _Record *   pRecord
+    );
+
+    virtual
+    VOID
+    DeleteKey(
+        _Key        key
+    );
+
+    virtual
+    VOID
+    DeleteIf(
+        PFN_DELETE_IF       pfnDeleteIf,
+        PVOID               pvContext
+    );
+
+    VOID
+    Apply(
+        PFN_APPLY           pfnApply,
+        PVOID               pvContext
+    );
+
+private:
+
+    __success(*ppNode != NULL && return != FALSE)
+    BOOL
+    FindNodeInternal(
+        _Key                    key,
+        DWORD                   dwHash,
+        __deref_out
+        HASH_NODE<_Record> **   ppNode,
+        __deref_opt_out
+        HASH_NODE<_Record> ***  pppPreviousNodeNextPointer = NULL
+    );
+
+    VOID
+    DeleteNode(
+        HASH_NODE<_Record> *    pNode
+    )
+    {
+        if (pNode->_pRecord != NULL)
+        {
+            DereferenceRecord(pNode->_pRecord);
+            pNode->_pRecord = NULL;
+        }
+
+        delete pNode;
+    }
+
+    VOID
+    RehashTableIfNeeded(
+        VOID
+    );
+
+    HASH_NODE<_Record> **   _ppBuckets;
+    DWORD                   _nBuckets;
+    DWORD                   _nItems;
+    //
+    // Allow to use lock object in const methods.
+    //
+    mutable
+    CWSDRWLock              _tableLock;
+};
+
+template <class _Record, class _Key>
+HRESULT
+HASH_TABLE<_Record,_Key>::Initialize(
+    DWORD   nBuckets
+)
+{
+    HRESULT hr = S_OK;
+
+    if ( nBuckets == 0 )
+    {
+        hr = E_INVALIDARG;
+        goto Failed;
+    }
+
+    if (nBuckets >= MAXDWORD/sizeof(HASH_NODE<_Record> *))
+    {
+        hr = E_INVALIDARG;
+        goto Failed;
+    }
+
+    _ASSERTE(_ppBuckets == NULL );
+    if ( _ppBuckets != NULL )
+    {
+        hr = E_INVALIDARG;
+        goto Failed;
+    }
+
+    hr = _tableLock.Init();
+    if ( FAILED( hr ) )
+    {
+        goto Failed;
+    }
+
+    _ppBuckets = (HASH_NODE<_Record> **)HeapAlloc(
+                            GetProcessHeap(),
+                            HEAP_ZERO_MEMORY,
+                            nBuckets*sizeof(HASH_NODE<_Record> *));
+    if (_ppBuckets == NULL)
+    {
+        hr = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
+        goto Failed;
+    }
+    _nBuckets = nBuckets;
+
+    return S_OK;
+
+Failed:
+
+    if (_ppBuckets)
+    {
+        HeapFree(GetProcessHeap(),
+                 0,
+                 _ppBuckets);
+        _ppBuckets = NULL;
+    }
+
+    return hr;
+}
+
+
+template <class _Record, class _Key>
+HASH_TABLE<_Record,_Key>::~HASH_TABLE()
+{
+    if (_ppBuckets == NULL)
+    {
+        return;
+    }
+
+    _ASSERTE(_nItems == 0);
+
+    HeapFree(GetProcessHeap(),
+             0,
+             _ppBuckets);
+    _ppBuckets = NULL;
+    _nBuckets = 0;
+}
+
+template< class _Record, class _Key>
+DWORD
+HASH_TABLE<_Record,_Key>::Count() const
+{
+    return _nItems;
+}
+
+template< class _Record, class _Key>
+bool
+HASH_TABLE<_Record,_Key>::IsInitialized(
+    VOID
+) const
+{
+    return _ppBuckets != NULL;
+}
+
+
+template <class _Record, class _Key>
+VOID
+HASH_TABLE<_Record,_Key>::Clear()
+{
+    HASH_NODE<_Record> *pCurrent;
+    HASH_NODE<_Record> *pNext;
+
+    // This is here in the off cases where someone instantiates a hashtable
+    // and then does an automatic "clear" before its destruction WITHOUT
+    // ever initializing it.
+    if ( ! _tableLock.QueryInited() )
+    {
+        return;
+    }
+
+    _tableLock.ExclusiveAcquire();
+
+    for (DWORD i=0; i<_nBuckets; i++)
+    {
+        pCurrent = _ppBuckets[i];
+        _ppBuckets[i] = NULL;
+        while (pCurrent != NULL)
+        {
+            pNext = pCurrent->_pNext;
+            DeleteNode(pCurrent);
+            pCurrent = pNext;
+        }
+    }
+
+    _nItems = 0;
+    _tableLock.ExclusiveRelease();
+}
+
+template <class _Record, class _Key>
+__success(*ppNode != NULL && return != FALSE)
+BOOL
+HASH_TABLE<_Record,_Key>::FindNodeInternal(
+    _Key                    key,
+    DWORD                   dwHash,
+    __deref_out
+    HASH_NODE<_Record> **   ppNode,
+    __deref_opt_out
+    HASH_NODE<_Record> ***  pppPreviousNodeNextPointer
+)
+/*++
+  Return value indicates whether the item is found
+  key, dwHash - key and hash for the node to find
+  ppNode - on successful return, the node found, on failed return, the first
+  node with hash value greater than the node to be found
+  pppPreviousNodeNextPointer - the pointer to previous node's _pNext
+
+  This routine may be called under either read or write lock
+--*/
+{
+    HASH_NODE<_Record> **ppPreviousNodeNextPointer;
+    HASH_NODE<_Record> *pNode;
+    BOOL fFound = FALSE;
+
+    ppPreviousNodeNextPointer = _ppBuckets + (dwHash % _nBuckets);
+    pNode = *ppPreviousNodeNextPointer;
+    while (pNode != NULL)
+    {
+        if (pNode->_dwHash == dwHash)
+        {
+            if (EqualKeys(key,
+                          ExtractKey(pNode->_pRecord)))
+            {
+                fFound = TRUE;
+                break;
+            }
+        }
+        else if (pNode->_dwHash > dwHash)
+        {
+            break;
+        }
+
+        ppPreviousNodeNextPointer = &(pNode->_pNext);
+        pNode = *ppPreviousNodeNextPointer;
+    }
+
+    __analysis_assume( (pNode == NULL && fFound == FALSE) ||
+                       (pNode != NULL && fFound == TRUE ) );
+    *ppNode = pNode;
+    if (pppPreviousNodeNextPointer != NULL)
+    {
+        *pppPreviousNodeNextPointer = ppPreviousNodeNextPointer;
+    }
+    return fFound;
+}
+
+template <class _Record, class _Key>
+VOID
+HASH_TABLE<_Record,_Key>::FindKey(
+    _Key                key,
+    _Record **          ppRecord
+)
+{
+    HASH_NODE<_Record> *pNode;
+
+    *ppRecord = NULL;
+
+    DWORD dwHash = CalcKeyHash(key);
+
+    _tableLock.SharedAcquire();
+
+    if (FindNodeInternal(key, dwHash, &pNode) &&
+        pNode->_pRecord != NULL)
+    {
+        ReferenceRecord(pNode->_pRecord);
+        *ppRecord = pNode->_pRecord;
+    }
+
+    _tableLock.SharedRelease();
+}
+
+template <class _Record, class _Key>
+HRESULT
+HASH_TABLE<_Record,_Key>::InsertRecord(
+    _Record *           pRecord
+)
+/*++
+  This method inserts a node for this record and also empty nodes for paths
+  in the heirarchy leading upto this path
+
+  The insert is done under only a read-lock - this is possible by keeping
+  the hashes in a bucket in increasing order and using interlocked operations
+  to actually insert the item in the hash-bucket lookaside list and the parent
+  children list
+
+  Returns HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS) if the record already exists.
+  Never leak this error to the end user because "*file* already exists" may be confusing.
+--*/
+{
+    BOOL fLocked = FALSE;
+    _Key key = ExtractKey(pRecord);
+    DWORD dwHash = CalcKeyHash(key);
+    HRESULT hr = S_OK;
+    HASH_NODE<_Record> *    pNewNode;
+    HASH_NODE<_Record> *    pNextNode;
+    HASH_NODE<_Record> **   ppPreviousNodeNextPointer;
+
+    //
+    // Ownership of pRecord is not transferred to pNewNode yet, so remember
+    // to either set it to null before deleting pNewNode or add an extra
+    // reference later - this is to make sure we do not do an extra ref/deref
+    // which users may view as getting flushed out of the hash-table
+    //
+    pNewNode = new HASH_NODE<_Record>(pRecord, dwHash);
+    if (pNewNode == NULL)
+    {
+        hr = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
+        goto Finished;
+    }
+
+    _tableLock.SharedAcquire();
+    fLocked = TRUE;
+
+    do
+    {
+        //
+        // Find the right place to add this node
+        //
+        if (FindNodeInternal(key, dwHash, &pNextNode, &ppPreviousNodeNextPointer))
+        {
+            //
+            // If node already there, return error
+            //
+            pNewNode->_pRecord = NULL;
+            DeleteNode(pNewNode);
+
+            //
+            // We should never leak this error to the end user
+            // because "file already exists" may be confusing.
+            //
+            hr = HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS);
+            goto Finished;
+        }
+
+        //
+        // If another node got inserted in between, we will have to retry
+        //
+        pNewNode->_pNext = pNextNode;
+    } while (InterlockedCompareExchangePointer((PVOID *)ppPreviousNodeNextPointer,
+                                               pNewNode,
+                                               pNextNode) != pNextNode);
+    // pass ownership of pRecord now
+    if (pRecord != NULL)
+    {
+        ReferenceRecord(pRecord);
+        pRecord = NULL;
+    }
+    InterlockedIncrement((LONG *)&_nItems);
+
+Finished:
+
+    if (fLocked)
+    {
+        _tableLock.SharedRelease();
+    }
+
+    if (SUCCEEDED(hr))
+    {
+        RehashTableIfNeeded();
+    }
+
+    return hr;
+}
+
+template <class _Record, class _Key>
+VOID
+HASH_TABLE<_Record,_Key>::DeleteKey(
+    _Key        key
+)
+{
+    HASH_NODE<_Record> *pNode;
+    HASH_NODE<_Record> **ppPreviousNodeNextPointer;
+
+    DWORD dwHash = CalcKeyHash(key);
+
+    _tableLock.ExclusiveAcquire();
+
+    if (FindNodeInternal(key, dwHash, &pNode, &ppPreviousNodeNextPointer))
+    {
+        *ppPreviousNodeNextPointer = pNode->_pNext;
+        DeleteNode(pNode);
+        _nItems--;
+    }
+
+    _tableLock.ExclusiveRelease();
+}
+
+template <class _Record, class _Key>
+VOID
+HASH_TABLE<_Record,_Key>::DeleteIf(
+    PFN_DELETE_IF               pfnDeleteIf,
+    PVOID                       pvContext
+)
+{
+    HASH_NODE<_Record> *pNode;
+    HASH_NODE<_Record> **ppPreviousNodeNextPointer;
+
+    _tableLock.ExclusiveAcquire();
+
+    for (DWORD i=0; i<_nBuckets; i++)
+    {
+        ppPreviousNodeNextPointer = _ppBuckets + i;
+        pNode = *ppPreviousNodeNextPointer;
+        while (pNode != NULL)
+        {
+            //
+            // Non empty nodes deleted based on DeleteIf, empty nodes deleted
+            // if they have no children
+            //
+            if (pfnDeleteIf(pNode->_pRecord, pvContext))
+            {
+                *ppPreviousNodeNextPointer = pNode->_pNext;
+                DeleteNode(pNode);
+                _nItems--;
+            }
+            else
+            {
+                ppPreviousNodeNextPointer = &pNode->_pNext;
+            }
+
+            pNode = *ppPreviousNodeNextPointer;
+        }
+    }
+
+    _tableLock.ExclusiveRelease();
+}
+
+template <class _Record, class _Key>
+VOID
+HASH_TABLE<_Record,_Key>::Apply(
+    PFN_APPLY                   pfnApply,
+    PVOID                       pvContext
+)
+{
+    HASH_NODE<_Record> *pNode;
+
+    _tableLock.SharedAcquire();
+
+    for (DWORD i=0; i<_nBuckets; i++)
+    {
+        pNode = _ppBuckets[i];
+        while (pNode != NULL)
+        {
+            if (pNode->_pRecord != NULL)
+            {
+                pfnApply(pNode->_pRecord, pvContext);
+            }
+
+            pNode = pNode->_pNext;
+        }
+    }
+
+    _tableLock.SharedRelease();
+}
+
+template <class _Record, class _Key>
+VOID
+HASH_TABLE<_Record,_Key>::RehashTableIfNeeded(
+    VOID
+)
+{
+    HASH_NODE<_Record> **ppBuckets;
+    DWORD nBuckets;
+    HASH_NODE<_Record> *pNode;
+    HASH_NODE<_Record> *pNextNode;
+    HASH_NODE<_Record> **ppNextPointer;
+    HASH_NODE<_Record> *pNewNextNode;
+    DWORD               nNewBuckets;
+
+    //
+    // If number of items has become too many, we will double the hash table
+    // size (we never reduce it however)
+    //
+    if (_nItems <= PRIME::GetPrime(2*_nBuckets))
+    {
+        return;
+    }
+
+    _tableLock.ExclusiveAcquire();
+
+    nNewBuckets = PRIME::GetPrime(2*_nBuckets);
+
+    if (_nItems <= nNewBuckets)
+    {
+        goto Finished;
+    }
+
+    nBuckets = nNewBuckets;
+    if (nBuckets >= 0xffffffff/sizeof(HASH_NODE<_Record> *))
+    {
+        goto Finished;
+    }
+    ppBuckets = (HASH_NODE<_Record> **)HeapAlloc(
+                        GetProcessHeap(),
+                        HEAP_ZERO_MEMORY,
+                        nBuckets*sizeof(HASH_NODE<_Record> *));
+    if (ppBuckets == NULL)
+    {
+        goto Finished;
+    }
+
+    //
+    // Take out nodes from the old hash table and insert in the new one, make
+    // sure to keep the hashes in increasing order
+    //
+    for (DWORD i=0; i<_nBuckets; i++)
+    {
+        pNode = _ppBuckets[i];
+        while (pNode != NULL)
+        {
+            pNextNode = pNode->_pNext;
+
+            ppNextPointer = ppBuckets + (pNode->_dwHash % nBuckets);
+            pNewNextNode = *ppNextPointer;
+            while (pNewNextNode != NULL &&
+                   pNewNextNode->_dwHash <= pNode->_dwHash)
+            {
+                ppNextPointer = &pNewNextNode->_pNext;
+                pNewNextNode = pNewNextNode->_pNext;
+            }
+            pNode->_pNext = pNewNextNode;
+            *ppNextPointer = pNode;
+
+            pNode = pNextNode;
+        }
+    }
+
+    HeapFree(GetProcessHeap(), 0, _ppBuckets);
+    _ppBuckets = ppBuckets;
+    _nBuckets = nBuckets;
+    ppBuckets = NULL;
+
+Finished:
+
+    _tableLock.ExclusiveRelease();
+}
diff --git a/src/IISIntegration/src/AspNetCoreModuleV1/IISLib/listentry.h b/src/IISIntegration/src/AspNetCoreModuleV1/IISLib/listentry.h
new file mode 100644
index 0000000000000000000000000000000000000000..80b70e97a937a07b8337eea20c81a09de3ec0a68
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV1/IISLib/listentry.h
@@ -0,0 +1,163 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#pragma once
+
+#ifndef _LIST_ENTRY_H
+#define _LIST_ENTRY_H
+
+//
+//  Doubly-linked list manipulation routines.
+//
+
+
+#define InitializeListHead32(ListHead) (\
+    (ListHead)->Flink = (ListHead)->Blink = PtrToUlong((ListHead)))
+
+
+FORCEINLINE
+VOID
+InitializeListHead(
+    IN PLIST_ENTRY ListHead
+    )
+{
+    ListHead->Flink = ListHead->Blink = ListHead;
+}
+
+FORCEINLINE
+BOOLEAN
+IsListEmpty(
+    IN const LIST_ENTRY * ListHead
+    )
+{
+    return (BOOLEAN)(ListHead->Flink == ListHead);
+}
+
+FORCEINLINE
+BOOLEAN
+RemoveEntryList(
+    IN PLIST_ENTRY Entry
+    )
+{
+    PLIST_ENTRY Blink;
+    PLIST_ENTRY Flink;
+
+    Flink = Entry->Flink;
+    Blink = Entry->Blink;
+    Blink->Flink = Flink;
+    Flink->Blink = Blink;
+    return (BOOLEAN)(Flink == Blink);
+}
+
+FORCEINLINE
+PLIST_ENTRY
+RemoveHeadList(
+    IN PLIST_ENTRY ListHead
+    )
+{
+    PLIST_ENTRY Flink;
+    PLIST_ENTRY Entry;
+
+    Entry = ListHead->Flink;
+    Flink = Entry->Flink;
+    ListHead->Flink = Flink;
+    Flink->Blink = ListHead;
+    return Entry;
+}
+
+
+
+FORCEINLINE
+PLIST_ENTRY
+RemoveTailList(
+    IN PLIST_ENTRY ListHead
+    )
+{
+    PLIST_ENTRY Blink;
+    PLIST_ENTRY Entry;
+
+    Entry = ListHead->Blink;
+    Blink = Entry->Blink;
+    ListHead->Blink = Blink;
+    Blink->Flink = ListHead;
+    return Entry;
+}
+
+
+FORCEINLINE
+VOID
+InsertTailList(
+    IN PLIST_ENTRY ListHead,
+    IN PLIST_ENTRY Entry
+    )
+{
+    PLIST_ENTRY Blink;
+
+    Blink = ListHead->Blink;
+    Entry->Flink = ListHead;
+    Entry->Blink = Blink;
+    Blink->Flink = Entry;
+    ListHead->Blink = Entry;
+}
+
+
+FORCEINLINE
+VOID
+InsertHeadList(
+    IN PLIST_ENTRY ListHead,
+    IN PLIST_ENTRY Entry
+    )
+{
+    PLIST_ENTRY Flink;
+
+    Flink = ListHead->Flink;
+    Entry->Flink = Flink;
+    Entry->Blink = ListHead;
+    Flink->Blink = Entry;
+    ListHead->Flink = Entry;
+}
+
+FORCEINLINE
+VOID
+AppendTailList(
+    IN PLIST_ENTRY ListHead,
+    IN PLIST_ENTRY ListToAppend
+    )
+{
+    PLIST_ENTRY ListEnd = ListHead->Blink;
+
+    ListHead->Blink->Flink = ListToAppend;
+    ListHead->Blink = ListToAppend->Blink;
+    ListToAppend->Blink->Flink = ListHead;
+    ListToAppend->Blink = ListEnd;
+}
+
+FORCEINLINE
+PSINGLE_LIST_ENTRY
+PopEntryList(
+    PSINGLE_LIST_ENTRY ListHead
+    )
+{
+    PSINGLE_LIST_ENTRY FirstEntry;
+    FirstEntry = ListHead->Next;
+    if (FirstEntry != NULL) {
+        ListHead->Next = FirstEntry->Next;
+    }
+
+    return FirstEntry;
+}
+
+
+FORCEINLINE
+VOID
+PushEntryList(
+    PSINGLE_LIST_ENTRY ListHead,
+    PSINGLE_LIST_ENTRY Entry
+    )
+{
+    Entry->Next = ListHead->Next;
+    ListHead->Next = Entry;
+}
+
+
+#endif
diff --git a/src/IISIntegration/src/AspNetCoreModuleV1/IISLib/macros.h b/src/IISIntegration/src/AspNetCoreModuleV1/IISLib/macros.h
new file mode 100644
index 0000000000000000000000000000000000000000..960f663a98c1dba4654365e83d1c9ec129c68577
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV1/IISLib/macros.h
@@ -0,0 +1,63 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#ifndef _MACROS_H
+#define _MACROS_H
+
+//
+// The DIFF macro should be used around an expression involving pointer
+// subtraction. The expression passed to DIFF is cast to a size_t type,
+// allowing the result to be easily assigned to any 32-bit variable or
+// passed to a function expecting a 32-bit argument.
+//
+
+#define DIFF(x)     ((size_t)(x))
+
+// Change a hexadecimal digit to its numerical equivalent
+#define TOHEX( ch )                                     \
+    ((ch) > L'9' ?                                      \
+        (ch) >= L'a' ?                                  \
+            (ch) - L'a' + 10 :                          \
+            (ch) - L'A' + 10                            \
+        : (ch) - L'0')
+
+
+// Change a number to its Hexadecimal equivalent
+
+#define TODIGIT( nDigit )                               \
+     (CHAR)((nDigit) > 9 ?                              \
+          (nDigit) - 10 + 'A'                           \
+        : (nDigit) + '0')
+
+
+inline int
+SAFEIsSpace(UCHAR c)
+{
+    return isspace( c );
+}
+
+inline int
+SAFEIsAlNum(UCHAR c)
+{
+    return isalnum( c );
+}
+
+inline int
+SAFEIsAlpha(UCHAR c)
+{
+    return isalpha( c );
+}
+
+inline int
+SAFEIsXDigit(UCHAR c)
+{
+    return isxdigit( c );
+}
+
+inline int
+SAFEIsDigit(UCHAR c)
+{
+    return isdigit( c );
+}
+
+#endif // _MACROS_H
diff --git a/src/IISIntegration/src/AspNetCoreModuleV1/IISLib/multisz.cpp b/src/IISIntegration/src/AspNetCoreModuleV1/IISLib/multisz.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..775ec4cd0c96fe11a6c5268d5fd9e5114562e562
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV1/IISLib/multisz.cpp
@@ -0,0 +1,474 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+
+#pragma warning (disable : 4267)
+
+#include "precomp.h"
+#include "multisz.h"
+#include <tchar.h>
+
+//
+//  Private Definitions
+//
+
+#define MAXULONG 4294967295
+#define ISWHITE( ch )       ((ch) == L' ' || (ch) == L'\t' || (ch) == L'\r')
+
+//
+//  When appending data, this is the extra amount we request to avoid
+//  reallocations
+//
+#define STR_SLOP        128
+
+
+DWORD
+MULTISZ::CalcLength( const WCHAR * str,
+                     LPDWORD pcStrings )
+{
+    DWORD count = 0;
+    DWORD total = 1;
+    DWORD len;
+
+    while( *str ) {
+        len = ::wcslen( str ) + 1;
+        total += len;
+        str += len;
+        count++;
+    }
+
+    if( pcStrings != NULL ) {
+        *pcStrings = count;
+    }
+
+    return total;
+
+}   // MULTISZ::CalcLength
+
+
+BOOL
+MULTISZ::FindString( const WCHAR * str )
+{
+
+    WCHAR * multisz;
+
+    //
+    // Sanity check.
+    //
+
+    DBG_ASSERT( QueryStr() != NULL );
+    DBG_ASSERT( str != NULL );
+    DBG_ASSERT( *str != '\0' );
+
+    //
+    // Scan it.
+    //
+
+    multisz = QueryStr();
+
+    while( *multisz != '\0' ) {
+
+        if( !::wcscmp( multisz, str ) ) {
+
+            return TRUE;
+
+        }
+
+        multisz += ::wcslen( multisz ) + 1;
+
+    }
+
+    return FALSE;
+
+}   // MULTISZ::FindString
+
+
+BOOL
+MULTISZ::FindStringNoCase( const WCHAR * str )
+{
+
+    WCHAR * multisz;
+
+    //
+    // Sanity check.
+    //
+
+    DBG_ASSERT( QueryStr() != NULL );
+    DBG_ASSERT( str != NULL );
+    DBG_ASSERT( *str != '\0' );
+
+    //
+    // Scan it.
+    //
+
+    multisz = QueryStr();
+
+    while( *multisz != '\0' ) {
+
+        if( !_wcsicmp( multisz, str ) ) {
+
+            return TRUE;
+
+        }
+
+        multisz += wcslen( multisz ) + 1;
+
+    }
+
+    return FALSE;
+
+}   // MULTISZ::FindStringNoCase
+
+
+VOID
+MULTISZ::AuxInit( const WCHAR * pInit )
+{
+    BOOL fRet;
+
+    if ( pInit )
+    {
+        DWORD cStrings;
+        int cbCopy = CalcLength( pInit, &cStrings ) * sizeof(WCHAR);
+        fRet = Resize( cbCopy );
+
+        if ( fRet ) {
+            CopyMemory( QueryPtr(), pInit, cbCopy );
+            m_cchLen = (cbCopy)/sizeof(WCHAR);
+            m_cStrings = cStrings;
+        } else {
+//            BUFFER::SetValid( FALSE);
+        }
+
+    } else {
+
+        Reset();
+
+    }
+
+} // MULTISZ::AuxInit()
+
+
+/*******************************************************************
+
+    NAME:       MULTISZ::AuxAppend
+
+    SYNOPSIS:   Appends the string onto the multisz.
+
+    ENTRY:      Object to append
+********************************************************************/
+
+BOOL MULTISZ::AuxAppend( const WCHAR * pStr, UINT cbStr, BOOL fAddSlop )
+{
+    DBG_ASSERT( pStr != NULL );
+
+    UINT cbThis = QueryCB();
+
+    DBG_ASSERT( cbThis >= 2 );
+
+    if( cbThis == 4 ) {
+
+        //
+        // It's empty, so start at the beginning.
+        //
+
+        cbThis = 0;
+
+    } else {
+
+        //
+        // It's not empty, so back up over the final terminating NULL.
+        //
+
+        cbThis -= sizeof(WCHAR);
+
+    }
+
+    //
+    //  Only resize when we have to.  When we do resize, we tack on
+    //  some extra space to avoid extra reallocations.
+    //
+    //  Note: QuerySize returns the requested size of the string buffer,
+    //        *not* the strlen of the buffer
+    //
+
+    //AcIncrement( CacMultiszAppend);
+    
+    // 
+    // Check for the arithmetic overflow
+    //
+    // ( 2 * sizeof( WCHAR ) ) is for the double terminator
+    //
+    ULONGLONG cb64Required = (ULONGLONG)cbThis + cbStr + 2 * sizeof(WCHAR);
+    if ( cb64Required > MAXULONG )
+    {
+        SetLastError( ERROR_ARITHMETIC_OVERFLOW );
+        return FALSE;
+    }
+    if ( QuerySize() < (DWORD) cb64Required )
+    {
+        ULONGLONG cb64AllocSize = cb64Required + (fAddSlop ? STR_SLOP : 0 );
+        // 
+        // Check for the arithmetic overflow
+        //
+        if ( cb64AllocSize > MAXULONG )
+        {
+            SetLastError( ERROR_ARITHMETIC_OVERFLOW );
+            return FALSE;
+        }
+        if ( !Resize( (DWORD) cb64AllocSize ) )
+            return FALSE;
+    }
+
+    // copy the exact string and tack on the double terminator
+    memcpy( (BYTE *) QueryPtr() + cbThis,
+            pStr,
+            cbStr);
+    *(WCHAR *)((BYTE *)QueryPtr() + cbThis + cbStr) = L'\0';
+    *(WCHAR *)((BYTE *)QueryPtr() + cbThis + cbStr + sizeof(WCHAR) ) = L'\0';
+
+    m_cchLen = CalcLength( (const WCHAR *)QueryPtr(), &m_cStrings );
+    return TRUE;
+
+} // MULTISZ::AuxAppend()
+
+
+#if 0
+
+BOOL
+MULTISZ::CopyToBuffer( WCHAR * lpszBuffer, LPDWORD lpcch) const
+/*++
+    Description:
+        Copies the string into the WCHAR buffer passed in if the buffer
+        is sufficient to hold the translated string.
+        If the buffer is small, the function returns small and sets *lpcch
+        to contain the required number of characters.
+
+    Arguments:
+        lpszBuffer      pointer to WCHAR buffer which on return contains
+                        the UNICODE version of string on success.
+        lpcch           pointer to DWORD containing the length of the buffer.
+                        If *lpcch == 0 then the function returns TRUE with
+                        the count of characters required stored in *lpcch.
+                        Also in this case lpszBuffer is not affected.
+    Returns:
+        TRUE on success.
+        FALSE on failure.  Use GetLastError() for further details.
+--*/
+{
+   BOOL fReturn = TRUE;
+
+    if ( lpcch == NULL) {
+        SetLastError( ERROR_INVALID_PARAMETER);
+        return ( FALSE);
+    }
+
+    if ( *lpcch == 0) {
+
+      //
+      //  Inquiring the size of buffer alone
+      //
+      *lpcch = QueryCCH() + 1;    // add one character for terminating null
+    } else {
+
+        //
+        // Copy after conversion from ANSI to Unicode
+        //
+        int  iRet;
+        iRet = MultiByteToWideChar( CP_ACP,
+                                    MB_PRECOMPOSED | MB_ERR_INVALID_CHARS,
+                                    QueryStrA(),  QueryCCH() + 1,
+                                    lpszBuffer, (int )*lpcch);
+
+        if ( iRet == 0 || iRet != (int ) *lpcch) {
+
+            //
+            // Error in conversion.
+            //
+            fReturn = FALSE;
+        }
+    }
+
+    return ( fReturn);
+} // MULTISZ::CopyToBuffer()
+#endif
+
+BOOL
+MULTISZ::CopyToBuffer( __out_ecount_opt(*lpcch) WCHAR * lpszBuffer, LPDWORD lpcch) const
+/*++
+    Description:
+        Copies the string into the WCHAR buffer passed in if the buffer
+          is sufficient to hold the translated string.
+        If the buffer is small, the function returns small and sets *lpcch
+          to contain the required number of characters.
+
+    Arguments:
+        lpszBuffer      pointer to WCHAR buffer which on return contains
+                        the string on success.
+        lpcch           pointer to DWORD containing the length of the buffer.
+                        If *lpcch == 0 then the function returns TRUE with
+                        the count of characters required stored in lpcch.
+                        Also in this case lpszBuffer is not affected.
+    Returns:
+        TRUE on success.
+        FALSE on failure.  Use GetLastError() for further details.
+--*/
+{
+   BOOL fReturn = TRUE;
+
+    if ( lpcch == NULL) {
+        SetLastError( ERROR_INVALID_PARAMETER);
+        return ( FALSE);
+    }
+
+    register DWORD cch = QueryCCH();
+
+    if ( *lpcch >= cch) {
+
+        DBG_ASSERT( lpszBuffer);
+        memcpy( lpszBuffer, QueryStr(), cch * sizeof(WCHAR));
+    } else {
+        DBG_ASSERT( *lpcch < cch);
+        SetLastError( ERROR_INSUFFICIENT_BUFFER);
+        fReturn = FALSE;
+    }
+
+    *lpcch = cch;
+
+    return ( fReturn);
+} // MULTISZ::CopyToBuffer()
+
+BOOL
+MULTISZ::Equals(
+    MULTISZ* pmszRhs
+)
+//
+// Compares this to pmszRhs, returns TRUE if equal
+//
+{
+    DBG_ASSERT( NULL != pmszRhs );
+
+    PCWSTR pszLhs = First( );
+    PCWSTR pszRhs = pmszRhs->First( );
+
+    if( m_cStrings != pmszRhs->m_cStrings )
+    {
+        return FALSE;
+    }
+
+    while( NULL != pszLhs )
+    {
+        DBG_ASSERT( NULL != pszRhs );
+
+        if( 0 != wcscmp( pszLhs, pszRhs ) )
+        {
+            return FALSE;
+        }
+
+        pszLhs = Next( pszLhs );
+        pszRhs = pmszRhs->Next( pszRhs );
+    }
+
+    return TRUE;
+}
+
+HRESULT
+SplitCommaDelimitedString(
+    PCWSTR                      pszList,
+    BOOL                        fTrimEntries,
+    BOOL                        fRemoveEmptyEntries,
+    MULTISZ *                   pmszList
+)
+/*++
+
+Routine Description:
+
+    Split comma delimited string into a multisz. Additional leading empty
+    entries after the first are discarded.
+
+Arguments:
+
+    pszList - List to split up
+    fTrimEntries - Whether each entry should be trimmed before added to multisz
+    fRemoveEmptyEntries - Whether empty entires should be discarded
+    pmszList - Filled with MULTISZ list
+
+Return Value:
+
+    HRESULT
+
+--*/
+{
+    HRESULT                 hr = S_OK;
+
+    if ( pszList == NULL ||
+         pmszList == NULL )
+    {
+        DBG_ASSERT( FALSE );
+        hr = HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
+        goto Finished;
+    }
+    
+    pmszList->Reset();
+
+    /*
+        pszCurrent: start of the current entry which may be the comma that
+                    precedes the next entry if the entry is empty
+
+        pszNext: the comma that precedes the next entry. If
+                 pszCurrent == pszNext, then the entry is empty
+
+        pszEnd: just past the end of the current entry
+    */
+    
+    for ( PCWSTR pszCurrent = pszList,
+                 pszNext = wcschr( pszCurrent, L',' )
+            ;
+            ;
+          pszCurrent = pszNext + 1,
+          pszNext = wcschr( pszCurrent, L',' ) )
+    {
+        PCWSTR pszEnd = NULL;
+
+        if ( pszNext != NULL )
+        {
+            pszEnd = pszNext;
+        }
+        else
+        {
+            pszEnd = pszCurrent + wcslen( pszCurrent );
+        }
+
+        if ( fTrimEntries )
+        {
+            while ( pszCurrent < pszEnd && ISWHITE( pszCurrent[ 0 ] ) )
+            {
+                pszCurrent++;
+            }
+
+            while ( pszEnd > pszCurrent && ISWHITE( pszEnd[ -1 ] ) )
+            {
+                pszEnd--;
+            }
+        }
+
+        if ( pszCurrent != pszEnd || !fRemoveEmptyEntries  )
+        {
+            if ( !pmszList->Append( pszCurrent, (DWORD) ( pszEnd - pszCurrent ) ) )
+            {
+                hr = HRESULT_FROM_WIN32( GetLastError() );
+                goto Finished;
+            }
+        }
+        
+        if ( pszNext == NULL )
+        {
+            break;
+        }
+    }
+
+Finished:
+
+    return hr;
+}
+
+#pragma warning(default:4267)
\ No newline at end of file
diff --git a/src/IISIntegration/src/AspNetCoreModuleV1/IISLib/multisz.h b/src/IISIntegration/src/AspNetCoreModuleV1/IISLib/multisz.h
new file mode 100644
index 0000000000000000000000000000000000000000..f65c151d4ff0820121e750d8942156bb665c9aa1
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV1/IISLib/multisz.h
@@ -0,0 +1,225 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#ifndef _MULTISZ_H_
+#define _MULTISZ_H_
+
+#include "stringu.h"
+#include "ntassert.h"
+
+/*++
+  class MULTISZ:
+
+  Intention:
+    A light-weight multi-string class supporting encapsulated string class.
+
+    This object is derived from BUFFER class.
+    It maintains following state:
+
+     m_fValid  - whether this object is valid -
+        used only by MULTISZ() init functions
+        * NYI: I need to kill this someday *
+     m_cchLen - string length cached when we update the string.
+     m_cStrings - number of strings.
+
+  Member Functions:
+    There are two categories of functions:
+      1) Safe Functions - which do integrity checking of state
+      2) UnSafe Functions - which do not do integrity checking, but
+                     enable writing to the data stream freely.
+             (someday this will be enabled as Safe versions without
+               problem for users)
+
+--*/
+class MULTISZ : public BUFFER
+{
+public:
+
+    MULTISZ()
+      : BUFFER   (),
+        m_cchLen ( 0),
+        m_cStrings(0)
+    { Reset(); }
+
+    // creates a stack version of the MULTISZ object - uses passed in stack buffer
+    //  MULTISZ does not free this pbInit on its own.
+    MULTISZ( __in_bcount(cbInit) WCHAR * pbInit, DWORD cbInit)
+        : BUFFER( (BYTE *) pbInit, cbInit),
+          m_cchLen (0),
+          m_cStrings(0)
+    {}
+
+    MULTISZ( const WCHAR * pchInit )
+        : BUFFER   (),
+          m_cchLen ( 0),
+          m_cStrings(0)
+    { AuxInit(pchInit); }
+
+    MULTISZ( const MULTISZ & str )
+        : BUFFER   (),
+          m_cchLen ( 0),
+          m_cStrings(0)
+    { AuxInit( str.QueryStr()); }
+
+//    BOOL IsValid(VOID) const { return ( BUFFER::IsValid()) ; }
+    //
+    //  Checks and returns TRUE if this string has no valid data else FALSE
+    //
+    BOOL IsEmpty( VOID) const      { return ( *QueryStr() == L'\0'); }
+
+    BOOL Append( const WCHAR  * pchInit ) {
+      return ((pchInit != NULL) ? (AuxAppend( pchInit,
+                                              (DWORD) (::wcslen(pchInit)) * sizeof(WCHAR)
+                                              )) :
+              TRUE);
+    }
+
+
+    BOOL Append( const WCHAR  * pchInit, DWORD cchLen ) {
+      return ((pchInit != NULL) ? (AuxAppend( pchInit,
+                                              cchLen * sizeof(WCHAR))) :
+              TRUE);
+    }
+
+    BOOL Append( STRU & str )
+      { return AuxAppend( str.QueryStr(),
+                          (str.QueryCCH()) * sizeof(WCHAR)); }
+
+    // Resets the internal string to be NULL string. Buffer remains cached.
+    VOID Reset( VOID)
+    { DBG_ASSERT( QueryPtr() != NULL);
+      QueryStr()[0] = L'\0';
+      QueryStr()[1] = L'\0';
+      m_cchLen = 2;
+      m_cStrings = 0;
+    }
+
+    BOOL Copy( const WCHAR  * pchInit, IN DWORD cbLen ) {
+      if ( QueryPtr() ) { Reset(); }
+      return ( (pchInit != NULL) ?
+               AuxAppend( pchInit, cbLen, FALSE ):
+               TRUE);
+    }
+
+    BOOL Copy( const MULTISZ   & str )
+    { return ( Copy(str.QueryStr(), str.QueryCB())); }
+
+    //
+    //  Returns the number of bytes in the string including the terminating
+    //  NULLs
+    //
+    UINT QueryCB( VOID ) const
+        { return ( m_cchLen * sizeof(WCHAR)); }
+
+    //
+    //  Returns # of characters in the string including the terminating NULLs
+    //
+    UINT QueryCCH( VOID ) const { return (m_cchLen); }
+
+    //
+    //  Returns # of strings in the multisz.
+    //
+
+    DWORD QueryStringCount( VOID ) const { return m_cStrings; }
+
+    //
+    // Makes a copy of the stored string in given buffer
+    //
+    BOOL CopyToBuffer( __out_ecount_opt(*lpcch) WCHAR * lpszBuffer,  LPDWORD lpcch) const;
+
+    //
+    //  Return the string buffer
+    //
+    WCHAR * QueryStrA( VOID ) const { return ( QueryStr()); }
+    WCHAR * QueryStr( VOID ) const { return ((WCHAR *) QueryPtr()); }
+
+    //
+    //  Makes a clone of the current string in the string pointer passed in.
+    //
+    BOOL
+      Clone( OUT MULTISZ * pstrClone) const
+        {
+          return ((pstrClone == NULL) ?
+                  (SetLastError(ERROR_INVALID_PARAMETER), FALSE) :
+                  (pstrClone->Copy( *this))
+                  );
+        } // MULTISZ::Clone()
+
+    //
+    //  Recalculates the length of *this because we've modified the buffers
+    //  directly
+    //
+
+    VOID RecalcLen( VOID )
+        { m_cchLen = MULTISZ::CalcLength( QueryStr(), &m_cStrings ); }
+
+    //
+    // Calculate total character length of a MULTI_SZ, including the
+    // terminating NULLs.
+    //
+
+    static DWORD CalcLength( const WCHAR * str,
+                                    LPDWORD pcStrings = NULL );
+
+    //
+    // Determine if the MULTISZ contains a specific string.
+    //
+
+    BOOL FindString( const WCHAR * str );
+
+    BOOL FindString( STRU & str )
+        { return FindString( str.QueryStr() ); }
+
+    //
+    // Determine if the MULTISZ contains a specific string - case-insensitive
+    //
+
+    BOOL FindStringNoCase( const WCHAR * str );
+
+    BOOL FindStringNoCase( STRU & str )
+        { return FindStringNoCase( str.QueryStr() ); }
+
+    //
+    // Used for scanning a multisz.
+    //
+
+    const WCHAR * First( VOID ) const
+        { return *QueryStr() == L'\0' ? NULL : QueryStr(); }
+
+    const WCHAR * Next( const WCHAR * Current ) const
+        { Current += ::wcslen( Current ) + 1;
+          return *Current == L'\0' ? NULL : Current; }
+
+    BOOL
+    Equals(
+        MULTISZ* pmszRhs
+    );
+
+private:
+
+    DWORD m_cchLen;
+    DWORD m_cStrings;
+    VOID AuxInit( const WCHAR * pInit );
+    BOOL AuxAppend( const WCHAR * pInit,
+                           UINT cbStr, BOOL fAddSlop = TRUE );
+
+};
+
+//
+//  Quick macro for declaring a MULTISZ that will use stack memory of <size>
+//  bytes.  If the buffer overflows then a heap buffer will be allocated
+//
+
+#define STACK_MULTISZ( name, size )     WCHAR __ach##name[size]; \
+                                    MULTISZ name( __ach##name, sizeof( __ach##name ))
+
+HRESULT
+SplitCommaDelimitedString(
+    PCWSTR                      pszList,
+    BOOL                        fTrimEntries,
+    BOOL                        fRemoveEmptyEntries,
+    MULTISZ *                   pmszList
+);
+
+#endif // !_MULTISZ_HXX_
+
diff --git a/src/IISIntegration/src/AspNetCoreModuleV1/IISLib/multisza.cpp b/src/IISIntegration/src/AspNetCoreModuleV1/IISLib/multisza.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..54717edf052858b70feb9f77e5413646e7541b12
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV1/IISLib/multisza.cpp
@@ -0,0 +1,408 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#pragma warning (disable : 4267)
+#include "precomp.h"
+#include "multisza.h"
+#include <tchar.h>
+
+//
+//  Private Definitions
+//
+
+#define MAXULONG 4294967295
+#define ISWHITE( ch )       ((ch) == L' ' || (ch) == L'\t' || (ch) == L'\r')
+
+//
+//  When appending data, this is the extra amount we request to avoid
+//  reallocations
+//
+#define STR_SLOP        128
+
+
+DWORD
+MULTISZA::CalcLength( const CHAR * str,
+                     LPDWORD pcStrings )
+{
+    DWORD count = 0;
+    DWORD total = 1;
+    DWORD len;
+
+    while( *str ) {
+        len = ::strlen( str ) + 1;
+        total += len;
+        str += len;
+        count++;
+    }
+
+    if( pcStrings != NULL ) {
+        *pcStrings = count;
+    }
+
+    return total;
+
+}   // MULTISZA::CalcLength
+
+
+BOOL
+MULTISZA::FindString( const CHAR * str )
+{
+
+    CHAR * multisz;
+
+    //
+    // Sanity check.
+    //
+
+    DBG_ASSERT( QueryStr() != NULL );
+    DBG_ASSERT( str != NULL );
+    DBG_ASSERT( *str != '\0' );
+
+    //
+    // Scan it.
+    //
+
+    multisz = QueryStr();
+
+    while( *multisz != '\0' ) {
+
+        if( !::strcmp( multisz, str ) ) {
+
+            return TRUE;
+
+        }
+
+        multisz += ::strlen( multisz ) + 1;
+
+    }
+
+    return FALSE;
+
+}   // MULTISZA::FindString
+
+
+BOOL
+MULTISZA::FindStringNoCase( const CHAR * str )
+{
+
+    CHAR * multisz;
+
+    //
+    // Sanity check.
+    //
+
+    DBG_ASSERT( QueryStr() != NULL );
+    DBG_ASSERT( str != NULL );
+    DBG_ASSERT( *str != '\0' );
+
+    //
+    // Scan it.
+    //
+
+    multisz = QueryStr();
+
+    while( *multisz != '\0' ) {
+
+        if( !_stricmp( multisz, str ) ) {
+
+            return TRUE;
+
+        }
+
+        multisz += strlen( multisz ) + 1;
+
+    }
+
+    return FALSE;
+
+}   // MULTISZA::FindStringNoCase
+
+
+VOID
+MULTISZA::AuxInit( const CHAR * pInit )
+{
+    BOOL fRet;
+
+    if ( pInit )
+    {
+        DWORD cStrings;
+        int cbCopy = CalcLength( pInit, &cStrings ) * sizeof(CHAR);
+        fRet = Resize( cbCopy );
+
+        if ( fRet ) {
+            CopyMemory( QueryPtr(), pInit, cbCopy );
+            m_cchLen = (cbCopy)/sizeof(CHAR);
+            m_cStrings = cStrings;
+        } else {
+//            BUFFER::SetValid( FALSE);
+        }
+
+    } else {
+
+        Reset();
+
+    }
+
+} // MULTISZA::AuxInit()
+
+
+/*******************************************************************
+
+    NAME:       MULTISZA::AuxAppend
+
+    SYNOPSIS:   Appends the string onto the MULTISZA.
+
+    ENTRY:      Object to append
+********************************************************************/
+
+BOOL MULTISZA::AuxAppend( const CHAR * pStr, UINT cbStr, BOOL fAddSlop )
+{
+    DBG_ASSERT( pStr != NULL );
+
+    UINT cbThis = QueryCB();
+
+    if( cbThis == 2 ) {
+
+        //
+        // It's empty, so start at the beginning.
+        //
+
+        cbThis = 0;
+
+    } else {
+
+        //
+        // It's not empty, so back up over the final terminating NULL.
+        //
+
+        cbThis -= sizeof(CHAR);
+
+    }
+
+    //
+    //  Only resize when we have to.  When we do resize, we tack on
+    //  some extra space to avoid extra reallocations.
+    //
+    //  Note: QuerySize returns the requested size of the string buffer,
+    //        *not* the strlen of the buffer
+    //
+
+    //AcIncrement( CacMultiszAppend);
+    
+    // 
+    // Check for the arithmetic overflow
+    //
+    // ( 2 * sizeof( CHAR ) ) is for the double terminator
+    //
+    ULONGLONG cb64Required = (ULONGLONG)cbThis + cbStr + 2 * sizeof(CHAR);
+    if ( cb64Required > MAXULONG )
+    {
+        SetLastError( ERROR_ARITHMETIC_OVERFLOW );
+        return FALSE;
+    }
+    if ( QuerySize() < (DWORD) cb64Required )
+    {
+        ULONGLONG cb64AllocSize = cb64Required + (fAddSlop ? STR_SLOP : 0 );
+        // 
+        // Check for the arithmetic overflow
+        //
+        if ( cb64AllocSize > MAXULONG )
+        {
+            SetLastError( ERROR_ARITHMETIC_OVERFLOW );
+            return FALSE;
+        }
+        if ( !Resize( (DWORD) cb64AllocSize ) )
+            return FALSE;
+    }
+
+    // copy the exact string and tack on the double terminator
+    memcpy( (BYTE *) QueryPtr() + cbThis,
+            pStr,
+            cbStr);
+    *(CHAR *)((BYTE *)QueryPtr() + cbThis + cbStr) = L'\0';
+    *(CHAR *)((BYTE *)QueryPtr() + cbThis + cbStr + sizeof(CHAR) ) = L'\0';
+
+    m_cchLen = CalcLength( (const CHAR *)QueryPtr(), &m_cStrings );
+    return TRUE;
+
+} // MULTISZA::AuxAppend()
+
+BOOL
+MULTISZA::CopyToBuffer( __out_ecount_opt(*lpcch) CHAR * lpszBuffer, LPDWORD lpcch) const
+/*++
+    Description:
+        Copies the string into the CHAR buffer passed in if the buffer
+          is sufficient to hold the translated string.
+        If the buffer is small, the function returns small and sets *lpcch
+          to contain the required number of characters.
+
+    Arguments:
+        lpszBuffer      pointer to CHAR buffer which on return contains
+                        the string on success.
+        lpcch           pointer to DWORD containing the length of the buffer.
+                        If *lpcch == 0 then the function returns TRUE with
+                        the count of characters required stored in lpcch.
+                        Also in this case lpszBuffer is not affected.
+    Returns:
+        TRUE on success.
+        FALSE on failure.  Use GetLastError() for further details.
+--*/
+{
+   BOOL fReturn = TRUE;
+
+    if ( lpcch == NULL) {
+        SetLastError( ERROR_INVALID_PARAMETER);
+        return ( FALSE);
+    }
+
+    register DWORD cch = QueryCCH();
+
+    if ( *lpcch >= cch) {
+
+        DBG_ASSERT( lpszBuffer);
+        memcpy( lpszBuffer, QueryStr(), cch * sizeof(CHAR));
+    } else {
+        DBG_ASSERT( *lpcch < cch);
+        SetLastError( ERROR_INSUFFICIENT_BUFFER);
+        fReturn = FALSE;
+    }
+
+    *lpcch = cch;
+
+    return ( fReturn);
+} // MULTISZA::CopyToBuffer()
+
+BOOL
+MULTISZA::Equals(
+    MULTISZA* pmszRhs
+)
+//
+// Compares this to pmszRhs, returns TRUE if equal
+//
+{
+    DBG_ASSERT( NULL != pmszRhs );
+
+    PCSTR pszLhs = First( );
+    PCSTR pszRhs = pmszRhs->First( );
+
+    if( m_cStrings != pmszRhs->m_cStrings )
+    {
+        return FALSE;
+    }
+
+    while( NULL != pszLhs )
+    {
+        DBG_ASSERT( NULL != pszRhs );
+
+        if( 0 != strcmp( pszLhs, pszRhs ) )
+        {
+            return FALSE;
+        }
+
+        pszLhs = Next( pszLhs );
+        pszRhs = pmszRhs->Next( pszRhs );
+    }
+
+    return TRUE;
+}
+
+HRESULT
+SplitCommaDelimitedString(
+    PCSTR                        pszList,
+    BOOL                         fTrimEntries,
+    BOOL                         fRemoveEmptyEntries,
+    MULTISZA *                   pmszList
+)
+/*++
+
+Routine Description:
+
+    Split comma delimited string into a MULTISZA. Additional leading empty
+    entries after the first are discarded.
+
+Arguments:
+
+    pszList - List to split up
+    fTrimEntries - Whether each entry should be trimmed before added to MULTISZA
+    fRemoveEmptyEntries - Whether empty entires should be discarded
+    pmszList - Filled with MULTISZA list
+
+Return Value:
+
+    HRESULT
+
+--*/
+{
+    HRESULT                 hr = S_OK;
+
+    if ( pszList == NULL ||
+         pmszList == NULL )
+    {
+        DBG_ASSERT( FALSE );
+        hr = HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
+        goto Finished;
+    }
+    
+    pmszList->Reset();
+
+    /*
+        pszCurrent: start of the current entry which may be the comma that
+                    precedes the next entry if the entry is empty
+
+        pszNext: the comma that precedes the next entry. If
+                 pszCurrent == pszNext, then the entry is empty
+
+        pszEnd: just past the end of the current entry
+    */
+    
+    for ( PCSTR pszCurrent = pszList,
+                 pszNext = strchr( pszCurrent, L',' )
+            ;
+            ;
+          pszCurrent = pszNext + 1,
+          pszNext = strchr( pszCurrent, L',' ) )
+    {
+        PCSTR pszEnd = NULL;
+
+        if ( pszNext != NULL )
+        {
+            pszEnd = pszNext;
+        }
+        else
+        {
+            pszEnd = pszCurrent + strlen( pszCurrent );
+        }
+
+        if ( fTrimEntries )
+        {
+            while ( pszCurrent < pszEnd && ISWHITE( pszCurrent[ 0 ] ) )
+            {
+                pszCurrent++;
+            }
+
+            while ( pszEnd > pszCurrent && ISWHITE( pszEnd[ -1 ] ) )
+            {
+                pszEnd--;
+            }
+        }
+
+        if ( pszCurrent != pszEnd || !fRemoveEmptyEntries  )
+        {
+            if ( !pmszList->Append( pszCurrent, (DWORD) ( pszEnd - pszCurrent ) ) )
+            {
+                hr = HRESULT_FROM_WIN32( GetLastError() );
+                goto Finished;
+            }
+        }
+        
+        if ( pszNext == NULL )
+        {
+            break;
+        }
+    }
+
+Finished:
+
+    return hr;
+}
+#pragma warning(default:4267)
\ No newline at end of file
diff --git a/src/IISIntegration/src/AspNetCoreModuleV1/IISLib/multisza.h b/src/IISIntegration/src/AspNetCoreModuleV1/IISLib/multisza.h
new file mode 100644
index 0000000000000000000000000000000000000000..d575ec94239bdb77b3ff7891f3c5d6452614278d
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV1/IISLib/multisza.h
@@ -0,0 +1,226 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#ifndef _MULTISZA_H_
+#define _MULTISZA_H_
+
+#include <Windows.h>
+#include "stringa.h"
+
+
+/*++
+  class MULTISZ:
+
+  Intention:
+    A light-weight multi-string class supporting encapsulated string class.
+
+    This object is derived from BUFFER class.
+    It maintains following state:
+
+     m_fValid  - whether this object is valid -
+        used only by MULTISZ() init functions
+        * NYI: I need to kill this someday *
+     m_cchLen - string length cached when we update the string.
+     m_cStrings - number of strings.
+
+  Member Functions:
+    There are two categories of functions:
+      1) Safe Functions - which do integrity checking of state
+      2) UnSafe Functions - which do not do integrity checking, but
+                     enable writing to the data stream freely.
+             (someday this will be enabled as Safe versions without
+               problem for users)
+
+--*/
+class MULTISZA : public BUFFER
+{
+public:
+
+    MULTISZA()
+      : BUFFER   (),
+        m_cchLen ( 0),
+        m_cStrings(0)
+    { Reset(); }
+
+    // creates a stack version of the MULTISZA object - uses passed in stack buffer
+    //  MULTISZA does not free this pbInit on its own.
+    MULTISZA( __in_bcount(cbInit) CHAR * pbInit, DWORD cbInit)
+        : BUFFER( (BYTE *) pbInit, cbInit),
+          m_cchLen (0),
+          m_cStrings(0)
+    {}
+
+    MULTISZA( const CHAR * pchInit )
+        : BUFFER   (),
+          m_cchLen ( 0),
+          m_cStrings(0)
+    { AuxInit(pchInit); }
+
+    MULTISZA( const MULTISZA & str )
+        : BUFFER   (),
+          m_cchLen ( 0),
+          m_cStrings(0)
+    { AuxInit( str.QueryStr()); }
+
+//    BOOL IsValid(VOID) const { return ( BUFFER::IsValid()) ; }
+    //
+    //  Checks and returns TRUE if this string has no valid data else FALSE
+    //
+    BOOL IsEmpty( VOID) const      { return ( *QueryStr() == L'\0'); }
+
+    BOOL Append( const CHAR  * pchInit ) {
+      return ((pchInit != NULL) ? (AuxAppend( pchInit,
+                                              (DWORD) (::strlen(pchInit)) * sizeof(CHAR)
+                                              )) :
+              TRUE);
+    }
+
+
+    BOOL Append( const CHAR  * pchInit, DWORD cchLen ) {
+      return ((pchInit != NULL) ? (AuxAppend( pchInit,
+                                              cchLen * sizeof(CHAR))) :
+              TRUE);
+    }
+
+    BOOL Append( STRA & str )
+      { return AuxAppend( str.QueryStr(),
+                          (str.QueryCCH()) * sizeof(CHAR)); }
+
+    // Resets the internal string to be NULL string. Buffer remains cached.
+    VOID Reset( VOID)
+    { DBG_ASSERT( QueryPtr() != NULL);
+      QueryStr()[0] = L'\0';
+      QueryStr()[1] = L'\0';
+      m_cchLen = 2;
+      m_cStrings = 0;
+    }
+
+    BOOL Copy( const CHAR  * pchInit, IN DWORD cbLen ) {
+      if ( QueryPtr() ) { Reset(); }
+      return ( (pchInit != NULL) ?
+               AuxAppend( pchInit, cbLen, FALSE ):
+               TRUE);
+    }
+
+    BOOL Copy( const MULTISZA   & str )
+    { return ( Copy(str.QueryStr(), str.QueryCB())); }
+
+    //
+    //  Returns the number of bytes in the string including the terminating
+    //  NULLs
+    //
+    UINT QueryCB( VOID ) const
+        { return ( m_cchLen * sizeof(CHAR)); }
+
+    //
+    //  Returns # of characters in the string including the terminating NULLs
+    //
+    UINT QueryCCH( VOID ) const { return (m_cchLen); }
+
+    //
+    //  Returns # of strings in the MULTISZA.
+    //
+
+    DWORD QueryStringCount( VOID ) const { return m_cStrings; }
+
+    //
+    // Makes a copy of the stored string in given buffer
+    //
+    BOOL CopyToBuffer( __out_ecount_opt(*lpcch) CHAR * lpszBuffer,  LPDWORD lpcch) const;
+
+    //
+    //  Return the string buffer
+    //
+    CHAR * QueryStrA( VOID ) const { return ( QueryStr()); }
+    CHAR * QueryStr( VOID ) const { return ((CHAR *) QueryPtr()); }
+
+    //
+    //  Makes a clone of the current string in the string pointer passed in.
+    //
+    BOOL
+      Clone( OUT MULTISZA * pstrClone) const
+        {
+          return ((pstrClone == NULL) ?
+                  (SetLastError(ERROR_INVALID_PARAMETER), FALSE) :
+                  (pstrClone->Copy( *this))
+                  );
+        } // MULTISZA::Clone()
+
+    //
+    //  Recalculates the length of *this because we've modified the buffers
+    //  directly
+    //
+
+    VOID RecalcLen( VOID )
+        { m_cchLen = MULTISZA::CalcLength( QueryStr(), &m_cStrings ); }
+
+    //
+    // Calculate total character length of a MULTI_SZ, including the
+    // terminating NULLs.
+    //
+
+    static DWORD CalcLength( const CHAR * str,
+                                    LPDWORD pcStrings = NULL );
+
+    //
+    // Determine if the MULTISZA contains a specific string.
+    //
+
+    BOOL FindString( const CHAR * str );
+
+    BOOL FindString( STRA & str )
+        { return FindString( str.QueryStr() ); }
+
+    //
+    // Determine if the MULTISZA contains a specific string - case-insensitive
+    //
+
+    BOOL FindStringNoCase( const CHAR * str );
+
+    BOOL FindStringNoCase( STRA & str )
+        { return FindStringNoCase( str.QueryStr() ); }
+
+    //
+    // Used for scanning a MULTISZA.
+    //
+
+    const CHAR * First( VOID ) const
+        { return *QueryStr() == L'\0' ? NULL : QueryStr(); }
+
+    const CHAR * Next( const CHAR * Current ) const
+        { Current += ::strlen( Current ) + 1;
+          return *Current == L'\0' ? NULL : Current; }
+
+    BOOL
+    Equals(
+        MULTISZA* pmszRhs
+    );
+
+private:
+
+    DWORD m_cchLen;
+    DWORD m_cStrings;
+    VOID AuxInit( const CHAR * pInit );
+    BOOL AuxAppend( const CHAR * pInit,
+                           UINT cbStr, BOOL fAddSlop = TRUE );
+
+};
+
+//
+//  Quick macro for declaring a MULTISZA that will use stack memory of <size>
+//  bytes.  If the buffer overflows then a heap buffer will be allocated
+//
+
+#define STACK_MULTISZA( name, size )     CHAR __ach##name[size]; \
+                                    MULTISZA name( __ach##name, sizeof( __ach##name ))
+
+HRESULT
+SplitCommaDelimitedString(
+    PCSTR                       pszList,
+    BOOL                        fTrimEntries,
+    BOOL                        fRemoveEmptyEntries,
+    MULTISZA *                  pmszList
+);
+
+#endif // !_MULTISZA_HXX_
+
diff --git a/src/IISIntegration/src/AspNetCoreModuleV1/IISLib/ntassert.h b/src/IISIntegration/src/AspNetCoreModuleV1/IISLib/ntassert.h
new file mode 100644
index 0000000000000000000000000000000000000000..6d2f3b9a300d07a8e91e6b947f7bd1e3af60338a
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV1/IISLib/ntassert.h
@@ -0,0 +1,32 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#pragma once
+
+#ifdef _ASSERTE
+    #undef _ASSERTE
+#endif
+
+#ifdef ASSERT
+    #undef ASSERT
+#endif
+
+#if defined( DBG ) && DBG
+    #define SX_ASSERT( _x )         ( (VOID)( ( ( _x ) ) ? TRUE : ( __annotation( L"Debug", L"AssertFail", L#_x  ), DbgRaiseAssertionFailure(), FALSE ) ) )
+    #define SX_ASSERTMSG( _m, _x )  ( (VOID)( ( ( _x ) ) ? TRUE : ( __annotation( L"Debug", L"AssertFail", L##_m ), DbgRaiseAssertionFailure(), FALSE ) ) )
+    #define SX_VERIFY( _x )         SX_ASSERT( _x )
+    #define _ASSERTE( _x )          SX_ASSERT( _x )
+    #define ASSERT( _x )            SX_ASSERT( _x )
+    #define assert( _x )            SX_ASSERT( _x )
+    #define DBG_ASSERT( _x )        SX_ASSERT( _x )
+    #define DBG_REQUIRE( _x )       SX_ASSERT( _x )
+#else
+    #define SX_ASSERT( _x )         ( (VOID)0 )
+    #define SX_ASSERTMSG( _m, _x )  ( (VOID)0 )
+    #define SX_VERIFY( _x )         ( (VOID)( ( _x ) ? TRUE : FALSE ) )
+    #define _ASSERTE( _x )          ( (VOID)0 )
+    #define assert( _x )            ( (VOID)0 )
+    #define DBG_ASSERT( _x )        ( (VOID)0 )
+    #define DBG_REQUIRE( _x )       ((VOID)(_x))
+#endif
+
diff --git a/src/IISIntegration/src/AspNetCoreModuleV1/IISLib/percpu.h b/src/IISIntegration/src/AspNetCoreModuleV1/IISLib/percpu.h
new file mode 100644
index 0000000000000000000000000000000000000000..5d3c56393520fbb0940e03dc7f84c05288d44520
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV1/IISLib/percpu.h
@@ -0,0 +1,305 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#pragma once
+
+template<typename T>
+class PER_CPU
+{
+public:
+
+    template<typename FunctionInitializer>
+    inline
+    static
+    HRESULT
+    Create(
+        FunctionInitializer         Initializer,
+        __deref_out PER_CPU<T> **   ppInstance
+    );
+
+    inline
+    T *
+    GetLocal(
+        VOID
+    );
+
+    template<typename FunctionForEach>
+    inline
+    VOID
+    ForEach(
+        FunctionForEach Function
+    );
+
+    inline
+    VOID
+    Dispose(
+        VOID
+    );
+
+private:
+
+    PER_CPU(
+        VOID
+    )
+    {
+        //
+        // Don't perform any operation during constructor.
+        // Constructor will never be called.
+        //
+    }
+
+    ~PER_CPU(
+        VOID
+    )
+    {
+        //
+        // Don't perform any operation during destructor.
+        // Constructor will never be called.
+        //
+    }
+
+    template<typename FunctionInitializer>
+    HRESULT
+    Initialize(
+        FunctionInitializer Initializer,
+        DWORD               NumberOfVariables,
+        DWORD               Alignment
+    );
+
+    T *
+    GetObject(
+        DWORD Index
+    );
+
+    static
+    HRESULT
+    GetProcessorInformation(
+        __out DWORD * pCacheLineSize,
+        __out DWORD * pNumberOfProcessors
+    );
+
+    //
+    // Pointer to the begining of the inlined array.
+    //
+    PVOID   m_pVariables;
+    SIZE_T  m_Alignment;
+    SIZE_T  m_VariablesCount;
+};
+
+template<typename T>
+template<typename FunctionInitializer>
+inline
+// static
+HRESULT
+PER_CPU<T>::Create(
+    FunctionInitializer        Initializer,
+    __deref_out PER_CPU<T> **  ppInstance
+)
+{
+    HRESULT         hr = S_OK;
+    DWORD           CacheLineSize = 0;
+    DWORD           ObjectCacheLineSize = 0;
+    DWORD           NumberOfProcessors = 0;
+    PER_CPU<T> *    pInstance = NULL;
+    
+    hr = GetProcessorInformation(&CacheLineSize,
+                                 &NumberOfProcessors);
+    if (FAILED(hr))
+    {
+        goto Finished;
+    }
+
+    if (sizeof(T) > CacheLineSize)
+    {
+        //
+        // Round to the next multiple of the cache line size.
+        //
+        ObjectCacheLineSize = (sizeof(T) + CacheLineSize-1) & (CacheLineSize-1);
+    }
+    else
+    {
+        ObjectCacheLineSize = CacheLineSize;
+    }
+
+    //
+    // Calculate the size of the PER_CPU<T> object, including the array.
+    // The first cache line is for the member variables and the array
+    // starts in the next cache line.
+    //
+    SIZE_T Size = CacheLineSize + NumberOfProcessors * ObjectCacheLineSize;
+
+    pInstance = (PER_CPU<T>*) _aligned_malloc(Size, CacheLineSize);
+    if (pInstance == NULL)
+    {
+        hr = E_OUTOFMEMORY;
+        goto Finished;
+    }
+    ZeroMemory(pInstance, Size);
+
+    //
+    // The array start in the 2nd cache line.
+    //
+    pInstance->m_pVariables = reinterpret_cast<PBYTE>(pInstance) + CacheLineSize;
+    
+    //
+    // Pass a disposer for disposing initialized items in case of failure.
+    //
+    hr = pInstance->Initialize(Initializer,
+                               NumberOfProcessors,
+                               ObjectCacheLineSize);
+    if (FAILED(hr))
+    {
+        goto Finished;
+    }
+
+    *ppInstance = pInstance;
+    pInstance = NULL;
+
+Finished:
+
+    if (pInstance != NULL)
+    {
+        //
+        // Free the instance without disposing it.
+        //
+        pInstance->Dispose();
+        pInstance = NULL;
+    }
+
+    return hr;
+}
+
+template<typename T>
+inline
+T *
+PER_CPU<T>::GetLocal(
+    VOID
+)
+{
+    // Use GetCurrentProcessorNumber (up to 64 logical processors) instead of
+    // GetCurrentProcessorNumberEx (more than 64 logical processors) because
+    // the number of processors are not densely packed per group.
+    // The idea of distributing variables per CPU is to have
+    // a scalability multiplier (could be NUMA node instead).
+    //
+    // Make sure the index don't go beyond the array size, if that happens,
+    // there won't be even distribution, but still better
+    // than one single variable.
+    //
+    return GetObject(GetCurrentProcessorNumber());
+}
+
+template<typename T>
+inline
+T *
+PER_CPU<T>::GetObject(
+    DWORD Index
+)
+{
+    return reinterpret_cast<T*>(static_cast<PBYTE>(m_pVariables) + Index * m_Alignment);
+}
+
+template<typename T>
+template<typename FunctionForEach>
+inline
+VOID
+PER_CPU<T>::ForEach(
+    FunctionForEach Function
+)
+{
+    for(DWORD Index = 0; Index < m_VariablesCount; ++Index)
+    {
+        T * pObject = GetObject(Index);
+        Function(pObject);
+    }
+}
+
+template<typename T>
+VOID
+PER_CPU<T>::Dispose(
+    VOID
+)
+{
+     _aligned_free(this);
+}
+
+template<typename T>
+template<typename FunctionInitializer>
+inline
+HRESULT
+PER_CPU<T>::Initialize(
+    FunctionInitializer Initializer,
+    DWORD               NumberOfVariables,
+    DWORD               Alignment
+)
+/*++
+
+Routine Description:
+
+    Initialize each object using the initializer function.
+    If initialization for any object fails, it dispose the
+    objects that were successfully initialized.
+
+Arguments:
+
+    Initializer - Function for initialize one object.
+                  Signature: HRESULT Func(T*)
+    Dispose - Function for disposing initialized objects in case of failure.
+              Signature: void Func(T*)
+    NumberOfVariables - The length of the array of variables.
+    Alignment - Alignment to use for avoiding false sharing.
+
+Return:
+
+    HRESULT - E_OUTOFMEMORY
+
+--*/
+{
+    HRESULT hr = S_OK;
+    DWORD Index = 0;
+
+    m_VariablesCount = NumberOfVariables;
+    m_Alignment = Alignment;
+
+    for (; Index < m_VariablesCount; ++Index)
+    {
+        T * pObject = GetObject(Index);
+        Initializer(pObject);
+    }
+
+    return hr;
+}
+
+template<typename T>
+// static
+HRESULT
+PER_CPU<T>::GetProcessorInformation(
+    __out DWORD * pCacheLineSize,
+    __out DWORD * pNumberOfProcessors
+)
+/*++
+
+Routine Description:
+
+    Gets the CPU cache-line size for the current system.
+    This information is used for avoiding CPU false sharing.
+
+Arguments:
+
+    pCacheLineSize - The processor cache-line size.
+    pNumberOfProcessors - Maximum number of processors per group.
+
+Return:
+
+    HRESULT - E_OUTOFMEMORY
+
+--*/
+{
+    SYSTEM_INFO     SystemInfo = { };
+
+    GetSystemInfo(&SystemInfo);
+    *pNumberOfProcessors = SystemInfo.dwNumberOfProcessors;
+    *pCacheLineSize = SYSTEM_CACHE_ALIGNMENT_SIZE;
+
+    return S_OK;
+}
\ No newline at end of file
diff --git a/src/IISIntegration/src/AspNetCoreModuleV1/IISLib/precomp.h b/src/IISIntegration/src/AspNetCoreModuleV1/IISLib/precomp.h
new file mode 100644
index 0000000000000000000000000000000000000000..9cccea4045571a33c659db79b7515c9bb18b55cf
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV1/IISLib/precomp.h
@@ -0,0 +1,22 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#include <windows.h>
+#include <ahadmin.h>
+#pragma warning( disable:4127 )
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <atlcomcli.h>
+#include <strsafe.h>
+#include <intsafe.h>
+
+#include "macros.h"
+#include "stringu.h"
+#include "stringa.h"
+#include "dbgutil.h"
+#include "ntassert.h"
+#include "ahutil.h"
+#include "acache.h"
+//#include "base64.hxx"
+
diff --git a/src/IISIntegration/src/AspNetCoreModuleV1/IISLib/prime.h b/src/IISIntegration/src/AspNetCoreModuleV1/IISLib/prime.h
new file mode 100644
index 0000000000000000000000000000000000000000..6a6a88ed780ee2f49fdad3799217db645bd8fe48
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV1/IISLib/prime.h
@@ -0,0 +1,85 @@
+// 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 <math.h>
+#include <stdlib.h>
+
+//
+// Pre-calculated prime numbers (up to 10,049,369).
+//
+extern __declspec(selectany) const DWORD g_Primes [] = {
+    3, 7, 11, 17, 23, 29, 37, 47, 59, 71, 89, 107, 131, 163, 197, 239, 293, 353, 431, 521, 631,
+    761, 919, 1103, 1327, 1597, 1931, 2333, 2801, 3371, 4049, 4861, 5839, 7013, 8419, 10103,
+    12143, 14591, 17519, 21023, 25229, 30293, 36353, 43627, 52361, 62851, 75431, 90523, 108631,
+    130363, 156437, 187751, 225307, 270371, 324449, 389357, 467237, 560689, 672827, 807403,
+    968897, 1162687, 1395263, 1674319, 2009191, 2411033, 2893249, 3471899, 4166287, 4999559,
+    5999471, 7199369, 7849369, 8649369, 9249369, 10049369
+};
+
+class PRIME
+{
+public:
+
+    static
+    DWORD
+    GetPrime(
+        DWORD dwMinimum
+    )
+    {
+        //
+        // Try to use the precalculated numbers.
+        //
+        for ( DWORD Index = 0; Index < _countof( g_Primes ); Index++ )
+        {
+            DWORD dwCandidate = g_Primes[Index];
+            if ( dwCandidate >= dwMinimum )
+            {
+                return dwCandidate;
+            }
+        }
+
+        //
+        // Do calculation.
+        //
+        for ( DWORD dwCandidate = dwMinimum | 1;
+             dwCandidate < MAXDWORD; 
+             dwCandidate += 2 )
+        {
+            if ( IsPrime( dwCandidate ) )
+            {
+                return dwCandidate;
+            }
+        }
+        return dwMinimum;
+    }
+
+private:
+
+    static
+    BOOL
+    IsPrime(
+        DWORD dwCandidate
+    )
+    {
+        if ((dwCandidate & 1) == 0)
+        {
+            return ( dwCandidate == 2 );
+        }
+
+        DWORD dwMax = static_cast<DWORD>(sqrt(static_cast<double>(dwCandidate)));
+
+        for ( DWORD Index = 3; Index <= dwMax; Index += 2 )
+        {
+            if ( (dwCandidate % Index) == 0 )
+            {
+                return FALSE;
+            }
+        }
+        return TRUE;
+    }
+
+    PRIME() {}
+    ~PRIME() {}
+};
\ No newline at end of file
diff --git a/src/IISIntegration/src/AspNetCoreModuleV1/IISLib/pudebug.h b/src/IISIntegration/src/AspNetCoreModuleV1/IISLib/pudebug.h
new file mode 100644
index 0000000000000000000000000000000000000000..7b0e35da0f1714f2c4fa62531b3018f3c93a3d99
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV1/IISLib/pudebug.h
@@ -0,0 +1,736 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+# ifndef _PUDEBUG_H_
+# define _PUDEBUG_H_
+
+#ifndef _NO_TRACING_
+# define _NO_TRACING_
+#endif // _NO_TRACING_
+
+/************************************************************
+ *     Include Headers
+ ************************************************************/
+
+# ifdef __cplusplus
+extern "C" {
+# endif // __cplusplus
+
+# include <windows.h>
+
+# ifndef dllexp
+# define dllexp   __declspec( dllexport)
+# endif // dllexp
+
+#include <specstrings.h>
+
+#ifndef IN_OUT
+#define IN_OUT __inout
+#endif
+
+/***********************************************************
+ *    Macros
+ ************************************************************/
+
+enum  PRINT_REASONS {
+    PrintNone     = 0x0,   // Nothing to be printed
+    PrintError    = 0x1,   // An error message
+    PrintWarning  = 0x2,   // A  warning message
+    PrintLog      = 0x3,   // Just logging. Indicates a trace of where ...
+    PrintMsg      = 0x4,   // Echo input message
+    PrintCritical = 0x5,   // Print and Exit
+    PrintAssertion= 0x6    // Printing for an assertion failure
+  };
+
+
+enum  DEBUG_OUTPUT_FLAGS {
+    DbgOutputNone     = 0x0,            // None
+    DbgOutputKdb      = 0x1,            // Output to Kernel Debugger
+    DbgOutputLogFile  = 0x2,            // Output to LogFile
+    DbgOutputTruncate = 0x4,            // Truncate Log File if necessary
+    DbgOutputStderr   = 0x8,            // Send output to std error
+    DbgOutputBackup   = 0x10,           // Make backup of debug file ?
+    DbgOutputMemory   = 0x20,           // Dump to memory buffer
+    DbgOutputAll      = 0xFFFFFFFF      // All the bits set.
+  };
+
+
+# define MAX_LABEL_LENGTH                 ( 100)
+
+
+// The following flags are used internally to track what level of tracing we
+// are currently using. Bitmapped for extensibility.
+#define DEBUG_FLAG_ODS          0x00000001
+//#define DEBUG_FLAG_INFO         0x00000002
+//#define DEBUG_FLAG_WARN         0x00000004
+//#define DEBUG_FLAG_ERROR        0x00000008
+// The following are used internally to determine whether to log or not based
+// on what the current state is
+//#define DEBUG_FLAGS_INFO        (DEBUG_FLAG_ODS | DEBUG_FLAG_INFO)
+//#define DEBUG_FLAGS_WARN        (DEBUG_FLAG_ODS | DEBUG_FLAG_INFO | DEBUG_FLAG_WARN)
+//#define DEBUG_FLAGS_ERROR       (DEBUG_FLAG_ODS | DEBUG_FLAG_INFO | DEBUG_FLAG_WARN | DEBUG_FLAG_ERROR)
+
+#define DEBUG_FLAGS_ANY         (DEBUG_FLAG_INFO | DEBUG_FLAG_WARN | DEBUG_FLAG_ERROR)
+
+//
+// user of DEBUG infrastructure may choose unique variable name for DEBUG_FLAGS
+// that's specially useful for cases where DEBUG infrastructure is used within
+// static library (static library may prefer to maintain it's own DebugFlags independent
+// on the main program it links to
+//
+#ifndef DEBUG_FLAGS_VAR
+#define DEBUG_FLAGS_VAR g_dwDebugFlags
+#endif
+
+extern
+#ifdef __cplusplus
+"C"
+# endif // _cplusplus
+ DWORD  DEBUG_FLAGS_VAR ;           // Debugging Flags
+
+# define DECLARE_DEBUG_VARIABLE()
+
+# define SET_DEBUG_FLAGS( dwFlags)         DEBUG_FLAGS_VAR = dwFlags
+# define GET_DEBUG_FLAGS()                 ( DEBUG_FLAGS_VAR )
+
+# define LOAD_DEBUG_FLAGS_FROM_REG(hkey, dwDefault)  \
+             DEBUG_FLAGS_VAR = PuLoadDebugFlagsFromReg((hkey), (dwDefault))
+
+# define LOAD_DEBUG_FLAGS_FROM_REG_STR(pszRegKey, dwDefault)  \
+             DEBUG_FLAGS_VAR = PuLoadDebugFlagsFromRegStr((pszRegKey), (dwDefault))
+
+# define SAVE_DEBUG_FLAGS_IN_REG(hkey, dwDbg)  \
+               PuSaveDebugFlagsInReg((hkey), (dwDbg))
+
+# define DEBUG_IF( arg, s)     if ( DEBUG_ ## arg & GET_DEBUG_FLAGS()) { \
+                                       s \
+                                } else {}
+
+# define IF_DEBUG( arg)        if ( DEBUG_## arg & GET_DEBUG_FLAGS())
+
+
+/*++
+  class DEBUG_PRINTS
+
+  This class is responsible for printing messages to log file / kernel debugger
+
+  Currently the class supports only member functions for <ANSI> char.
+   ( not unicode-strings).
+
+--*/
+
+
+typedef struct _DEBUG_PRINTS {
+
+    CHAR         m_rgchLabel[MAX_LABEL_LENGTH];
+    CHAR         m_rgchLogFilePath[MAX_PATH];
+    CHAR         m_rgchLogFileName[MAX_PATH];
+    HANDLE       m_LogFileHandle;
+    HANDLE       m_StdErrHandle;
+    BOOL         m_fInitialized;
+    BOOL         m_fBreakOnAssert;
+    DWORD        m_dwOutputFlags;
+    VOID        *m_pMemoryLog;
+} DEBUG_PRINTS, FAR * LPDEBUG_PRINTS;
+
+
+LPDEBUG_PRINTS
+PuCreateDebugPrintsObject(
+   IN const char * pszPrintLabel,
+   IN DWORD  dwOutputFlags);
+
+//
+// frees the debug prints object and closes any file if necessary.
+//  Returns NULL on success or returns pDebugPrints on failure.
+//
+LPDEBUG_PRINTS
+PuDeleteDebugPrintsObject(
+   IN_OUT LPDEBUG_PRINTS  pDebugPrints);
+
+
+VOID
+PuDbgPrint(
+   IN_OUT LPDEBUG_PRINTS   pDebugPrints,
+   IN const char *         pszFilePath,
+   IN int                  nLineNum,
+   IN const char *         pszFunctionName,
+   IN const char *         pszFormat,
+   ...);
+                           // arglist
+VOID
+PuDbgPrintW(
+   IN_OUT LPDEBUG_PRINTS   pDebugPrints,
+   IN const char *         pszFilePath,
+   IN int                  nLineNum,
+   IN const char *         pszFunctionName,
+   IN const WCHAR *        pszFormat,
+   ...);                               // arglist
+
+// PuDbgPrintError is similar to PuDbgPrint() but allows
+// one to print error code in friendly manner
+VOID
+PuDbgPrintError(
+   IN_OUT LPDEBUG_PRINTS   pDebugPrints,
+   IN const char *         pszFilePath,
+   IN int                  nLineNum,
+   IN const char *         pszFunctionName,
+   IN DWORD                dwError,
+   IN const char *         pszFormat,
+   ...);                               // arglist
+
+/*++
+  PuDbgDump() does not do any formatting of output.
+  It just dumps the given message onto the debug destinations.
+--*/
+VOID
+PuDbgDump(
+   IN_OUT LPDEBUG_PRINTS   pDebugPrints,
+   IN const char *         pszFilePath,
+   IN int                  nLineNum,
+   IN const char *         pszFunctionName,
+   IN const char *         pszDump
+   );
+
+//
+// PuDbgAssertFailed() *must* be __cdecl to properly capture the
+// thread context at the time of the failure.
+//
+
+INT
+__cdecl
+PuDbgAssertFailed(
+   IN_OUT LPDEBUG_PRINTS   pDebugPrints,
+   IN const char *         pszFilePath,
+   IN int                  nLineNum,
+   IN const char *         pszFunctionName,
+   IN const char *         pszExpression,
+   IN const char *         pszMessage);
+
+INT
+WINAPI
+PuDbgPrintAssertFailed(
+   IN_OUT LPDEBUG_PRINTS   pDebugPrints,
+   IN const char *         pszFilePath,
+   IN int                  nLineNum,
+   IN const char *         pszFunctionName,
+   IN const char *         pszExpression,
+   IN const char *         pszMessage);
+
+VOID
+PuDbgCaptureContext (
+    OUT PCONTEXT ContextRecord
+    );
+
+VOID
+PuDbgPrintCurrentTime(
+    IN_OUT LPDEBUG_PRINTS         pDebugPrints,
+    IN const char *               pszFilePath,
+    IN int                        nLineNum,
+    IN const char *               pszFunctionName
+    );
+
+VOID
+PuSetDbgOutputFlags(
+   IN_OUT LPDEBUG_PRINTS   pDebugPrints,
+   IN DWORD                dwFlags);
+
+DWORD
+PuGetDbgOutputFlags(
+   IN const LPDEBUG_PRINTS       pDebugPrints);
+
+
+//
+// Following functions return Win32 error codes.
+// NO_ERROR if success
+//
+
+DWORD
+PuOpenDbgPrintFile(
+   IN_OUT LPDEBUG_PRINTS   pDebugPrints,
+   IN const char *         pszFileName,
+   IN const char *         pszPathForFile);
+
+DWORD
+PuReOpenDbgPrintFile(
+   IN_OUT LPDEBUG_PRINTS   pDebugPrints);
+
+DWORD
+PuCloseDbgPrintFile(
+   IN_OUT LPDEBUG_PRINTS   pDebugPrints);
+
+DWORD
+PuOpenDbgMemoryLog(
+    IN_OUT LPDEBUG_PRINTS   pDebugPrints);
+
+DWORD
+PuCloseDbgMemoryLog(
+    IN_OUT LPDEBUG_PRINTS   pDebugPrints);
+
+DWORD
+PuLoadDebugFlagsFromReg(IN HKEY hkey, IN DWORD dwDefault);
+
+DWORD
+PuLoadDebugFlagsFromRegStr(IN LPCSTR pszRegKey, IN DWORD dwDefault);
+
+DWORD
+PuSaveDebugFlagsInReg(IN HKEY hkey, IN DWORD dwDbg);
+
+
+# define PuPrintToKdb( pszOutput)    \
+                    if ( pszOutput != NULL)   {   \
+                        OutputDebugString( pszOutput);  \
+                    } else {}
+
+
+
+# ifdef __cplusplus
+};
+# endif // __cplusplus
+
+// begin_user_unmodifiable
+
+
+
+/***********************************************************
+ *    Macros
+ ************************************************************/
+
+
+extern
+#ifdef __cplusplus
+"C"
+# endif // _cplusplus
+DEBUG_PRINTS  *  g_pDebug;        // define a global debug variable
+
+# if DBG
+
+// For the CHK build we want ODS enabled. For an explanation of these flags see
+// the comment just after the definition of DBG_CONTEXT
+# define DECLARE_DEBUG_PRINTS_OBJECT()                      \
+         DEBUG_PRINTS  *  g_pDebug = NULL;                  \
+         DWORD  DEBUG_FLAGS_VAR = DEBUG_FLAG_ERROR;
+
+#else // !DBG
+
+# define DECLARE_DEBUG_PRINTS_OBJECT()          \
+         DEBUG_PRINTS  *  g_pDebug = NULL;      \
+         DWORD  DEBUG_FLAGS_VAR = 0;
+
+#endif // !DBG
+
+
+//
+// Call the following macro as part of your initialization for program
+//  planning to use the debugging class.
+//
+/** DEBUGDEBUG
+# define CREATE_DEBUG_PRINT_OBJECT( pszLabel)  \
+        g_pDebug = PuCreateDebugPrintsObject( pszLabel, DEFAULT_OUTPUT_FLAGS);\
+         if  ( g_pDebug == NULL) {   \
+               OutputDebugStringA( "Unable to Create Debug Print Object \n"); \
+         }
+*/
+
+//
+// Call the following macro once as part of the termination of program
+//    which uses the debugging class.
+//
+# define DELETE_DEBUG_PRINT_OBJECT( )  \
+        g_pDebug = PuDeleteDebugPrintsObject( g_pDebug);
+
+
+# define VALID_DEBUG_PRINT_OBJECT()     \
+        ( ( g_pDebug != NULL) && g_pDebug->m_fInitialized)
+
+
+//
+//  Use the DBG_CONTEXT without any surrounding braces.
+//  This is used to pass the values for global DebugPrintObject
+//     and File/Line information
+//
+//# define DBG_CONTEXT        g_pDebug, __FILE__, __LINE__, __FUNCTION__
+
+// The 3 main tracing macros, each one corresponds to a different level of
+// tracing
+
+// The 3 main tracing macros, each one corresponds to a different level of
+// tracing
+//# define DBGINFO(args)      {if (DEBUG_FLAGS_VAR & DEBUG_FLAGS_INFO) { PuDbgPrint args; }}
+//# define DBGWARN(args)      {if (DEBUG_FLAGS_VAR & DEBUG_FLAGS_WARN) { PuDbgPrint args; }}
+//# define DBGERROR(args)     {if (DEBUG_FLAGS_VAR & DEBUG_FLAGS_ERROR) { PuDbgPrint args; }}
+
+# define DBGINFOW(args)     {if (DEBUG_FLAGS_VAR & DEBUG_FLAGS_INFO) { PuDbgPrintW args; }}
+# define DBGWARNW(args)     {if (DEBUG_FLAGS_VAR & DEBUG_FLAGS_WARN) { PuDbgPrintW args; }}
+# define DBGERRORW(args)    {if (DEBUG_FLAGS_VAR & DEBUG_FLAGS_ERROR) { PuDbgPrintW args; }}
+
+
+//
+//  DBGPRINTF() is printing function ( much like printf) but always called
+//    with the DBG_CONTEXT as follows
+//   DBGPRINTF( ( DBG_CONTEXT, format-string, arguments for format list));
+//
+# define DBGPRINTF DBGINFO
+
+//
+//  DPERROR() is printing function ( much like printf) but always called
+//    with the DBG_CONTEXT as follows
+//   DPERROR( ( DBG_CONTEXT, error, format-string,
+//                      arguments for format list));
+//
+# define DPERROR( args)       {if (DEBUG_FLAGS_VAR & DEBUG_FLAGS_ERROR) { PuDbgPrintError args; }}
+
+# if DBG
+
+# define DBG_CODE(s)          s          /* echoes code in debugging mode */
+
+// The same 3 main tracing macros however in this case the macros are only compiled
+// into the CHK build. This is necessary because some tracing info used functions or
+// variables which are not compiled into the FRE build.
+# define CHKINFO(args)      { PuDbgPrint args; }
+# define CHKWARN(args)      { PuDbgPrint args; }
+# define CHKERROR(args)     { PuDbgPrint args; }
+
+# define CHKINFOW(args)     { PuDbgPrintW args; }
+# define CHKWARNW(args)     { PuDbgPrintW args; }
+# define CHKERRORW(args)    { PuDbgPrintW args; }
+
+
+#ifndef DBG_ASSERT
+# ifdef _PREFAST_
+#  define DBG_ASSERT(exp)                         ((void)0) /* Do Nothing */
+#  define DBG_ASSERT_MSG(exp, pszMsg)             ((void)0) /* Do Nothing */
+#  define DBG_REQUIRE( exp)                       ((void) (exp))
+# else  // !_PREFAST_
+#  define DBG_ASSERT( exp )                  \
+    ( (VOID)( ( exp ) || ( DebugBreak(),    \
+                           PuDbgPrintAssertFailed( DBG_CONTEXT, #exp, "" ) ) ) )
+
+#  define DBG_ASSERT_MSG( exp, pszMsg)       \
+    ( (VOID)( ( exp ) || ( DebugBreak(),    \
+                           PuDbgPrintAssertFailed( DBG_CONTEXT, #exp, pszMsg ) ) ) )
+
+#  define DBG_REQUIRE( exp )                 \
+    DBG_ASSERT( exp )
+# endif // !_PREFAST_
+#endif
+
+
+# define DBG_LOG()      PuDbgPrint( DBG_CONTEXT, "\n" )
+
+# define DBG_OPEN_LOG_FILE( pszFile, pszPath )  \
+                        PuOpenDbgPrintFile( g_pDebug, (pszFile), (pszPath) )
+
+# define DBG_CLOSE_LOG_FILE( )  \
+                        PuCloseDbgPrintFile( g_pDebug )
+
+# define DBG_OPEN_MEMORY_LOG( ) \
+                        PuOpenDbgMemoryLog( g_pDebug )
+
+
+# define DBGDUMP( args )            PuDbgDump  args
+
+# define DBGPRINT_CURRENT_TIME()    PuDbgPrintCurrentTime( DBG_CONTEXT )
+
+# else // !DBG
+
+# define DBG_CODE(s)        ((void)0) /* Do Nothing */
+
+# define CHKINFO(args)      ((void)0) /* Do Nothing */
+# define CHKWARN(args)      ((void)0) /* Do Nothing */
+# define CHKERROR(args)     ((void)0) /* Do Nothing */
+
+# define CHKINFOW(args)     ((void)0) /* Do Nothing */
+# define CHKWARNW(args)     ((void)0) /* Do Nothing */
+# define CHKERRORW(args)    ((void)0) /* Do Nothing */
+
+#ifndef DBG_ASSERT
+# define DBG_ASSERT(exp)                         ((void)0) /* Do Nothing */
+
+# define DBG_ASSERT_MSG(exp, pszMsg)             ((void)0) /* Do Nothing */
+
+# define DBG_REQUIRE( exp)                       ((void) (exp))
+#endif // !DBG_ASSERT
+
+# define DBGDUMP( args)                          ((void)0) /* Do nothing */
+
+# define DBG_LOG()                               ((void)0) /* Do Nothing */
+
+# define DBG_OPEN_LOG_FILE( pszFile, pszPath)    ((void)0) /* Do Nothing */
+
+# define DBG_OPEN_MEMORY_LOG()                   ((void)0) /* Do Nothing */
+
+# define DBG_CLOSE_LOG_FILE()                    ((void)0) /* Do Nothing */
+
+# define DBGPRINT_CURRENT_TIME()                 ((void)0) /* Do Nothing */
+
+# endif // !DBG
+
+
+// end_user_unmodifiable
+
+// begin_user_unmodifiable
+
+
+#ifdef ASSERT
+# undef ASSERT
+#endif
+
+
+# define ASSERT( exp)           DBG_ASSERT( exp)
+
+
+// end_user_unmodifiable
+
+// begin_user_modifiable
+
+//
+//  Debugging constants consist of two pieces.
+//  All constants in the range 0x0 to 0x8000 are reserved
+//  User extensions may include additional constants (bit flags)
+//
+
+# define DEBUG_API_ENTRY                  0x00000001L
+# define DEBUG_API_EXIT                   0x00000002L
+# define DEBUG_INIT_CLEAN                 0x00000004L
+# define DEBUG_ERROR                      0x00000008L
+
+                   // End of Reserved Range
+# define DEBUG_RESERVED                   0x00000FFFL
+
+// end_user_modifiable
+
+
+
+/***********************************************************
+ *    Platform Type related variables and macros
+ ************************************************************/
+
+//
+// Enum for product types
+//
+
+typedef enum _PLATFORM_TYPE {
+
+    PtInvalid = 0,                 // Invalid
+    PtNtWorkstation = 1,           // NT Workstation
+    PtNtServer = 2,                // NT Server
+
+} PLATFORM_TYPE;
+
+//
+// IISGetPlatformType is the function used to the platform type
+//
+
+extern
+#ifdef __cplusplus
+"C"
+# endif // _cplusplus
+PLATFORM_TYPE
+IISGetPlatformType(
+        VOID
+        );
+
+//
+// External Macros
+//
+
+#define InetIsNtServer( _pt )           ((_pt) == PtNtServer)
+#define InetIsNtWksta( _pt )            ((_pt) == PtNtWorkstation)
+#define InetIsValidPT(_pt)              ((_pt) != PtInvalid)
+
+extern
+#ifdef __cplusplus
+"C"
+# endif // _cplusplus
+PLATFORM_TYPE    g_PlatformType;
+
+
+// Use the DECLARE_PLATFORM_TYPE macro to declare the platform type
+#define DECLARE_PLATFORM_TYPE()  \
+   PLATFORM_TYPE    g_PlatformType = PtInvalid;
+
+// Use the INITIALIZE_PLATFORM_TYPE to init the platform type
+// This should typically go inside the DLLInit or equivalent place.
+#define INITIALIZE_PLATFORM_TYPE()  \
+   g_PlatformType = IISGetPlatformType();
+
+//
+// Additional Macros to use the Platform Type
+//
+
+#define TsIsNtServer( )         InetIsNtServer(g_PlatformType)
+#define TsIsNtWksta( )          InetIsNtWksta(g_PlatformType)
+#define IISIsValidPlatform()    InetIsValidPT(g_PlatformType)
+#define IISPlatformType()       (g_PlatformType)
+
+
+/***********************************************************
+ *    Some utility functions for Critical Sections
+ ************************************************************/
+
+//
+// IISSetCriticalSectionSpinCount() provides a thunk for the
+// original NT4.0sp3 API SetCriticalSectionSpinCount() for CS with Spin counts
+// Users of this function should definitely dynlink with kernel32.dll,
+// Otherwise errors will surface to a large extent
+//
+extern
+# ifdef __cplusplus
+"C"
+# endif // _cplusplus
+DWORD
+IISSetCriticalSectionSpinCount(
+    LPCRITICAL_SECTION lpCriticalSection,
+    DWORD dwSpinCount
+);
+
+
+//
+// Macro for the calls to SetCriticalSectionSpinCount()
+//
+# define SET_CRITICAL_SECTION_SPIN_COUNT( lpCS, dwSpins) \
+  IISSetCriticalSectionSpinCount( (lpCS), (dwSpins))
+
+//
+// IIS_DEFAULT_CS_SPIN_COUNT is the default value of spins used by
+//  Critical sections defined within IIS.
+// NYI: We should have to switch the individual values based on experiments!
+// Current value is an arbitrary choice
+//
+# define IIS_DEFAULT_CS_SPIN_COUNT   (1000)
+
+//
+// Initializes a critical section and sets its spin count
+// to IIS_DEFAULT_CS_SPIN_COUNT.  Equivalent to
+// InitializeCriticalSectionAndSpinCount(lpCS, IIS_DEFAULT_CS_SPIN_COUNT),
+// but provides a safe thunking layer for older systems that don't provide
+// this API.
+//
+extern
+# ifdef __cplusplus
+"C"
+# endif // _cplusplus
+BOOL
+IISInitializeCriticalSection(
+    LPCRITICAL_SECTION lpCriticalSection
+);
+
+//
+// Macro for the calls to InitializeCriticalSection()
+//
+# define INITIALIZE_CRITICAL_SECTION(lpCS) IISInitializeCriticalSection(lpCS)
+
+# endif  /* _DEBUG_HXX_ */
+
+//
+// The following macros allow the automatic naming of certain Win32 objects.
+// See IIS\SVCS\IISRTL\WIN32OBJ.C for details on the naming convention.
+//
+// Set IIS_NAMED_WIN32_OBJECTS to a non-zero value to enable named events,
+// semaphores, and mutexes.
+//
+
+#if DBG
+#define IIS_NAMED_WIN32_OBJECTS 1
+#else
+#define IIS_NAMED_WIN32_OBJECTS 0
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+HANDLE
+PuDbgCreateEvent(
+    __in LPSTR FileName,
+    IN ULONG LineNumber,
+    __in LPSTR MemberName,
+    IN PVOID Address,
+    IN BOOL ManualReset,
+    IN BOOL InitialState
+    );
+
+HANDLE
+PuDbgCreateSemaphore(
+    __in LPSTR FileName,
+    IN ULONG LineNumber,
+    __in LPSTR MemberName,
+    IN PVOID Address,
+    IN LONG InitialCount,
+    IN LONG MaximumCount
+    );
+
+HANDLE
+PuDbgCreateMutex(
+    __in LPSTR FileName,
+    IN ULONG LineNumber,
+    __in LPSTR MemberName,
+    IN PVOID Address,
+    IN BOOL InitialOwner
+    );
+
+#ifdef __cplusplus
+}   // extern "C"
+#endif
+
+#if IIS_NAMED_WIN32_OBJECTS
+
+#define IIS_CREATE_EVENT( membername, address, manual, state )              \
+    PuDbgCreateEvent(                                                       \
+        (LPSTR)__FILE__,                                                    \
+        (ULONG)__LINE__,                                                    \
+        (membername),                                                       \
+        (PVOID)(address),                                                   \
+        (manual),                                                           \
+        (state)                                                             \
+        )
+
+#define IIS_CREATE_SEMAPHORE( membername, address, initial, maximum )       \
+    PuDbgCreateSemaphore(                                                   \
+        (LPSTR)__FILE__,                                                    \
+        (ULONG)__LINE__,                                                    \
+        (membername),                                                       \
+        (PVOID)(address),                                                   \
+        (initial),                                                          \
+        (maximum)                                                           \
+        )
+
+#define IIS_CREATE_MUTEX( membername, address, initial )                     \
+    PuDbgCreateMutex(                                                       \
+        (LPSTR)__FILE__,                                                    \
+        (ULONG)__LINE__,                                                    \
+        (membername),                                                       \
+        (PVOID)(address),                                                   \
+        (initial)                                                           \
+        )
+
+#else   // !IIS_NAMED_WIN32_OBJECTS
+
+#define IIS_CREATE_EVENT( membername, address, manual, state )              \
+    CreateEventA(                                                           \
+        NULL,                                                               \
+        (manual),                                                           \
+        (state),                                                            \
+        NULL                                                                \
+        )
+
+#define IIS_CREATE_SEMAPHORE( membername, address, initial, maximum )       \
+    CreateSemaphoreA(                                                       \
+        NULL,                                                               \
+        (initial),                                                          \
+        (maximum),                                                          \
+        NULL                                                                \
+        )
+
+#define IIS_CREATE_MUTEX( membername, address, initial )                     \
+    CreateMutexA(                                                           \
+        NULL,                                                               \
+        (initial),                                                          \
+        NULL                                                                \
+        )
+
+#endif  // IIS_NAMED_WIN32_OBJECTS
+
+
+/************************ End of File ***********************/
+
diff --git a/src/IISIntegration/src/AspNetCoreModuleV1/IISLib/reftrace.c b/src/IISIntegration/src/AspNetCoreModuleV1/IISLib/reftrace.c
new file mode 100644
index 0000000000000000000000000000000000000000..c1b2e13a6edeec9a65bcad2d7e61cbbd2bdb1ff7
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV1/IISLib/reftrace.c
@@ -0,0 +1,229 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#include <windows.h>
+#include "dbgutil.h"
+#include "pudebug.h"
+#include "reftrace.h"
+
+
+PTRACE_LOG
+CreateRefTraceLog(
+    IN LONG LogSize,
+    IN LONG ExtraBytesInHeader
+    )
+/*++
+
+Routine Description:
+
+    Creates a new (empty) ref count trace log buffer.
+
+Arguments:
+
+    LogSize - The number of entries in the log.
+
+    ExtraBytesInHeader - The number of extra bytes to include in the
+        log header. This is useful for adding application-specific
+        data to the log.
+
+Return Value:
+
+    PTRACE_LOG - Pointer to the newly created log if successful,
+        NULL otherwise.
+
+--*/
+{
+
+    return CreateTraceLog(
+               LogSize,
+               ExtraBytesInHeader,
+               sizeof(REF_TRACE_LOG_ENTRY)
+               );
+
+}   // CreateRefTraceLog
+
+
+VOID
+DestroyRefTraceLog(
+    IN PTRACE_LOG Log
+    )
+/*++
+
+Routine Description:
+
+    Destroys a ref count trace log buffer created with CreateRefTraceLog().
+
+Arguments:
+
+    Log - The ref count trace log buffer to destroy.
+
+Return Value:
+
+    None.
+
+--*/
+{
+
+    DestroyTraceLog( Log );
+
+}   // DestroyRefTraceLog
+
+
+//
+// N.B. For RtlCaptureBacktrace() to work properly, the calling function
+// *must* be __cdecl, and must have a "normal" stack frame. So, we decorate
+// WriteRefTraceLog[Ex]() with the __cdecl modifier and disable the frame
+// pointer omission (FPO) optimization.
+//
+
+//#pragma optimize( "y", off )    // disable frame pointer omission (FPO)
+#pragma optimize( "", off )    // disable frame pointer omission (FPO)
+
+LONG
+__cdecl
+WriteRefTraceLog(
+    IN PTRACE_LOG Log,
+    IN LONG NewRefCount,
+    IN CONST VOID * Context
+    )
+/*++
+
+Routine Description:
+
+    Writes a new entry to the specified ref count trace log. The entry
+    written contains the updated reference count and a stack backtrace
+    leading up to the current caller.
+
+Arguments:
+
+    Log - The log to write to.
+
+    NewRefCount - The updated reference count.
+
+    Context - An uninterpreted context to associate with the log entry.
+
+Return Value:
+
+    Index of entry in log.
+
+--*/
+{
+
+    return WriteRefTraceLogEx(
+        Log,
+        NewRefCount,
+        Context,
+        REF_TRACE_EMPTY_CONTEXT, // suppress use of optional extra contexts
+        REF_TRACE_EMPTY_CONTEXT,
+        REF_TRACE_EMPTY_CONTEXT
+        );
+
+}   // WriteRefTraceLog
+
+
+
+
+LONG
+__cdecl
+WriteRefTraceLogEx(
+    IN PTRACE_LOG Log,
+    IN LONG NewRefCount,
+    IN CONST VOID * Context,
+    IN CONST VOID * Context1, // optional extra context
+    IN CONST VOID * Context2, // optional extra context
+    IN CONST VOID * Context3  // optional extra context
+    )
+/*++
+
+Routine Description:
+
+    Writes a new "extended" entry to the specified ref count trace log.
+    The entry written contains the updated reference count, stack backtrace
+    leading up to the current caller and extra context information.
+
+Arguments:
+
+    Log - The log to write to.
+
+    NewRefCount - The updated reference count.
+
+    Context  - An uninterpreted context to associate with the log entry.
+    Context1 - An uninterpreted context to associate with the log entry.
+    Context2 - An uninterpreted context to associate with the log entry.
+    Context3 - An uninterpreted context to associate with the log entry.
+
+    NOTE Context1/2/3 are "optional" in that the caller may suppress
+    debug display of these values by passing REF_TRACE_EMPTY_CONTEXT
+    for each of them.
+
+Return Value:
+
+    Index of entry in log.
+
+--*/
+{
+
+    REF_TRACE_LOG_ENTRY entry;
+    ULONG hash;
+    DWORD cStackFramesSkipped;
+
+    //
+    // Initialize the entry.
+    //
+
+    RtlZeroMemory(
+        &entry,
+        sizeof(entry)
+        );
+
+    //
+    //  Set log entry members.
+    //
+
+    entry.NewRefCount = NewRefCount;
+    entry.Context = Context;
+    entry.Thread = GetCurrentThreadId();
+    entry.Context1 = Context1;
+    entry.Context2 = Context2;
+    entry.Context3 = Context3;
+
+    //
+    // Capture the stack backtrace. Normally, we skip two stack frames:
+    // one for this routine, and one for RtlCaptureBacktrace() itself.
+    // For non-Ex callers who come in via WriteRefTraceLog,
+    // we skip three stack frames.
+    //
+
+    if (    entry.Context1 == REF_TRACE_EMPTY_CONTEXT
+         && entry.Context2 == REF_TRACE_EMPTY_CONTEXT
+         && entry.Context3 == REF_TRACE_EMPTY_CONTEXT
+         ) {
+
+         cStackFramesSkipped = 2;
+
+    } else {
+
+         cStackFramesSkipped = 1;
+
+    }
+
+    RtlCaptureStackBackTrace(
+        cStackFramesSkipped,
+        REF_TRACE_LOG_STACK_DEPTH,
+        entry.Stack,
+        &hash
+        );
+
+    //
+    // Write it to the log.
+    //
+
+    return WriteTraceLog(
+        Log,
+        &entry
+        );
+
+}   // WriteRefTraceLogEx
+
+#pragma optimize( "", on )      // restore frame pointer omission (FPO)
+
diff --git a/src/IISIntegration/src/AspNetCoreModuleV1/IISLib/reftrace.h b/src/IISIntegration/src/AspNetCoreModuleV1/IISLib/reftrace.h
new file mode 100644
index 0000000000000000000000000000000000000000..e90ca0444a719b2830eb3b2a1be825e3e63072f1
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV1/IISLib/reftrace.h
@@ -0,0 +1,87 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#ifndef _REFTRACE_H_
+#define _REFTRACE_H_
+
+
+#if defined(__cplusplus)
+extern "C" {
+#endif  // __cplusplus
+
+#include <Windows.h>
+#include "tracelog.h"
+
+//
+// This is the number of stack backtrace values captured in each
+// trace log entry. This value is chosen to make the log entry
+// exactly twelve dwords long, making it a bit easier to interpret
+// from within the debugger without the debugger extension.
+//
+
+#define REF_TRACE_LOG_STACK_DEPTH   9
+
+// No-op value for the Context1,2,3 parameters of WriteRefTraceLogEx
+//#define REF_TRACE_EMPTY_CONTEXT ((PVOID) -1)
+#define REF_TRACE_EMPTY_CONTEXT NULL
+
+
+//
+// This defines the entry written to the trace log.
+//
+
+typedef struct _REF_TRACE_LOG_ENTRY {
+
+    LONG NewRefCount;
+    CONST VOID * Context;
+    CONST VOID * Context1;
+    CONST VOID * Context2;
+    CONST VOID * Context3;
+    DWORD Thread;
+    PVOID Stack[REF_TRACE_LOG_STACK_DEPTH];
+
+} REF_TRACE_LOG_ENTRY, *PREF_TRACE_LOG_ENTRY;
+
+
+//
+// Manipulators.
+//
+
+PTRACE_LOG
+CreateRefTraceLog(
+    IN LONG LogSize,
+    IN LONG ExtraBytesInHeader
+    );
+
+VOID
+DestroyRefTraceLog(
+    IN PTRACE_LOG Log
+    );
+
+LONG
+__cdecl
+WriteRefTraceLog(
+    IN PTRACE_LOG Log,
+    IN LONG NewRefCount,
+    IN CONST VOID * Context
+    );
+
+LONG
+__cdecl
+WriteRefTraceLogEx(
+    IN PTRACE_LOG Log,
+    IN LONG NewRefCount,
+    IN CONST VOID * Context,
+    IN CONST VOID * Context1,
+    IN CONST VOID * Context2,
+    IN CONST VOID * Context3
+    );
+
+
+#if defined(__cplusplus)
+}   // extern "C"
+#endif  // __cplusplus
+
+
+#endif  // _REFTRACE_H_
+
diff --git a/src/IISIntegration/src/AspNetCoreModuleV1/IISLib/rwlock.h b/src/IISIntegration/src/AspNetCoreModuleV1/IISLib/rwlock.h
new file mode 100644
index 0000000000000000000000000000000000000000..dc7ccf834bef129bb7eae8c8a4f36eaf34dd5ccd
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV1/IISLib/rwlock.h
@@ -0,0 +1,193 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#pragma once
+
+#if (_WIN32_WINNT < 0x600)
+
+//
+// XP implementation.
+//
+class CWSDRWLock
+{
+public:
+
+    CWSDRWLock()
+        : m_bInited(FALSE)
+    {
+    }
+
+    ~CWSDRWLock()
+    {
+        if (m_bInited)
+        {
+            DeleteCriticalSection(&m_rwLock.critsec);
+            CloseHandle(m_rwLock.ReadersDoneEvent);
+        }
+    }
+
+    BOOL QueryInited() const
+    {
+        return m_bInited;
+    }
+
+    HRESULT Init()
+    {
+        HRESULT hr = S_OK;
+    
+        if (FALSE == m_bInited)
+        {
+            m_rwLock.fWriterWaiting = FALSE;
+            m_rwLock.LockCount = 0;
+            if ( !InitializeCriticalSectionAndSpinCount( &m_rwLock.critsec, 0 )) 
+            {
+                DWORD dwError  = GetLastError();
+                hr = HRESULT_FROM_WIN32(dwError);
+                return hr;
+            }
+
+            m_rwLock.ReadersDoneEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+            if( NULL == m_rwLock.ReadersDoneEvent ) 
+            {
+                DWORD dwError  = GetLastError();
+                hr = HRESULT_FROM_WIN32(dwError);
+                DeleteCriticalSection(&m_rwLock.critsec);
+                return hr;
+            }
+            m_bInited = TRUE;
+        }
+
+        return hr;
+    }
+    
+    void SharedAcquire()
+    {
+        EnterCriticalSection(&m_rwLock.critsec);
+        InterlockedIncrement(&m_rwLock.LockCount);
+        LeaveCriticalSection(&m_rwLock.critsec);
+    }
+    
+    void SharedRelease()
+    {
+        ReleaseRWLock();
+    }
+    
+    void ExclusiveAcquire()
+    {
+        EnterCriticalSection( &m_rwLock.critsec );
+    
+        m_rwLock.fWriterWaiting = TRUE;
+    
+        // check if there are any readers active
+        if ( InterlockedExchangeAdd( &m_rwLock.LockCount, 0 ) > 0 ) 
+        {
+            //
+            // Wait for all the readers to get done..
+            //
+            WaitForSingleObject( m_rwLock.ReadersDoneEvent, INFINITE );
+        }
+        m_rwLock.LockCount = -1;
+    }
+    
+    void ExclusiveRelease()
+    {
+        ReleaseRWLock();
+    }
+
+private:
+
+    BOOL m_bInited;
+
+    typedef struct _RW_LOCK 
+    {
+        BOOL  fWriterWaiting; // Is a writer waiting on the lock?
+        LONG LockCount;
+        CRITICAL_SECTION critsec;
+        HANDLE ReadersDoneEvent;
+    } RW_LOCK, *PRW_LOCK;
+
+    RW_LOCK m_rwLock;
+
+private:
+
+    void ReleaseRWLock()
+    {
+        LONG Count = InterlockedDecrement( &m_rwLock.LockCount );
+    
+        if ( 0 <= Count )
+        {
+            // releasing a read lock
+            if (( m_rwLock.fWriterWaiting ) && ( 0 == Count ))
+            {
+                SetEvent( m_rwLock.ReadersDoneEvent );
+            }
+        }
+        else 
+        {
+            // Releasing a write lock
+            m_rwLock.LockCount = 0;
+            m_rwLock.fWriterWaiting = FALSE;
+            LeaveCriticalSection(&m_rwLock.critsec);
+        }
+    }
+};
+
+#else
+
+//
+// Implementation for Windows Vista or greater.
+//
+class CWSDRWLock
+{
+public:
+
+    CWSDRWLock()
+    {
+        InitializeSRWLock(&m_rwLock);
+    }
+
+    BOOL QueryInited()
+    {
+        return TRUE;
+    }
+
+
+    HRESULT Init()
+    {
+        //
+        // Method defined to keep compatibility with CWSDRWLock class for XP.
+        //
+        return S_OK;
+    }
+
+    void SharedAcquire()
+    {
+        AcquireSRWLockShared(&m_rwLock);
+    }
+    
+    void SharedRelease()
+    {
+        ReleaseSRWLockShared(&m_rwLock);
+    }
+
+    void ExclusiveAcquire()
+    {
+        AcquireSRWLockExclusive(&m_rwLock);
+    }
+    
+    void ExclusiveRelease()
+    {
+        ReleaseSRWLockExclusive(&m_rwLock);
+    }
+
+private:
+
+    SRWLOCK m_rwLock;
+};
+
+#endif
+
+//
+// Rename the lock class to a more clear name.
+//
+typedef CWSDRWLock READ_WRITE_LOCK;
\ No newline at end of file
diff --git a/src/IISIntegration/src/AspNetCoreModuleV1/IISLib/stringa.cpp b/src/IISIntegration/src/AspNetCoreModuleV1/IISLib/stringa.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..29da773bcab8b01aafc175387da78bd70995125a
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV1/IISLib/stringa.cpp
@@ -0,0 +1,1767 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#include "precomp.h"
+
+STRA::STRA(
+    VOID
+) : m_cchLen( 0 )
+{
+    *( QueryStr() ) = '\0';
+}
+
+STRA::STRA(
+    __inout_ecount(cchInit) CHAR* pbInit,
+    __in DWORD cchInit
+) : m_Buff( pbInit, cchInit * sizeof( CHAR ) ),
+    m_cchLen(0)
+/*++
+    Description:
+
+        Used by STACK_STRA. Initially populates underlying buffer with pbInit.
+
+        pbInit is not freed.
+
+    Arguments:
+
+        pbInit - initial memory to use
+        cchInit - count, in characters, of pbInit
+
+    Returns:
+
+        None.
+
+--*/
+{
+    _ASSERTE( NULL != pbInit );
+    _ASSERTE( cchInit > 0 );
+    _ASSERTE( pbInit[0] == '\0' );
+}
+
+BOOL
+STRA::IsEmpty(
+    VOID
+) const
+{
+    return ( m_cchLen == 0 );
+}
+
+BOOL
+STRA::Equals(
+    __in PCSTR  pszRhs,
+    __in BOOL   fIgnoreCase /*= FALSE*/
+) const
+{
+    _ASSERTE( NULL != pszRhs );
+
+    if( fIgnoreCase )
+    {
+        return ( 0 == _stricmp( QueryStr(), pszRhs ) );
+    }
+
+    return ( 0 == strcmp( QueryStr(), pszRhs ) );
+}
+
+BOOL
+STRA::Equals(
+    __in const STRA *   pstrRhs,
+    __in BOOL           fIgnoreCase /*= FALSE*/
+) const
+{
+    _ASSERTE( NULL != pstrRhs );
+    return Equals( pstrRhs->QueryStr(), fIgnoreCase );
+}
+
+BOOL
+STRA::Equals(
+    __in const STRA &  strRhs,
+    __in BOOL           fIgnoreCase /*= FALSE*/
+) const
+{
+    return Equals( strRhs.QueryStr(), fIgnoreCase );
+}
+
+DWORD
+STRA::QueryCB(
+    VOID
+) const
+//
+// Returns the number of bytes in the string excluding the terminating NULL
+//
+{
+    return m_cchLen * sizeof( CHAR );
+}
+
+DWORD
+STRA::QueryCCH(
+    VOID
+) const
+//
+//  Returns the number of characters in the string excluding the terminating NULL
+//
+{
+    return m_cchLen;
+}
+
+DWORD
+STRA::QuerySizeCCH(
+    VOID
+) const
+//
+// Returns size of the underlying storage buffer, in characters
+//
+{
+    return m_Buff.QuerySize() / sizeof( CHAR );
+}
+
+DWORD
+STRA::QuerySize(
+    VOID
+) const
+//
+//  Returns the size of the storage buffer in bytes
+//
+{
+    return m_Buff.QuerySize();
+}
+
+__nullterminated
+__bcount(this->m_cchLen)
+CHAR *
+STRA::QueryStr(
+    VOID
+) const
+//
+//  Return the string buffer
+//
+{
+    return m_Buff.QueryPtr();
+}
+
+VOID
+STRA::Reset(
+    VOID
+)
+//
+// Resets the internal string to be NULL string. Buffer remains cached.
+//
+{
+    _ASSERTE( QueryStr() != NULL );
+    *(QueryStr()) = '\0';
+    m_cchLen = 0;
+}
+
+HRESULT
+STRA::Resize(
+    __in DWORD cchSize
+)
+{
+    if( !m_Buff.Resize( cchSize * sizeof( CHAR ) ) )
+    {
+        return E_OUTOFMEMORY;
+    }
+
+    return S_OK;
+}
+
+HRESULT
+STRA::SyncWithBuffer(
+    VOID
+)
+//
+// Recalculate the length of the string, etc. because we've modified
+// the buffer directly.
+//
+{
+    HRESULT hr;
+    size_t size;
+    hr = StringCchLengthA( QueryStr(),
+                           QuerySizeCCH(),
+                           &size );
+    if ( SUCCEEDED( hr ) )
+    {
+        m_cchLen = static_cast<DWORD>(size);
+    }
+    return hr;
+}
+
+HRESULT
+STRA::Copy(
+    __in PCSTR   pszCopy
+)
+{
+    HRESULT     hr;
+    size_t      cbLen;
+    hr = StringCbLengthA( pszCopy,
+                          STRSAFE_MAX_CCH,
+                          &cbLen );
+    if ( FAILED( hr ) )
+    {
+        return hr;
+    }
+    return Copy( pszCopy, cbLen );
+}
+
+
+HRESULT
+STRA::Copy(
+    __in_ecount(cchLen)
+    PCSTR           pszCopy,
+    __in SIZE_T     cbLen
+)
+//
+// Copy the contents of another string to this one
+//
+{
+    _ASSERTE( cbLen <= MAXDWORD );
+
+    return AuxAppend(
+        pszCopy,
+        static_cast<DWORD>(cbLen),
+        0
+    );
+}
+
+HRESULT
+STRA::Copy(
+    __in const STRA * pstrRhs
+)
+{
+    _ASSERTE( pstrRhs != NULL );
+    return Copy( pstrRhs->QueryStr(), pstrRhs->QueryCCH() );
+}
+
+HRESULT
+STRA::Copy(
+    __in const STRA & strRhs
+)
+{
+    return Copy( strRhs.QueryStr(), strRhs.QueryCCH() );
+}
+
+HRESULT
+STRA::CopyW(
+    __in PCWSTR  pszCopyW
+)
+{
+    HRESULT     hr;
+    size_t      cchLen;
+    hr = StringCchLengthW( pszCopyW,
+                           STRSAFE_MAX_CCH,
+                           &cchLen );
+    if ( FAILED( hr ) )
+    {
+        return hr;
+    }
+    return CopyW( pszCopyW, cchLen );
+}
+
+HRESULT
+STRA::CopyWTruncate(
+    __in PCWSTR pszCopyWTruncate
+)
+{
+    HRESULT     hr;
+    size_t      cchLen;
+    hr = StringCchLengthW( pszCopyWTruncate,
+                           STRSAFE_MAX_CCH,
+                           &cchLen );
+    if ( FAILED( hr ) )
+    {
+        return hr;
+    }
+    return CopyWTruncate( pszCopyWTruncate, cchLen );
+}
+
+HRESULT
+STRA::CopyWTruncate(
+    __in_ecount(cchLen)
+    PCWSTR          pszCopyWTruncate,
+    __in SIZE_T     cchLen
+)
+//
+// The "Truncate" methods do not do proper conversion. They do a (CHAR) caste
+//
+{
+    _ASSERTE( cchLen <= MAXDWORD );
+
+    return AuxAppendWTruncate(
+        pszCopyWTruncate,
+        static_cast<DWORD>(cchLen),
+        0
+    );
+}
+
+HRESULT
+STRA::Append(
+    __in PCSTR pszAppend
+)
+{
+    HRESULT     hr;
+    size_t      cbLen;
+    hr = StringCbLengthA( pszAppend,
+                          STRSAFE_MAX_CCH,
+                          &cbLen );
+    if ( FAILED( hr ) )
+    {
+        return hr;
+    }
+    return Append( pszAppend, cbLen );
+}
+
+HRESULT
+STRA::Append(
+    __in_ecount(cchLen)
+    PCSTR       pszAppend,
+    __in SIZE_T cbLen
+)
+{
+    _ASSERTE( cbLen <= MAXDWORD );
+    if ( cbLen == 0 )
+    {
+        return S_OK;
+    }
+    return AuxAppend(
+        pszAppend,
+        static_cast<DWORD>(cbLen),
+        QueryCB()
+    );
+}
+
+HRESULT
+STRA::Append(
+    __in const STRA * pstrRhs
+)
+{
+    _ASSERTE( pstrRhs != NULL );
+    return Append( pstrRhs->QueryStr(), pstrRhs->QueryCCH() );
+}
+
+HRESULT
+STRA::Append(
+    __in const STRA & strRhs
+)
+{
+    return Append( strRhs.QueryStr(), strRhs.QueryCCH() );
+}
+
+HRESULT
+STRA::AppendWTruncate(
+    __in PCWSTR pszAppendWTruncate
+)
+{
+    HRESULT     hr;
+    size_t      cchLen;
+    hr = StringCchLengthW( pszAppendWTruncate,
+                           STRSAFE_MAX_CCH,
+                           &cchLen );
+    if ( FAILED( hr ) )
+    {
+        return hr;
+    }
+    return AppendWTruncate( pszAppendWTruncate, cchLen );
+}
+
+HRESULT
+STRA::AppendWTruncate(
+    __in_ecount(cchLen)
+    PCWSTR          pszAppendWTruncate,
+    __in SIZE_T     cchLen
+)
+//
+// The "Truncate" methods do not do proper conversion. They do a (CHAR) caste
+//
+{
+    _ASSERTE( cchLen <= MAXDWORD );
+    if ( cchLen == 0 )
+    {
+        return S_OK;
+    }
+    return AuxAppendWTruncate(
+        pszAppendWTruncate,
+        static_cast<DWORD>(cchLen),
+        QueryCB()
+    );
+}
+
+HRESULT
+STRA::CopyToBuffer(
+    __out_bcount(*pcb) CHAR*    pszBuffer,
+    __inout DWORD *             pcb
+) const
+//
+// Makes a copy of the stored string into the given buffer
+//
+{
+    _ASSERTE( NULL != pszBuffer );
+    _ASSERTE( NULL != pcb );
+
+    HRESULT hr          = S_OK;
+    DWORD   cbNeeded    = QueryCB() + sizeof( CHAR );
+
+    if( *pcb < cbNeeded )
+    {
+        hr = HRESULT_FROM_WIN32( ERROR_INSUFFICIENT_BUFFER );
+        goto Finished;
+    }
+
+    memcpy( pszBuffer, QueryStr(), cbNeeded );
+
+Finished:
+
+    *pcb = cbNeeded;
+
+    return hr;
+}
+
+HRESULT
+STRA::SetLen(
+    __in DWORD cchLen
+)
+/*++
+ *
+Routine Description:
+
+    Set the length of the string and null terminate, if there
+    is sufficient buffer already allocated. Will not reallocate.
+
+Arguments:
+
+    cchLen - The number of characters in the new string.
+
+Return Value:
+
+    HRESULT
+
+--*/
+{
+    if( cchLen >= QuerySizeCCH() )
+    {
+        return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
+    }
+
+    *( QueryStr() + cchLen ) = '\0';
+    m_cchLen = cchLen;
+
+    return S_OK;
+}
+
+
+HRESULT
+STRA::SafeSnprintf(
+    __in __format_string
+    PCSTR       pszFormatString,
+    ...
+)
+/*++
+
+Routine Description:
+
+    Writes to a STRA, growing it as needed. It arbitrarily caps growth at 64k chars.
+
+Arguments:
+
+    pszFormatString    - printf format
+    ...                - printf args
+
+Return Value:
+
+    HRESULT
+
+--*/
+{
+    HRESULT     hr          = S_OK;
+    va_list     argsList;
+    va_start(   argsList, pszFormatString );
+
+    hr = SafeVsnprintf(pszFormatString, argsList);
+
+    va_end( argsList );
+    return hr;
+}
+
+HRESULT
+STRA::SafeVsnprintf(
+    __in __format_string
+    PCSTR       pszFormatString,
+    va_list     argsList
+)
+/*++
+
+Routine Description:
+
+    Writes to a STRA, growing it as needed. It arbitrarily caps growth at 64k chars.
+
+Arguments:
+
+    pszFormatString    - printf format
+    argsList           - printf va_list
+
+Return Value:
+
+    HRESULT
+
+--*/
+{
+    HRESULT     hr          = S_OK;
+    int         cchOutput;
+    int         cchNeeded;
+
+    //
+    // Format the incoming message using vsnprintf()
+    // so that the overflows are captured
+    //
+    cchOutput = _vsnprintf_s(
+            QueryStr(),
+            QuerySizeCCH(),
+            QuerySizeCCH() - 1,
+            pszFormatString,
+            argsList
+        );
+
+    if( cchOutput == -1 )
+    {
+        //
+        // Couldn't fit this in the original STRU size.
+        //
+        cchNeeded = _vscprintf( pszFormatString, argsList );
+        if( cchNeeded > 64 * 1024 )
+        {
+            //
+            // If we're trying to produce a string > 64k chars, then
+            // there is probably a problem
+            //
+            hr = HRESULT_FROM_WIN32( ERROR_INVALID_DATA );
+            goto Finished;
+        }
+
+        //
+        // _vscprintf doesn't include terminating null character
+        //
+        cchNeeded++;
+
+        hr = Resize( cchNeeded );
+        if( FAILED( hr ) )
+        {
+            goto Finished;
+        }
+
+        cchOutput = _vsnprintf_s(
+            QueryStr(),
+            QuerySizeCCH(),
+            QuerySizeCCH() - 1,
+            pszFormatString,
+            argsList
+        );
+        if( -1 == cchOutput )
+        {
+            //
+            // This should never happen, cause we should already have correctly sized memory
+            //
+            _ASSERTE( FALSE );
+
+            hr = HRESULT_FROM_WIN32( ERROR_INVALID_DATA );
+            goto Finished;
+        }
+    }
+
+    //
+    // always null terminate at the last WCHAR
+    //
+    QueryStr()[ QuerySizeCCH() - 1 ] = L'\0';
+
+    //
+    // we directly touched the buffer - therefore:
+    //
+    hr = SyncWithBuffer();
+    if( FAILED( hr ) )
+    {
+        goto Finished;
+    }
+
+Finished:
+
+    if( FAILED( hr ) )
+    {
+        Reset();
+    }
+
+    return hr;
+}
+
+bool
+FShouldEscapeUtf8(
+    BYTE ch
+    )
+{
+    if ( ( ch >= 128 ) )
+    {
+        return true;
+    }
+
+    return false;
+}
+
+bool
+FShouldEscapeUrl(
+    BYTE ch
+    )
+{
+    if ( ( ch >= 128   ||
+           ch <= 32    ||
+           ch == '<'   ||
+           ch == '>'   ||
+           ch == '%'   ||
+           ch == '?'   ||
+           ch == '#' ) &&
+         !( ch == '\n' || ch == '\r' ) )
+    {
+        return true;
+    }
+
+    return false;
+}
+
+HRESULT
+STRA::Escape(
+    VOID
+)
+/*++
+
+Routine Description:
+
+    Escapes a STRA
+
+Arguments:
+
+    None
+
+Return Value:
+
+    None
+
+--*/
+{
+    return EscapeInternal( FShouldEscapeUrl );
+}
+
+HRESULT
+STRA::EscapeUtf8(
+    VOID
+)
+/*++
+
+Routine Description:
+
+    Escapes the high-bit chars in a STRA.  LWS, CR, LF & controls are untouched.
+
+Arguments:
+
+    None
+
+Return Value:
+
+    None
+
+--*/
+{
+    return EscapeInternal( FShouldEscapeUtf8 );
+}
+
+
+HRESULT
+STRA::EscapeInternal(
+    PFN_F_SHOULD_ESCAPE pfnFShouldEscape
+)
+/*++
+
+Routine Description:
+
+    Escapes a STRA according to the predicate function passed in
+
+Arguments:
+
+    None
+
+Return Value:
+
+    None
+
+--*/
+{
+    LPCSTR  pch     = QueryStr();
+    __analysis_assume( pch != NULL );
+    int     i      = 0;
+    BYTE    ch;
+    HRESULT hr      = S_OK;
+    BOOL    fRet    = FALSE;
+    SIZE_T  NewSize = 0;
+
+    // Set to true if any % escaping occurs
+    BOOL fEscapingDone = FALSE;
+
+    //
+    // If there are any characters that need to be escaped we copy the entire string
+    // character by character into straTemp, escaping as we go, then at the end
+    // copy all of straTemp over. Don't modify InlineBuffer directly.
+    //
+    CHAR InlineBuffer[512];
+    InlineBuffer[0] = '\0';
+    STRA straTemp(InlineBuffer, sizeof(InlineBuffer)/sizeof(*InlineBuffer));
+
+    _ASSERTE( pch );
+
+    while (ch = pch[i])
+    {
+        //
+        //  Escape characters that are in the non-printable range
+        //  but ignore CR and LF
+        //
+
+        if ( pfnFShouldEscape( ch ) )
+        {
+            if (FALSE == fEscapingDone)
+            {
+                // first character in the string that needed escaping
+                fEscapingDone = TRUE;
+
+                // guess that the size needs to be larger than
+                // what we used to have times two
+                NewSize = QueryCCH() * 2;
+                if ( NewSize > MAXDWORD )
+                {
+                    hr = HRESULT_FROM_WIN32( ERROR_ARITHMETIC_OVERFLOW );
+                    return hr;
+                }
+
+                hr = straTemp.Resize( static_cast<DWORD>(NewSize) );
+
+                if (FAILED(hr))
+                {
+                    return hr;
+                }
+
+                // Copy all of the previous buffer into buffTemp, only if it is not the first character:
+
+                if ( i > 0)
+                {
+                    hr = straTemp.Copy(QueryStr(),
+                                       i * sizeof(CHAR));
+                    if (FAILED(hr))
+                    {
+                        return hr;
+                    }
+                }
+            }
+
+            // resize the temporary (if needed) with the slop of the entire buffer length
+            // this fixes constant reallocation if the entire string needs to be escaped
+            NewSize = QueryCCH() + 2 * sizeof(CHAR) + 1 * sizeof(CHAR);
+            if ( NewSize > MAXDWORD )
+            {
+                hr = HRESULT_FROM_WIN32( ERROR_ARITHMETIC_OVERFLOW );
+                return hr;
+            }
+
+            fRet = straTemp.m_Buff.Resize( NewSize );
+            if ( !fRet )
+            {
+                hr = HRESULT_FROM_WIN32(GetLastError());
+                return hr;
+            }
+
+            //
+            //  Create the string to append for the current character
+            //
+
+            CHAR chHex[3];
+            chHex[0] = '%';
+
+            //
+            //  Convert the low then the high character to hex
+            //
+
+            UINT nLowDigit = (UINT)(ch % 16);
+            chHex[2] = TODIGIT( nLowDigit );
+
+            ch /= 16;
+
+            UINT nHighDigit = (UINT)(ch % 16);
+
+            chHex[1] = TODIGIT( nHighDigit );
+
+            //
+            // Actually append the converted character to the end of the temporary
+            //
+            hr = straTemp.Append(chHex, 3);
+            if (FAILED(hr))
+            {
+                return hr;
+            }
+        }
+        else
+        {
+            // if no escaping done, no need to copy
+            if (fEscapingDone)
+            {
+                // if ANY escaping done, copy current character into new buffer
+                straTemp.Append(&pch[i], 1);
+            }
+        }
+
+        // inspect the next character in the string
+        i++;
+    }
+
+    if (fEscapingDone)
+    {
+        // the escaped string is now in straTemp
+        hr = Copy(straTemp);
+    }
+
+    return hr;
+
+} // EscapeInternal()
+
+VOID
+STRA::Unescape(
+    VOID
+)
+/*++
+
+Routine Description:
+
+    Unescapes a STRA
+
+    Supported escape sequences are:
+      %uxxxx unescapes Unicode character xxxx into system codepage
+      %xx    unescapes character xx
+      %      without following hex digits is ignored
+
+Arguments:
+
+    None
+
+Return Value:
+
+    None
+
+--*/
+{
+    CHAR   *pScan;
+    CHAR   *pDest;
+    CHAR   *pNextScan;
+    WCHAR   wch;
+    DWORD   dwLen;
+    BOOL    fChanged = FALSE;
+
+    //
+    // Now take care of any escape characters
+    //
+    pDest = pScan = strchr(QueryStr(), '%');
+
+    while (pScan)
+    {
+        if ((pScan[1] == 'u' || pScan[1] == 'U') &&
+            SAFEIsXDigit(pScan[2]) &&
+            SAFEIsXDigit(pScan[3]) &&
+            SAFEIsXDigit(pScan[4]) &&
+            SAFEIsXDigit(pScan[5]))
+        {
+            wch = TOHEX(pScan[2]) * 4096 + TOHEX(pScan[3]) * 256
+                + TOHEX(pScan[4]) * 16 + TOHEX(pScan[5]);
+
+            dwLen = WideCharToMultiByte(CP_ACP,
+                                        WC_NO_BEST_FIT_CHARS,
+                                        &wch,
+                                        1,
+                                        (LPSTR) pDest,
+                                        6,
+                                        NULL,
+                                        NULL);
+
+            pDest += dwLen;
+            pScan += 6;
+            fChanged = TRUE;
+        }
+        else if (SAFEIsXDigit(pScan[1]) && SAFEIsXDigit(pScan[2]))
+        {
+            *pDest = TOHEX(pScan[1]) * 16 + TOHEX(pScan[2]);
+
+            pDest ++;
+            pScan += 3;
+            fChanged = TRUE;
+        }
+        else   // Not an escaped char, just a '%'
+        {
+            if (fChanged)
+            {
+                *pDest = *pScan;
+            }
+
+            pDest++;
+            pScan++;
+        }
+
+        //
+        // Copy all the information between this and the next escaped char
+        //
+        pNextScan = strchr(pScan, '%');
+
+        if (fChanged)   // pScan!=pDest, so we have to copy the char's
+        {
+            if (!pNextScan)   // That was the last '%' in the string
+            {
+                memmove(pDest,
+                        pScan,
+                        QueryCCH() - DIFF(pScan - QueryStr()) + 1);
+            }
+            else
+            {
+                // There is another '%', move intermediate chars
+                if ((dwLen = (DWORD)DIFF(pNextScan - pScan)) != 0)
+                {
+                    memmove(pDest,
+                            pScan,
+                            dwLen);
+                    pDest += dwLen;
+                }
+            }
+        }
+
+        pScan = pNextScan;
+    }
+
+    if (fChanged)
+    {
+        m_cchLen = (DWORD)strlen(QueryStr());  // for safety recalc the length
+    }
+
+    return;
+}
+
+HRESULT
+STRA::CopyWToUTF8Unescaped(
+    __in LPCWSTR cpchStr
+)
+{
+    return STRA::CopyWToUTF8Unescaped(cpchStr, (DWORD) wcslen(cpchStr));
+}
+
+HRESULT
+STRA::CopyWToUTF8Unescaped(
+    __in_ecount(cch)
+    LPCWSTR         cpchStr,
+    __in DWORD      cch
+)
+{
+    HRESULT hr = S_OK;
+    int iRet;
+
+    if (cch == 0)
+    {
+        Reset();
+        return S_OK;
+    }
+
+    iRet = ConvertUnicodeToUTF8(cpchStr,
+                                &m_Buff,
+                                cch);
+    if (-1 == iRet)
+    {
+        // could not convert
+        hr = HRESULT_FROM_WIN32(GetLastError());
+        goto Finished;
+    }
+
+    m_cchLen = iRet;
+
+    _ASSERTE(strlen(m_Buff.QueryPtr()) == m_cchLen);
+Finished:
+    return hr;
+}
+
+HRESULT
+STRA::CopyWToUTF8Escaped(
+    __in LPCWSTR cpchStr
+)
+{
+    return STRA::CopyWToUTF8Escaped(cpchStr, (DWORD) wcslen(cpchStr));
+}
+
+HRESULT
+STRA::CopyWToUTF8Escaped(
+    __in_ecount(cch)
+    LPCWSTR         cpchStr,
+    __in DWORD      cch
+)
+{
+    HRESULT hr = S_OK;
+
+    hr = CopyWToUTF8Unescaped(cpchStr, cch);
+    if (FAILED(hr))
+    {
+        goto Finished;
+    }
+
+    hr = Escape();
+    if (FAILED(hr))
+    {
+        goto Finished;
+    }
+
+    hr = S_OK;
+Finished:
+    return hr;
+}
+
+HRESULT
+STRA::AuxAppend(
+    __in_ecount(cbLen)
+    LPCSTR          pStr,
+    __in DWORD      cbLen,
+    __in DWORD      cbOffset
+)
+{
+    _ASSERTE( NULL != pStr );
+    _ASSERTE( cbOffset <= QueryCB() );
+
+    ULONGLONG cb64NewSize = (ULONGLONG)cbOffset + cbLen + sizeof( CHAR );
+    if( cb64NewSize > MAXDWORD )
+    {
+        return HRESULT_FROM_WIN32( ERROR_ARITHMETIC_OVERFLOW );
+    }
+
+    if( m_Buff.QuerySize() < cb64NewSize )
+    {
+        if( !m_Buff.Resize( static_cast<SIZE_T>(cb64NewSize) ) )
+        {
+            return E_OUTOFMEMORY;
+        }
+    }
+
+    memcpy( reinterpret_cast<BYTE*>(m_Buff.QueryPtr()) + cbOffset, pStr, cbLen );
+
+    m_cchLen = cbLen + cbOffset;
+
+    *( QueryStr() + m_cchLen ) = '\0';
+
+    return S_OK;
+}
+
+HRESULT
+STRA::AuxAppendW(
+    __in_ecount(cchAppendW)
+    PCWSTR          pszAppendW,
+    __in DWORD      cchAppendW,
+    __in DWORD      cbOffset,
+    __in UINT       CodePage,
+    __in BOOL       fFailIfNoTranslation,
+    __in DWORD      dwFlags
+)
+{
+    HRESULT hr          = S_OK;
+    DWORD   cbAvailable = 0;
+    DWORD   cbRet       = 0;
+
+    //
+    // There are only two expect places to append
+    //
+    _ASSERTE( 0 == cbOffset || QueryCB() == cbOffset );
+
+    if ( cchAppendW == 0 )
+    {
+        goto Finished;
+    }
+
+    //
+    // start by assuming 1 char to 1 char will be enough space
+    //
+    if( !m_Buff.Resize( cbOffset + cchAppendW + sizeof( CHAR ) ) )
+    {
+        hr = E_OUTOFMEMORY;
+        goto Finished;
+    }
+
+    cbAvailable = m_Buff.QuerySize() - cbOffset;
+
+    cbRet = WideCharToMultiByte(
+        CodePage,
+        dwFlags,
+        pszAppendW,
+        cchAppendW,
+        QueryStr() + cbOffset,
+        cbAvailable,
+        NULL,
+        NULL
+    );
+    if( 0 != cbRet )
+    {
+        if(!m_Buff.Resize(cbOffset + cbRet + 1))
+        {
+            hr = E_OUTOFMEMORY;
+        }
+
+        //
+        // not zero --> success, so we're done
+        //
+        goto Finished;
+    }
+
+    //
+    // We only know how to handle ERROR_INSUFFICIENT_BUFFER
+    //
+    hr = HRESULT_FROM_WIN32( GetLastError() );
+    if( hr != HRESULT_FROM_WIN32( ERROR_INSUFFICIENT_BUFFER ) )
+    {
+        goto Finished;
+    }
+
+    //
+    // Reset HResult because we need to get the number of bytes needed
+    //
+    hr = S_OK;
+    cbRet = WideCharToMultiByte(
+        CodePage,
+        dwFlags,
+        pszAppendW,
+        cchAppendW,
+        NULL,
+        0,
+        NULL,
+        NULL
+    );
+    if( 0 == cbRet )
+    {
+        //
+        // no idea how we could ever reach here
+        //
+        hr = HRESULT_FROM_WIN32( GetLastError() );
+        goto Finished;
+    }
+
+    if( !m_Buff.Resize( cbOffset + cbRet + 1) )
+    {
+        hr = E_OUTOFMEMORY;
+        goto Finished;
+    }
+
+    cbAvailable = m_Buff.QuerySize() - cbOffset;
+
+    cbRet = WideCharToMultiByte(
+        CodePage,
+        dwFlags,
+        pszAppendW,
+        cchAppendW,
+        QueryStr() + cbOffset,
+        cbAvailable,
+        NULL,
+        NULL
+    );
+    if( 0 == cbRet )
+    {
+        hr = HRESULT_FROM_WIN32( GetLastError() );
+        goto Finished;
+    }
+
+Finished:
+
+    if( SUCCEEDED( hr ) && 0 != cbRet )
+    {
+        m_cchLen = cbRet + cbOffset;
+    }
+
+    //
+    // ensure we're still NULL terminated in the right spot
+    // (regardless of success or failure)
+    //
+    QueryStr()[m_cchLen] = '\0';
+
+    return hr;
+}
+
+HRESULT
+STRA::AuxAppendWTruncate(
+    __in_ecount(cchAppendW)
+    __in PCWSTR     pszAppendW,
+    __in DWORD      cchAppendW,
+    __in DWORD      cbOffset
+)
+//
+// Cheesey WCHAR --> CHAR conversion
+//
+{
+    HRESULT hr = S_OK;
+    CHAR*   pszBuffer;
+
+    _ASSERTE( NULL != pszAppendW );
+    _ASSERTE( 0 == cbOffset || cbOffset == QueryCB() );
+
+    if( !pszAppendW )
+    {
+        hr = HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
+        goto Finished;
+    }
+
+    ULONGLONG cbNeeded = (ULONGLONG)cbOffset + cchAppendW + sizeof( CHAR );
+    if( cbNeeded > MAXDWORD )
+    {
+        hr = HRESULT_FROM_WIN32( ERROR_ARITHMETIC_OVERFLOW );
+        goto Finished;
+    }
+
+    if( !m_Buff.Resize( static_cast<SIZE_T>(cbNeeded) ) )
+    {
+        hr = E_OUTOFMEMORY;
+        goto Finished;
+    }
+
+    //
+    // Copy/convert the UNICODE string over (by making two bytes into one)
+    //
+    pszBuffer = QueryStr() + cbOffset;
+    for( DWORD i = 0; i < cchAppendW; i++ )
+    {
+        pszBuffer[i] = static_cast<CHAR>(pszAppendW[i]);
+    }
+
+    m_cchLen = cchAppendW + cbOffset;
+    *( QueryStr() + m_cchLen ) = '\0';
+
+Finished:
+
+    return hr;
+}
+
+// static
+int
+STRA::ConvertUnicodeToCodePage(
+    __in_ecount(dwStringLen)
+    LPCWSTR                     pszSrcUnicodeString,
+    __inout BUFFER_T<CHAR,1> *  pbufDstAnsiString,
+    __in DWORD                  dwStringLen,
+    __in UINT                   uCodePage
+)
+{
+    _ASSERTE(NULL != pszSrcUnicodeString);
+    _ASSERTE(NULL != pbufDstAnsiString);
+
+    BOOL bTemp;
+    int iStrLen = 0;
+    DWORD dwFlags;
+
+    if (uCodePage == CP_ACP)
+    {
+        dwFlags = WC_NO_BEST_FIT_CHARS;
+    }
+    else
+    {
+        dwFlags = 0;
+    }
+
+    iStrLen = WideCharToMultiByte(uCodePage,
+                                  dwFlags,
+                                  pszSrcUnicodeString,
+                                  dwStringLen,
+                                  (LPSTR)pbufDstAnsiString->QueryPtr(),
+                                  (int)pbufDstAnsiString->QuerySize(),
+                                  NULL,
+                                  NULL);
+    if ((iStrLen == 0) && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
+        iStrLen = WideCharToMultiByte(uCodePage,
+                                      dwFlags,
+                                      pszSrcUnicodeString,
+                                      dwStringLen,
+                                      NULL,
+                                      0,
+                                      NULL,
+                                      NULL);
+        if (iStrLen != 0) {
+            // add one just for the extra NULL
+            bTemp = pbufDstAnsiString->Resize(iStrLen + 1);
+            if (!bTemp)
+            {
+                iStrLen = 0;
+            }
+            else
+            {
+                iStrLen = WideCharToMultiByte(uCodePage,
+                                              dwFlags,
+                                              pszSrcUnicodeString,
+                                              dwStringLen,
+                                              (LPSTR)pbufDstAnsiString->QueryPtr(),
+                                              (int)pbufDstAnsiString->QuerySize(),
+                                              NULL,
+                                              NULL);
+            }
+
+        }
+    }
+
+    if (0 != iStrLen &&
+        pbufDstAnsiString->Resize(iStrLen + 1))
+    {
+        // insert a terminating NULL into buffer for the dwStringLen+1 in the case that the dwStringLen+1 was not a NULL.
+        ((CHAR*)pbufDstAnsiString->QueryPtr())[iStrLen] = '\0';
+    }
+    else
+    {
+        iStrLen = -1;
+    }
+
+    return iStrLen;
+}
+
+// static
+HRESULT
+STRA::ConvertUnicodeToMultiByte(
+    __in_ecount(dwStringLen)
+    LPCWSTR                     pszSrcUnicodeString,
+    __in BUFFER_T<CHAR,1> *     pbufDstAnsiString,
+    __in DWORD                  dwStringLen
+)
+{
+    return ConvertUnicodeToCodePage( pszSrcUnicodeString,
+                                      pbufDstAnsiString,
+                                      dwStringLen,
+                                      CP_ACP );
+}
+
+// static
+HRESULT
+STRA::ConvertUnicodeToUTF8(
+    __in_ecount(dwStringLen)
+    LPCWSTR                     pszSrcUnicodeString,
+    __in BUFFER_T<CHAR,1> *     pbufDstAnsiString,
+    __in DWORD                  dwStringLen
+)
+{
+    return ConvertUnicodeToCodePage( pszSrcUnicodeString,
+                                      pbufDstAnsiString,
+                                      dwStringLen,
+                                      CP_UTF8 );
+}
+
+/*++
+
+Routine Description:
+
+    Removes leading and trailing whitespace
+
+--*/
+
+VOID
+STRA::Trim()
+{
+    PSTR    pszString               = QueryStr();
+    DWORD   cchNewLength            = m_cchLen;
+    DWORD   cchLeadingWhitespace    = 0;
+    DWORD   cchTempLength           = 0;
+
+    for (LONG ixString = m_cchLen - 1; ixString >= 0; ixString--)
+    {
+        if (isspace((unsigned char) pszString[ixString]) != 0)
+        {
+            pszString[ixString] = '\0';
+            cchNewLength--;
+        }
+        else
+        {
+            break;
+        }
+    }
+
+    cchTempLength = cchNewLength;
+    for (DWORD ixString = 0; ixString < cchTempLength; ixString++)
+    {
+        if (isspace((unsigned char) pszString[ixString]) != 0)
+        {
+            cchLeadingWhitespace++;
+            cchNewLength--;
+        }
+        else
+        {
+            break;
+        }
+    }
+
+    if (cchNewLength == 0)
+    {
+
+        Reset();
+    }
+    else if (cchLeadingWhitespace > 0)
+    {
+        memmove(pszString, pszString + cchLeadingWhitespace, cchNewLength * sizeof(CHAR));
+        pszString[cchNewLength] = '\0';
+    }
+
+    SyncWithBuffer();
+}
+
+/*++
+
+Routine Description:
+
+    Compares the string to the provided prefix to check for equality
+
+Arguments:
+
+    pStraPrefix - string to compare with
+    fIgnoreCase - indicates whether the string comparison should be case-sensitive
+
+Return Value:
+
+    TRUE if prefix string matches with internal string, FALSE otherwise
+
+--*/
+BOOL
+STRA::StartsWith(
+    __in const STRA *   pStraPrefix,
+    __in bool           fIgnoreCase) const
+{
+    _ASSERTE( pStraPrefix != NULL );
+    return StartsWith(pStraPrefix->QueryStr(), fIgnoreCase);
+}
+
+/*++
+
+Routine Description:
+
+    Compares the string to the provided prefix to check for equality
+
+Arguments:
+
+    straPrefix  - string to compare with
+    fIgnoreCase - indicates whether the string comparison should be case-sensitive
+
+Return Value:
+
+    TRUE if prefix string matches with internal string, FALSE otherwise
+
+--*/
+BOOL
+STRA::StartsWith(
+    __in const STRA &   straPrefix,
+    __in bool           fIgnoreCase) const
+{
+    return StartsWith(straPrefix.QueryStr(), fIgnoreCase);
+}
+
+/*++
+
+Routine Description:
+
+    Compares the string to the provided prefix to check for equality
+
+Arguments:
+
+    pszPrefix   - string to compare with
+    fIgnoreCase - indicates whether the string comparison should be case-sensitive
+
+Return Value:
+
+    TRUE if prefix string matches with internal string, FALSE otherwise
+
+--*/
+BOOL
+STRA::StartsWith(
+    __in PCSTR          pszPrefix,
+    __in bool           fIgnoreCase) const
+{
+    HRESULT hr          = S_OK;
+    BOOL    fMatch      = FALSE;
+    size_t  cchPrefix   = 0;
+
+    if (pszPrefix == NULL)
+    {
+        goto Finished;
+    }
+
+    hr = StringCchLengthA( pszPrefix,
+                           STRSAFE_MAX_CCH,
+                           &cchPrefix );
+    if (FAILED(hr))
+    {
+        goto Finished;
+    }
+
+    _ASSERTE( cchPrefix <= MAXDWORD );
+
+    if (cchPrefix > m_cchLen)
+    {
+        goto Finished;
+    }
+
+    if( fIgnoreCase )
+    {
+        fMatch = ( 0 == _strnicmp( QueryStr(), pszPrefix, cchPrefix ) );
+    }
+    else
+    {
+        fMatch = ( 0 == strncmp( QueryStr(), pszPrefix, cchPrefix ) );
+    }
+
+
+Finished:
+
+    return fMatch;
+}
+
+/*++
+
+Routine Description:
+
+    Compares the string to the provided suffix to check for equality
+
+Arguments:
+
+    pStraSuffix - string to compare with
+    fIgnoreCase - indicates whether the string comparison should be case-sensitive
+
+Return Value:
+
+    TRUE if suffix string matches with internal string, FALSE otherwise
+
+--*/
+BOOL
+STRA::EndsWith(
+    __in const STRA *   pStraSuffix,
+    __in bool           fIgnoreCase) const
+{
+    _ASSERTE( pStraSuffix != NULL );
+    return EndsWith(pStraSuffix->QueryStr(), fIgnoreCase);
+}
+
+
+/*++
+
+Routine Description:
+
+    Compares the string to the provided suffix to check for equality
+
+Arguments:
+
+    straSuffix  - string to compare with
+    fIgnoreCase - indicates whether the string comparison should be case-sensitive
+
+Return Value:
+
+    TRUE if suffix string matches with internal string, FALSE otherwise
+
+--*/
+BOOL
+STRA::EndsWith(
+    __in const STRA &   straSuffix,
+    __in bool           fIgnoreCase) const
+{
+    return EndsWith(straSuffix.QueryStr(), fIgnoreCase);
+}
+
+
+/*++
+
+Routine Description:
+
+    Compares the string to the provided suffix to check for equality
+
+Arguments:
+
+    pszSuffix   - string to compare with
+    fIgnoreCase - indicates whether the string comparison should be case-sensitive
+
+Return Value:
+
+    TRUE if suffix string matches with internal string, FALSE otherwise
+
+--*/
+BOOL
+STRA::EndsWith(
+    __in PCSTR          pszSuffix,
+    __in bool           fIgnoreCase) const
+{
+    HRESULT   hr          = S_OK;
+    PSTR      pszString   = QueryStr();
+    BOOL      fMatch      = FALSE;
+    size_t    cchSuffix   = 0;
+    ptrdiff_t ixOffset    = 0;
+
+    if (pszSuffix == NULL)
+    {
+        goto Finished;
+    }
+
+    hr = StringCchLengthA( pszSuffix,
+                           STRSAFE_MAX_CCH,
+                           &cchSuffix );
+    if (FAILED(hr))
+    {
+        goto Finished;
+    }
+
+    _ASSERTE( cchSuffix <= MAXDWORD );
+
+    if (cchSuffix > m_cchLen)
+    {
+        goto Finished;
+    }
+
+    ixOffset = m_cchLen - cchSuffix;
+    _ASSERTE(ixOffset >= 0 && ixOffset <= MAXDWORD);
+
+    if( fIgnoreCase )
+    {
+        fMatch = ( 0 == _strnicmp( pszString + ixOffset, pszSuffix, cchSuffix ) );
+    }
+    else
+    {
+        fMatch = ( 0 == strncmp( pszString + ixOffset, pszSuffix, cchSuffix ) );
+    }
+
+Finished:
+
+    return fMatch;
+}
+
+
+/*++
+
+Routine Description:
+
+    Searches the string for the first occurrence of the specified character.
+
+Arguments:
+
+    charValue       - character to find
+    dwStartIndex    - the initial index.
+
+Return Value:
+
+    The index for the first character occurence in the string.
+
+    -1 if not found.
+
+--*/
+INT
+STRA::IndexOf(
+    __in CHAR           charValue,
+    __in DWORD          dwStartIndex
+    ) const
+{
+    INT nIndex = -1;
+
+    // Make sure that there are no buffer overruns.
+    if( dwStartIndex >= QueryCCH() )
+    {
+        goto Finished;
+    }
+
+    const CHAR* pChar = strchr( QueryStr() + dwStartIndex, charValue );
+
+    // Determine the index if found
+    if( pChar )
+    {
+        // nIndex will be set to -1 on failure.
+        (VOID)SizeTToInt( pChar - QueryStr(), &nIndex );
+    }
+
+Finished:
+
+    return nIndex;
+}
+
+
+/*++
+
+Routine Description:
+
+    Searches the string for the first occurrence of the specified substring.
+
+Arguments:
+
+    pszValue        - substring to find
+    dwStartIndex    - initial index.
+
+Return Value:
+
+    The index for the first character occurence in the string.
+
+    -1 if not found.
+
+--*/
+INT
+STRA::IndexOf(
+    __in PCSTR          pszValue,
+    __in DWORD          dwStartIndex
+    ) const
+{
+    HRESULT hr = S_OK;
+    INT nIndex = -1;
+    SIZE_T cchValue = 0;
+
+    // Validate input parameters
+    if( dwStartIndex >= QueryCCH() || !pszValue )
+    {
+        goto Finished;
+    }
+
+    const CHAR* pChar = strstr( QueryStr() + dwStartIndex, pszValue );
+
+    // Determine the index if found
+    if( pChar )
+    {
+        // nIndex will be set to -1 on failure.
+        (VOID)SizeTToInt( pChar - QueryStr(), &nIndex );
+    }
+
+Finished:
+
+    return nIndex;
+}
+
+
+/*++
+
+Routine Description:
+
+    Searches the string for the last occurrence of the specified character.
+
+Arguments:
+
+    charValue       - character to find
+    dwStartIndex    - initial index.
+
+Return Value:
+
+    The index for the last character occurence in the string.
+
+    -1 if not found.
+
+--*/
+INT
+STRA::LastIndexOf(
+    __in CHAR           charValue,
+    __in DWORD          dwStartIndex
+    ) const
+{
+    INT nIndex = -1;
+
+    // Make sure that there are no buffer overruns.
+    if( dwStartIndex >= QueryCCH() )
+    {
+        goto Finished;
+    }
+
+    const CHAR* pChar = strrchr( QueryStr() + dwStartIndex, charValue );
+
+    // Determine the index if found
+    if( pChar )
+    {
+        // nIndex will be set to -1 on failure.
+        (VOID)SizeTToInt( pChar - QueryStr(), &nIndex );
+    }
+
+Finished:
+
+    return nIndex;
+}
diff --git a/src/IISIntegration/src/AspNetCoreModuleV1/IISLib/stringa.h b/src/IISIntegration/src/AspNetCoreModuleV1/IISLib/stringa.h
new file mode 100644
index 0000000000000000000000000000000000000000..39737f4a69d8ce5bc7f2ae6938a96bb6166cd50f
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV1/IISLib/stringa.h
@@ -0,0 +1,515 @@
+// 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 "buffer.h"
+#include "macros.h"
+#include <strsafe.h>
+
+class STRA
+{
+
+public:
+
+    STRA(
+        VOID
+    );
+
+    STRA(
+        __inout_ecount(cchInit) CHAR* pbInit,
+        __in DWORD cchInit
+    );
+
+    BOOL
+    IsEmpty(
+        VOID
+    ) const;
+
+    BOOL
+    Equals(
+        __in PCSTR  pszRhs,
+        __in BOOL   fIgnoreCase = FALSE
+    ) const;
+
+    BOOL
+    Equals(
+        __in const STRA *   pstrRhs,
+        __in BOOL           fIgnoreCase = FALSE
+    ) const;
+
+    BOOL
+    Equals(
+        __in const STRA &  strRhs,
+        __in BOOL           fIgnoreCase = FALSE
+    ) const;
+
+    static
+    BOOL
+    Equals(
+        __in PCSTR          pszLhs,
+        __in PCSTR          pszRhs,
+        __in bool           fIgnoreCase = false
+    )
+    {
+        // Return FALSE if either or both strings are NULL.
+        if (!pszLhs || !pszRhs) return FALSE;
+
+        if( fIgnoreCase )
+        {
+            return ( 0 == _stricmp( pszLhs, pszRhs ) );
+        }
+
+        return ( 0 == strcmp( pszLhs, pszRhs ) );
+    }
+
+    VOID
+    Trim();
+
+    BOOL
+    StartsWith(
+        __in const STRA *   pStraPrefix,
+        __in bool           fIgnoreCase = FALSE
+    ) const;
+
+    BOOL
+    StartsWith(
+        __in const STRA &   straPrefix,
+        __in bool           fIgnoreCase = FALSE
+    ) const;
+
+    BOOL
+    StartsWith(
+        __in PCSTR          pszPrefix,
+        __in bool           fIgnoreCase = FALSE
+    ) const;
+
+    BOOL
+    EndsWith(
+        __in const STRA *   pStraSuffix,
+        __in bool           fIgnoreCase = FALSE
+    ) const;
+
+    BOOL
+    EndsWith(
+        __in const STRA &   straSuffix,
+        __in bool           fIgnoreCase = FALSE
+    ) const;
+
+    BOOL
+    EndsWith(
+        __in PCSTR          pszSuffix,
+        __in bool           fIgnoreCase = FALSE
+    ) const;
+
+    INT
+    IndexOf(
+        __in CHAR           charValue,
+        __in DWORD          dwStartIndex = 0
+    ) const;
+
+    INT
+    IndexOf(
+        __in PCSTR          pszValue,
+        __in DWORD          dwStartIndex = 0
+    ) const;
+
+    INT
+    LastIndexOf(
+        __in CHAR           charValue,
+        __in DWORD          dwStartIndex = 0
+    ) const;
+
+    DWORD
+    QueryCB(
+        VOID
+    ) const;
+
+    DWORD
+    QueryCCH(
+        VOID
+    ) const;
+
+    DWORD
+    QuerySizeCCH(
+        VOID
+    ) const;
+
+    DWORD
+    QuerySize(
+        VOID
+    ) const;
+
+    __nullterminated
+    __bcount(this->m_cchLen)
+    CHAR *
+    QueryStr(
+        VOID
+    ) const;
+
+    VOID
+    Reset(
+        VOID
+    );
+
+    HRESULT
+    Resize(
+        __in DWORD cchSize
+    );
+
+    HRESULT
+    SyncWithBuffer(
+        VOID
+    );
+
+    HRESULT
+    Copy(
+        __in PCSTR   pszCopy
+    );
+
+    HRESULT
+    Copy(
+        __in_ecount(cbLen)
+        PCSTR           pszCopy,
+        __in SIZE_T     cbLen
+    );
+
+    HRESULT
+    Copy(
+        __in const STRA * pstrRhs
+    );
+
+    HRESULT
+    Copy(
+        __in const STRA & strRhs
+    );
+
+    HRESULT
+    CopyW(
+        __in PCWSTR  pszCopyW
+    );
+
+    HRESULT
+    CopyW(
+        __in_ecount(cchLen)
+        PCWSTR          pszCopyW,
+        __in SIZE_T     cchLen,
+        __in UINT       CodePage = CP_UTF8,
+        __in BOOL       fFailIfNoTranslation = FALSE
+    )
+    {
+        _ASSERTE( cchLen <= MAXDWORD );
+
+        return AuxAppendW(
+            pszCopyW,
+            static_cast<DWORD>(cchLen),
+            0,
+            CodePage,
+            fFailIfNoTranslation
+        );
+    }
+
+    HRESULT
+    CopyWTruncate(
+        __in PCWSTR pszCopyWTruncate
+    );
+
+    HRESULT
+    CopyWTruncate(
+        __in_ecount(cchLen)
+        PCWSTR          pszCopyWTruncate,
+        __in SIZE_T     cchLen
+    );
+
+    HRESULT
+    Append(
+        __in PCSTR pszAppend
+    );
+
+    HRESULT
+    Append(
+        __in_ecount(cbLen)
+        PCSTR       pszAppend,
+        __in SIZE_T cbLen
+    );
+
+    HRESULT
+    Append(
+        __in const STRA * pstrRhs
+    );
+
+    HRESULT
+    Append(
+        __in const STRA & strRhs
+    );
+
+    HRESULT
+    AppendW(
+        __in PCWSTR  pszAppendW
+    )
+    {
+        HRESULT     hr;
+        size_t      cchLen;
+        hr = StringCchLengthW( pszAppendW,
+                               STRSAFE_MAX_CCH,
+                               &cchLen );
+        if ( FAILED( hr ) )
+        {
+            return hr;
+        }
+        return AppendW( pszAppendW, cchLen );
+    }
+
+    HRESULT
+    AppendW(
+        __in_ecount(cchLen)
+        PCWSTR          pszAppendW,
+        __in SIZE_T     cchLen,
+        __in UINT       CodePage = CP_UTF8,
+        __in BOOL       fFailIfNoTranslation = FALSE
+    )
+    {
+        _ASSERTE( cchLen <= MAXDWORD );
+        if ( cchLen == 0 )
+        {
+            return S_OK;
+        }
+        return AuxAppendW(
+            pszAppendW,
+            static_cast<DWORD>(cchLen),
+            QueryCB(),
+            CodePage,
+            fFailIfNoTranslation
+        );
+    }
+
+    HRESULT
+    AppendWTruncate(
+        __in PCWSTR pszAppendWTruncate
+    );
+
+    HRESULT
+    AppendWTruncate(
+        __in_ecount(cchLen)
+        PCWSTR          pszAppendWTruncate,
+        __in SIZE_T     cchLen
+    );
+
+    HRESULT
+    CopyToBuffer(
+        __out_bcount(*pcb) CHAR*    pszBuffer,
+        __inout DWORD *             pcb
+    ) const;
+
+    HRESULT
+    SetLen(
+        __in DWORD cchLen
+    );
+
+    HRESULT
+    SafeSnprintf(
+        __in __format_string
+        PCSTR       pszFormatString,
+        ...
+    );
+
+    HRESULT
+    SafeVsnprintf(
+        __in __format_string
+        PCSTR       pszFormatString,
+        va_list     argsList
+    );
+
+    HRESULT
+    Escape(
+        VOID
+    );
+
+    HRESULT
+    EscapeUtf8(
+        VOID
+    );
+
+    VOID
+    Unescape(
+        VOID
+    );
+
+    HRESULT
+    CopyWToUTF8Unescaped(
+        __in LPCWSTR cpchStr
+    );
+
+    HRESULT
+    CopyWToUTF8Unescaped(
+        __in_ecount(cch)
+        LPCWSTR         cpchStr,
+        __in DWORD      cch
+    );
+
+    HRESULT
+    CopyWToUTF8Escaped(
+        __in LPCWSTR cpchStr
+    );
+
+    HRESULT
+    CopyWToUTF8Escaped(
+        __in_ecount(cch)
+        LPCWSTR         cpchStr,
+        __in DWORD      cch
+    );
+
+private:
+
+    //
+    // Avoid C++ errors. This object should never go through a copy
+    // constructor, unintended cast or assignment.
+    //
+    STRA( const STRA &);
+    STRA & operator = (const STRA &);
+
+    HRESULT
+    AuxAppend(
+        __in_ecount(cbLen)
+        LPCSTR          pStr,
+        __in DWORD      cbLen,
+        __in DWORD      cbOffset
+    );
+
+    HRESULT
+    AuxAppendW(
+        __in_ecount(cchAppendW)
+        PCWSTR          pszAppendW,
+        __in DWORD      cchAppendW,
+        __in DWORD      cbOffset,
+        __in UINT       CodePage,
+        __in BOOL       fFailIfNoTranslation
+    )
+    {
+        DWORD dwFlags = 0;
+
+        if( CP_ACP == CodePage )
+        {
+            dwFlags = WC_NO_BEST_FIT_CHARS;
+        }
+        else if( fFailIfNoTranslation && CodePage == CP_UTF8 )
+        {
+            //
+            // WC_ERR_INVALID_CHARS is only supported in Longhorn or greater.
+            //
+#if defined( NTDDI_VERSION ) && NTDDI_VERSION >= NTDDI_LONGHORN
+            dwFlags |= WC_ERR_INVALID_CHARS;
+#else
+            UNREFERENCED_PARAMETER(fFailIfNoTranslation);
+#endif
+        }
+
+        return AuxAppendW( pszAppendW,
+                            cchAppendW,
+                            cbOffset,
+                            CodePage,
+                            fFailIfNoTranslation,
+                            dwFlags );
+    }
+
+    HRESULT
+    AuxAppendW(
+        __in_ecount(cchAppendW)
+        PCWSTR          pszAppendW,
+        __in DWORD      cchAppendW,
+        __in DWORD      cbOffset,
+        __in UINT       CodePage,
+        __in BOOL       fFailIfNoTranslation,
+        __in DWORD      dwFlags
+    );
+
+    HRESULT
+    AuxAppendWTruncate(
+        __in_ecount(cchAppendW)
+        __in PCWSTR     pszAppendW,
+        __in DWORD      cchAppendW,
+        __in DWORD      cbOffset
+    );
+
+    static
+    int
+    ConvertUnicodeToCodePage(
+        __in_ecount(dwStringLen)
+        LPCWSTR                     pszSrcUnicodeString,
+        __inout BUFFER_T<CHAR,1> *  pbufDstAnsiString,
+        __in DWORD                  dwStringLen,
+        __in UINT                   uCodePage
+    );
+
+    static
+    HRESULT
+    ConvertUnicodeToMultiByte(
+        __in_ecount(dwStringLen)
+        LPCWSTR                     pszSrcUnicodeString,
+        __in BUFFER_T<CHAR,1> *     pbufDstAnsiString,
+        __in DWORD                  dwStringLen
+    );
+
+    static
+    HRESULT
+    ConvertUnicodeToUTF8(
+        __in_ecount(dwStringLen)
+        LPCWSTR                     pszSrcUnicodeString,
+        __in BUFFER_T<CHAR,1> *     pbufDstAnsiString,
+        __in DWORD                  dwStringLen
+    );
+
+    typedef bool (* PFN_F_SHOULD_ESCAPE)(BYTE ch);
+
+    HRESULT
+    EscapeInternal(
+        PFN_F_SHOULD_ESCAPE pfnFShouldEscape
+    );
+
+    //
+    // Buffer with an inline buffer of 1,
+    // enough to hold null-terminating character.
+    //
+    BUFFER_T<CHAR,1>    m_Buff;
+    DWORD               m_cchLen;
+};
+
+inline
+HRESULT
+AppendToString(
+    ULONGLONG Number,
+    STRA & String
+)
+{
+    // prefast complains Append requires input
+    // to be null terminated, so zero initialize
+    // and pass the size of the buffer minus one
+    // to _ui64toa_s
+    CHAR chNumber[32] = {0};
+    if (_ui64toa_s(Number,
+                   chNumber,
+                   sizeof(chNumber) - sizeof(CHAR),
+                   10) != 0)
+    {
+        return E_INVALIDARG;
+    }
+    return String.Append(chNumber);
+}
+
+template<DWORD size>
+CHAR* InitHelper(__out CHAR (&psz)[size])
+{
+    psz[0] = '\0';
+    return psz;
+}
+
+//
+// Heap operation reduction macros
+//
+#define STACK_STRA(name, size)  CHAR __ach##name[size];\
+                                STRA  name(InitHelper(__ach##name), sizeof(__ach##name))
+
+#define INLINE_STRA(name, size) CHAR __ach##name[size];\
+                                STRA  name;
+
+#define INLINE_STRA_INIT(name) name(InitHelper(__ach##name), sizeof(__ach##name))
diff --git a/src/IISIntegration/src/AspNetCoreModuleV1/IISLib/stringu.cpp b/src/IISIntegration/src/AspNetCoreModuleV1/IISLib/stringu.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..15da79a7fe1dc5bef14520dd48225d2b6b5cb6a8
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV1/IISLib/stringu.cpp
@@ -0,0 +1,1271 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#pragma warning (disable : 4267)
+
+#include "precomp.h"
+
+STRU::STRU(
+    VOID
+) : m_cchLen( 0 )
+{
+    *(QueryStr()) = L'\0';
+}
+
+STRU::STRU(
+    __inout_ecount(cchInit) WCHAR* pbInit,
+    __in DWORD cchInit
+) : m_Buff( pbInit, cchInit * sizeof( WCHAR ) ),
+    m_cchLen( 0 )
+/*++
+    Description:
+
+        Used by STACK_STRU. Initially populates underlying buffer with pbInit.
+
+        pbInit is not freed.
+
+    Arguments:
+
+        pbInit - initial memory to use
+        cchInit - count, in characters, of pbInit
+
+    Returns:
+
+        None.
+
+--*/
+{
+    _ASSERTE( cchInit <= (MAXDWORD / sizeof( WCHAR )) );
+    _ASSERTE( NULL != pbInit );
+    _ASSERTE(cchInit > 0 );
+    _ASSERTE(pbInit[0] == L'\0');
+}
+
+BOOL
+STRU::IsEmpty(
+    VOID
+) const
+{
+    return ( m_cchLen == 0 );
+}
+
+DWORD
+STRU::QueryCB(
+    VOID
+) const
+//
+// Returns the number of bytes in the string excluding the terminating NULL
+//
+{
+    return m_cchLen * sizeof( WCHAR );
+}
+
+DWORD
+STRU::QueryCCH(
+    VOID
+) const
+//
+//  Returns the number of characters in the string excluding the terminating NULL
+//
+{
+    return m_cchLen;
+}
+
+DWORD
+STRU::QuerySizeCCH(
+    VOID
+) const
+//
+// Returns size of the underlying storage buffer, in characters
+//
+{
+    return m_Buff.QuerySize() / sizeof( WCHAR );
+}
+
+__nullterminated
+__ecount(this->m_cchLen)
+WCHAR*
+STRU::QueryStr(
+    VOID
+) const
+//
+//  Return the string buffer
+//
+{
+    return m_Buff.QueryPtr();
+}
+
+VOID
+STRU::Reset(
+    VOID
+)
+//
+// Resets the internal string to be NULL string. Buffer remains cached.
+//
+{
+    _ASSERTE( QueryStr() != NULL );
+    *(QueryStr()) = L'\0';
+    m_cchLen = 0;
+}
+
+HRESULT
+STRU::Resize(
+    DWORD cchSize
+)
+{
+    SIZE_T cbSize = cchSize * sizeof( WCHAR );
+    if ( cbSize > MAXDWORD )
+    {
+        return HRESULT_FROM_WIN32( ERROR_ARITHMETIC_OVERFLOW );
+    }
+    if( !m_Buff.Resize( cbSize ) )
+    {
+        return E_OUTOFMEMORY;
+    }
+
+    return S_OK;
+}
+
+HRESULT
+STRU::SyncWithBuffer(
+    VOID
+)
+//
+// Recalculate the length of the string, etc. because we've modified
+// the buffer directly.
+//
+{
+    HRESULT hr;
+    size_t size;
+    hr = StringCchLengthW( QueryStr(),
+                           QuerySizeCCH(),
+                           &size );
+    if ( SUCCEEDED( hr ) )
+    {
+        m_cchLen = static_cast<DWORD>(size);
+    }
+    return hr;
+}
+
+HRESULT
+STRU::Copy(
+    __in PCWSTR pszCopy
+)
+{
+    HRESULT hr;
+    size_t  cbStr;
+
+    hr = StringCchLengthW( pszCopy,
+                          STRSAFE_MAX_CCH,
+                          &cbStr );
+    if ( FAILED( hr ) )
+    {
+        return hr;
+    }
+
+    _ASSERTE( cbStr <= MAXDWORD );
+    return Copy( pszCopy,
+                 cbStr );
+}
+
+HRESULT
+STRU::Copy(
+    __in_ecount(cchLen)
+    PCWSTR  pszCopy,
+    SIZE_T  cchLen
+)
+//
+// Copy the contents of another string to this one
+//
+{
+    return AuxAppend( pszCopy,
+                      cchLen * sizeof(WCHAR),
+                      0);
+}
+
+HRESULT
+STRU::Copy(
+    __in const STRU * pstrRhs
+)
+{
+    _ASSERTE( NULL != pstrRhs );
+    return Copy( pstrRhs->QueryStr(), pstrRhs->QueryCCH() );
+}
+
+HRESULT
+STRU::Copy(
+    __in const STRU & str
+)
+{
+    return Copy( str.QueryStr(), str.QueryCCH() );
+}
+
+HRESULT
+STRU::CopyAndExpandEnvironmentStrings(
+    __in PCWSTR     pszSource
+)
+{
+    HRESULT hr = S_OK;
+    DWORD   cchDestReqBuff = 0;
+
+    Reset();
+
+    cchDestReqBuff = ExpandEnvironmentStringsW( pszSource,
+                                                QueryStr(),
+                                                QuerySizeCCH() );
+    if ( cchDestReqBuff == 0 )
+    {
+        hr = HRESULT_FROM_WIN32( GetLastError() );
+        goto Finished;
+    }
+    else if ( cchDestReqBuff > QuerySizeCCH() )
+    {
+        hr = Resize( cchDestReqBuff );
+        if ( FAILED( hr ) )
+        {
+            goto Finished;
+        }
+
+        cchDestReqBuff = ExpandEnvironmentStringsW( pszSource,
+                                                    QueryStr(),
+                                                    QuerySizeCCH() );
+
+        if ( cchDestReqBuff == 0 || cchDestReqBuff > QuerySizeCCH() )
+        {
+            _ASSERTE( FALSE );
+            hr = HRESULT_FROM_WIN32( GetLastError() );
+            goto Finished;
+        }
+    }
+
+    hr = SyncWithBuffer();
+    if ( FAILED( hr ) )
+    {
+        goto Finished;
+    }
+
+Finished:
+
+    return hr;
+
+}
+
+HRESULT
+STRU::CopyA(
+    __in PCSTR  pszCopyA
+)
+{
+    HRESULT hr;
+    size_t  cbStr;
+
+    hr = StringCbLengthA( pszCopyA,
+                          STRSAFE_MAX_CCH,
+                          &cbStr );
+    if ( FAILED( hr ) )
+    {
+        return hr;
+    }
+
+    _ASSERTE( cbStr <= MAXDWORD );
+    return CopyA( pszCopyA,
+                  cbStr );
+}
+
+HRESULT
+STRU::CopyA(
+    __in_bcount(cchLen)
+    PCSTR   pszCopyA,
+    SIZE_T  cchLen,
+    UINT    CodePage /*= CP_UTF8*/
+)
+{
+    return AuxAppendA(
+        pszCopyA,
+        cchLen,
+        0,
+        CodePage
+    );
+}
+
+HRESULT
+STRU::Append(
+    __in PCWSTR  pszAppend
+)
+{
+    HRESULT hr;
+    size_t  cbStr;
+
+    hr = StringCchLengthW( pszAppend,
+                           STRSAFE_MAX_CCH,
+                           &cbStr );
+    if ( FAILED( hr ) )
+    {
+        return hr;
+    }
+
+    _ASSERTE( cbStr <= MAXDWORD );
+    return Append( pszAppend,
+                   cbStr );
+}
+
+HRESULT
+STRU::Append(
+    __in_ecount(cchLen)
+    PCWSTR  pszAppend,
+    SIZE_T  cchLen
+)
+//
+// Append something to the end of the string
+//
+{
+    if ( cchLen == 0 )
+    {
+        return S_OK;
+    }
+    return AuxAppend( pszAppend,
+                      cchLen * sizeof(WCHAR),
+                      QueryCB() );
+}
+
+HRESULT
+STRU::Append(
+    __in const STRU * pstrRhs
+)
+{
+    _ASSERTE( NULL != pstrRhs );
+    return Append( pstrRhs->QueryStr(), pstrRhs->QueryCCH() );
+}
+
+HRESULT
+STRU::Append(
+    __in const STRU & strRhs
+)
+{
+    return Append( strRhs.QueryStr(), strRhs.QueryCCH() );
+}
+
+HRESULT
+STRU::AppendA(
+    __in PCSTR  pszAppendA
+)
+{
+    HRESULT hr;
+    size_t  cbStr;
+
+    hr = StringCbLengthA( pszAppendA,
+                          STRSAFE_MAX_CCH,
+                          &cbStr );
+    if ( FAILED( hr ) )
+    {
+        return hr;
+    }
+
+    _ASSERTE( cbStr <= MAXDWORD );
+    return AppendA( pszAppendA,
+                    cbStr );
+}
+
+HRESULT
+STRU::AppendA(
+    __in_bcount(cchLen)
+    PCSTR   pszAppendA,
+    SIZE_T  cchLen,
+    UINT    CodePage /*= CP_UTF8*/
+)
+{
+    if ( cchLen == 0 )
+    {
+        return S_OK;
+    }
+    return AuxAppendA(
+        pszAppendA,
+        cchLen,
+        QueryCB(),
+        CodePage
+    );
+}
+
+HRESULT
+STRU::CopyToBuffer(
+    __out_bcount(*pcb) WCHAR*   pszBuffer,
+    PDWORD                      pcb
+) const
+//
+// Makes a copy of the stored string into the given buffer
+//
+{
+    _ASSERTE( NULL != pszBuffer );
+    _ASSERTE( NULL != pcb );
+
+    HRESULT hr          = S_OK;
+    DWORD   cbNeeded    = QueryCB() + sizeof( WCHAR );
+
+    if( *pcb < cbNeeded )
+    {
+        hr = HRESULT_FROM_WIN32( ERROR_INSUFFICIENT_BUFFER );
+        goto Finished;
+    }
+
+    //
+    // BUGBUG: StringCchCopy?
+    //
+    memcpy( pszBuffer, QueryStr(), cbNeeded );
+
+Finished:
+
+    *pcb = cbNeeded;
+
+    return hr;
+}
+
+HRESULT
+STRU::SetLen(
+    __in DWORD cchLen
+)
+/*++
+ *
+Routine Description:
+
+    Set the length of the string and null terminate, if there
+    is sufficient buffer already allocated. Will not reallocate.
+
+Arguments:
+
+    cchLen - The number of characters in the new string.
+
+Return Value:
+
+    HRESULT
+
+--*/
+{
+    if( cchLen >= QuerySizeCCH() )
+    {
+        return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
+    }
+
+    *( QueryStr() + cchLen ) = L'\0';
+    m_cchLen = cchLen;
+
+    return S_OK;
+}
+
+HRESULT
+STRU::SafeSnwprintf(
+    __in PCWSTR pwszFormatString,
+    ...
+)
+/*++
+
+Routine Description:
+
+    Writes to a STRU, growing it as needed. It arbitrarily caps growth at 64k chars.
+
+Arguments:
+
+    pwszFormatString    - printf format
+    ...                 - printf args
+
+Return Value:
+
+    HRESULT
+
+--*/
+{
+    HRESULT     hr = S_OK;
+    va_list     argsList;
+    va_start(   argsList, pwszFormatString );
+
+    hr = SafeVsnwprintf(pwszFormatString, argsList);
+
+    va_end( argsList );
+    return hr;
+}
+
+HRESULT
+STRU::SafeVsnwprintf(
+    __in PCWSTR pwszFormatString,
+    va_list     argsList
+)
+/*++
+
+Routine Description:
+
+    Writes to a STRU, growing it as needed. It arbitrarily caps growth at 64k chars.
+
+Arguments:
+
+    pwszFormatString    - printf format
+    argsList            - printf va_list
+
+Return Value:
+
+    HRESULT
+
+--*/
+{
+    HRESULT     hr = S_OK;
+    int         cchOutput;
+    int         cchNeeded;
+
+    //
+    // Format the incoming message using vsnprintf()
+    // so that the overflows are captured
+    //
+    cchOutput = _vsnwprintf_s(
+            QueryStr(),
+            QuerySizeCCH(),
+            QuerySizeCCH() - 1,
+            pwszFormatString,
+            argsList
+        );
+
+    if( cchOutput == -1 )
+    {
+        //
+        // Couldn't fit this in the original STRU size.
+        //
+        cchNeeded = _vscwprintf( pwszFormatString, argsList );
+        if( cchNeeded > 64 * 1024 )
+        {
+            //
+            // If we're trying to produce a string > 64k chars, then
+            // there is probably a problem
+            //
+            hr = HRESULT_FROM_WIN32( ERROR_INVALID_DATA );
+            goto Finished;
+        }
+
+        //
+        // _vscprintf doesn't include terminating null character
+        //
+        cchNeeded++;
+
+        hr = Resize( cchNeeded );
+        if( FAILED( hr ) )
+        {
+            goto Finished;
+        }
+
+        cchOutput = _vsnwprintf_s(
+            QueryStr(),
+            QuerySizeCCH(),
+            QuerySizeCCH() - 1,
+            pwszFormatString,
+            argsList
+        );
+        if( -1 == cchOutput )
+        {
+            //
+            // This should never happen, cause we should already have correctly sized memory
+            //
+            _ASSERTE( FALSE );
+
+            hr = HRESULT_FROM_WIN32( ERROR_INVALID_DATA );
+            goto Finished;
+        }
+    }
+
+    //
+    // always null terminate at the last WCHAR
+    //
+    QueryStr()[ QuerySizeCCH() - 1 ] = L'\0';
+
+    //
+    // we directly touched the buffer - therefore:
+    //
+    hr = SyncWithBuffer();
+    if ( FAILED( hr ) )
+    {
+        goto Finished;
+    }
+
+Finished:
+
+    if( FAILED( hr ) )
+    {
+        Reset();
+    }
+
+    return hr;
+}
+
+HRESULT
+STRU::AuxAppend(
+    __in_ecount(cNumStrings)
+    PCWSTR const    rgpszStrings[],
+    SIZE_T          cNumStrings
+)
+/*++
+
+Routine Description:
+
+    Appends an array of strings of length cNumStrings
+
+Arguments:
+
+    rgStrings   - The array of strings to be appened
+    cNumStrings - The count of String
+
+Return Value:
+
+    HRESULT
+
+--*/
+{
+    HRESULT         hr = S_OK;
+    size_t          cbStringsTotal = sizeof( WCHAR ); // Account for null-terminator
+
+    //
+    //  Compute total size of the string.
+    //  Resize internal buffer
+    //  Copy each array element one by one to backing buffer
+    //  Update backing buffer string length
+    //
+    for ( SIZE_T i = 0; i < cNumStrings; i++ )
+    {
+        _ASSERTE( rgpszStrings[ i ] != NULL );
+        if ( NULL == rgpszStrings[ i ] )
+        {
+            return E_INVALIDARG;
+        }
+
+        size_t      cbString = 0;
+
+        hr = StringCbLengthW( rgpszStrings[ i ],
+                             STRSAFE_MAX_CCH * sizeof( WCHAR ),
+                             &cbString );
+        if ( FAILED( hr ) )
+        {
+            return hr;
+        }
+
+        cbStringsTotal += cbString;
+
+        if ( cbStringsTotal > MAXDWORD )
+        {
+            return HRESULT_FROM_WIN32( ERROR_ARITHMETIC_OVERFLOW );
+        }
+    }
+
+    size_t cbBufSizeRequired = QueryCB() + cbStringsTotal;
+    if ( cbBufSizeRequired > MAXDWORD )
+    {
+        return HRESULT_FROM_WIN32( ERROR_ARITHMETIC_OVERFLOW );
+    }
+
+    if( m_Buff.QuerySize() < cbBufSizeRequired )
+    {
+        if( !m_Buff.Resize( cbBufSizeRequired ) )
+        {
+            return E_OUTOFMEMORY;
+        }
+    }
+
+    STRSAFE_LPWSTR pszStringEnd = QueryStr() + QueryCCH();
+    size_t cchRemaining = QuerySizeCCH() - QueryCCH();
+    for ( SIZE_T i = 0; i < cNumStrings; i++ )
+    {
+        hr = StringCchCopyExW( pszStringEnd,        //  pszDest
+                               cchRemaining,        //  cchDest
+                               rgpszStrings[ i ],   //  pszSrc
+                               &pszStringEnd,       //  ppszDestEnd
+                               &cchRemaining,       //  pcchRemaining
+                               0 );                 //  dwFlags
+        if ( FAILED( hr ) )
+        {
+            _ASSERTE( FALSE );
+            HRESULT hr2 = SyncWithBuffer();
+            if ( FAILED( hr2 ) )
+            {
+                return hr2;
+            }
+            return hr;
+        }
+    }
+
+    m_cchLen = static_cast< DWORD >( cbBufSizeRequired ) / sizeof( WCHAR ) - 1;
+
+    return S_OK;
+}
+
+HRESULT
+STRU::AuxAppend(
+    __in_bcount(cbStr)
+    const WCHAR*    pStr,
+    SIZE_T          cbStr,
+    DWORD           cbOffset
+)
+/*++
+
+Routine Description:
+
+    Appends to the string starting at the (byte) offset cbOffset.
+
+Arguments:
+
+    pStr     - A unicode string to be appended
+    cbStr    - Length, in bytes, of pStr
+    cbOffset - Offset, in bytes, at which to begin the append
+
+Return Value:
+
+    HRESULT
+
+--*/
+{
+    _ASSERTE( NULL != pStr );
+    _ASSERTE( 0 == cbStr % sizeof( WCHAR ) );
+    _ASSERTE( cbOffset <= QueryCB() );
+    _ASSERTE( 0 == cbOffset % sizeof( WCHAR ) );
+
+    ULONGLONG cb64NewSize = (ULONGLONG)cbOffset + cbStr + sizeof( WCHAR );
+    if( cb64NewSize > MAXDWORD )
+    {
+        return HRESULT_FROM_WIN32( ERROR_ARITHMETIC_OVERFLOW );
+    }
+
+    if( m_Buff.QuerySize() < cb64NewSize )
+    {
+        if( !m_Buff.Resize( static_cast<SIZE_T>(cb64NewSize) ) )
+        {
+            return E_OUTOFMEMORY;
+        }
+    }
+
+    memcpy( reinterpret_cast<BYTE*>(m_Buff.QueryPtr()) + cbOffset, pStr, cbStr );
+
+    m_cchLen = (static_cast<DWORD>(cbStr) + cbOffset) / sizeof(WCHAR);
+
+    *( QueryStr() + m_cchLen ) = L'\0';
+
+    return S_OK;
+}
+
+HRESULT
+STRU::AuxAppendA(
+    __in_bcount(cbStr)
+    const CHAR*     pStr,
+    SIZE_T          cbStr,
+    DWORD           cbOffset,
+    UINT            CodePage
+)
+/*++
+
+Routine Description:
+
+    Convert and append an ANSI string to the string starting at
+    the (byte) offset cbOffset
+
+Arguments:
+
+    pStr     - An ANSI string to be appended
+    cbStr    - Length, in bytes, of pStr
+    cbOffset - Offset, in bytes, at which to begin the append
+    CodePage - code page to use for conversion
+
+Return Value:
+
+    HRESULT
+
+--*/
+{
+    WCHAR*  pszBuffer;
+    DWORD   cchBuffer;
+    DWORD   cchCharsCopied = 0;
+
+    _ASSERTE( NULL != pStr );
+    _ASSERTE( cbOffset <= QueryCB() );
+    _ASSERTE( 0 == cbOffset % sizeof( WCHAR ) );
+
+    if ( NULL == pStr )
+    {
+        return E_INVALIDARG;
+    }
+
+    if( 0 == cbStr )
+    {
+        return S_OK;
+    }
+
+    //
+    //  Only resize when we have to.  When we do resize, we tack on
+    //  some extra space to avoid extra reallocations.
+    //
+    if( m_Buff.QuerySize() < (ULONGLONG)cbOffset + (cbStr * sizeof( WCHAR )) + sizeof(WCHAR) )
+    {
+        ULONGLONG cb64NewSize = (ULONGLONG)( cbOffset + cbStr * sizeof(WCHAR) + sizeof( WCHAR ) );
+
+        //
+        // Check for the arithmetic overflow
+        //
+        if( cb64NewSize > MAXDWORD )
+        {
+            return HRESULT_FROM_WIN32( ERROR_ARITHMETIC_OVERFLOW );
+        }
+
+        if( !m_Buff.Resize( static_cast<SIZE_T>(cb64NewSize) ) )
+        {
+            return E_OUTOFMEMORY;
+        }
+    }
+
+    pszBuffer = reinterpret_cast<WCHAR*>(reinterpret_cast<BYTE*>(m_Buff.QueryPtr()) + cbOffset);
+    cchBuffer = ( m_Buff.QuerySize() - cbOffset - sizeof( WCHAR ) ) / sizeof( WCHAR );
+
+    cchCharsCopied = MultiByteToWideChar(
+        CodePage,
+        MB_ERR_INVALID_CHARS,
+        pStr,
+        static_cast<int>(cbStr),
+        pszBuffer,
+        cchBuffer
+    );
+    if( 0 == cchCharsCopied )
+    {
+        return HRESULT_FROM_WIN32( GetLastError() );
+    }
+
+    //
+    // set the new length
+    //
+    m_cchLen = cchCharsCopied + cbOffset/sizeof(WCHAR);
+
+    //
+    // Must be less than, cause still need to add NULL
+    //
+    _ASSERTE( m_cchLen < QuerySizeCCH() );
+
+    //
+    // append NULL character
+    //
+    *(QueryStr() + m_cchLen) = L'\0';
+
+    return S_OK;
+}
+
+
+/*++
+
+Routine Description:
+
+    Removes leading and trailing whitespace
+
+--*/
+
+VOID
+STRU::Trim()
+{
+    PWSTR               pwszString              = QueryStr();
+    DWORD               cchNewLength            = m_cchLen;
+    DWORD               cchLeadingWhitespace    = 0;
+    DWORD               cchTempLength           = 0;
+
+    for (LONG ixString = m_cchLen - 1; ixString >= 0; ixString--)
+    {
+        if (iswspace(pwszString[ixString]) != 0)
+        {
+            pwszString[ixString] = L'\0';
+            cchNewLength--;
+        }
+        else
+        {
+            break;
+        }
+    }
+
+    cchTempLength = cchNewLength;
+    for (DWORD ixString = 0; ixString < cchTempLength; ixString++)
+    {
+        if (iswspace(pwszString[ixString]) != 0)
+        {
+            cchLeadingWhitespace++;
+            cchNewLength--;
+        }
+        else
+        {
+            break;
+        }
+    }
+
+    if (cchNewLength == 0)
+    {
+
+        Reset();
+    }
+    else if (cchLeadingWhitespace > 0)
+    {
+        memmove(pwszString, pwszString + cchLeadingWhitespace, cchNewLength * sizeof(WCHAR));
+        pwszString[cchNewLength] = L'\0';
+    }
+
+    SyncWithBuffer();
+}
+
+/*++
+
+Routine Description:
+
+    Compares the string to the provided prefix to check for equality
+
+Arguments:
+
+    pwszPrefix  - wide char string to compare with
+    fIgnoreCase - indicates whether the string comparison should be case-sensitive
+
+Return Value:
+
+    TRUE if prefix string matches with internal string, FALSE otherwise
+
+--*/
+
+BOOL
+STRU::StartsWith(
+    __in PCWSTR         pwszPrefix,
+    __in bool           fIgnoreCase) const
+{
+    HRESULT hr          = S_OK;
+    BOOL    fMatch      = FALSE;
+    size_t  cchPrefix   = 0;
+
+    if (pwszPrefix == NULL)
+    {
+        goto Finished;
+    }
+
+    hr = StringCchLengthW( pwszPrefix,
+                           STRSAFE_MAX_CCH,
+                           &cchPrefix );
+    if (FAILED(hr))
+    {
+        goto Finished;
+    }
+
+    _ASSERTE( cchPrefix <= MAXDWORD );
+
+    if (cchPrefix > m_cchLen)
+    {
+        goto Finished;
+    }
+
+    #if defined( NTDDI_VERSION ) && NTDDI_VERSION >= NTDDI_LONGHORN
+
+        fMatch = ( CSTR_EQUAL == CompareStringOrdinal( QueryStr(),
+                                                       cchPrefix,
+                                                       pwszPrefix,
+                                                       cchPrefix,
+                                                       fIgnoreCase ) );
+    #else
+
+        if( fIgnoreCase )
+        {
+            fMatch = ( 0 == _wcsnicmp( QueryStr(), pwszPrefix, cchPrefix ) );
+        }
+        else
+        {
+            fMatch = ( 0 == wcsncmp( QueryStr(), pwszPrefix, cchPrefix ) );
+        }
+
+    #endif
+
+Finished:
+
+    return fMatch;
+}
+
+/*++
+
+Routine Description:
+
+    Compares the string to the provided suffix to check for equality
+
+Arguments:
+
+    pwszSuffix  - wide char string to compare with
+    fIgnoreCase - indicates whether the string comparison should be case-sensitive
+
+Return Value:
+
+    TRUE if suffix string matches with internal string, FALSE otherwise
+
+--*/
+
+
+BOOL
+STRU::EndsWith(
+    __in PCWSTR         pwszSuffix,
+    __in bool           fIgnoreCase) const
+{
+    HRESULT     hr          = S_OK;
+    PWSTR       pwszString  = QueryStr();
+    BOOL        fMatch      = FALSE;
+    size_t      cchSuffix   = 0;
+    ptrdiff_t   ixOffset    = 0;
+
+    if (pwszSuffix == NULL)
+    {
+        goto Finished;
+    }
+
+    hr = StringCchLengthW( pwszSuffix,
+                           STRSAFE_MAX_CCH,
+                           &cchSuffix );
+    if (FAILED(hr))
+    {
+        goto Finished;
+    }
+
+    _ASSERTE( cchSuffix <= MAXDWORD );
+
+    if (cchSuffix > m_cchLen)
+    {
+        goto Finished;
+    }
+
+    ixOffset = m_cchLen - cchSuffix;
+    _ASSERTE(ixOffset >= 0 && ixOffset <= MAXDWORD);
+
+    #if defined( NTDDI_VERSION ) && NTDDI_VERSION >= NTDDI_LONGHORN
+
+        fMatch = ( CSTR_EQUAL == CompareStringOrdinal( pwszString + ixOffset,
+                                                       cchSuffix,
+                                                       pwszSuffix,
+                                                       cchSuffix,
+                                                       fIgnoreCase ) );
+    #else
+
+        if( fIgnoreCase )
+        {
+            fMatch = ( 0 == _wcsnicmp( pwszString + ixOffset, pwszSuffix, cchSuffix ) );
+        }
+        else
+        {
+            fMatch = ( 0 == wcsncmp( pwszString + ixOffset, pwszSuffix, cchSuffix ) );
+        }
+
+    #endif
+
+Finished:
+
+    return fMatch;
+}
+
+/*++
+
+Routine Description:
+
+    Searches the string for the first occurrence of the specified character.
+
+Arguments:
+
+    charValue       - character to find
+    dwStartIndex    - the initial index.
+
+Return Value:
+
+    The index for the first character occurence in the string.
+
+    -1 if not found.
+
+--*/
+INT
+STRU::IndexOf(
+    __in WCHAR          charValue,
+    __in DWORD          dwStartIndex
+    ) const
+{
+    INT nIndex = -1;
+
+    // Make sure that there are no buffer overruns.
+    if( dwStartIndex >= QueryCCH() )
+    {
+        goto Finished;
+    }
+
+    const WCHAR* pwChar = wcschr( QueryStr() + dwStartIndex, charValue );
+
+    // Determine the index if found
+    if( pwChar )
+    {
+        // nIndex will be set to -1 on failure.
+        (VOID)SizeTToInt( pwChar - QueryStr(), &nIndex );
+    }
+
+Finished:
+
+    return nIndex;
+}
+
+
+/*++
+
+Routine Description:
+
+    Searches the string for the first occurrence of the specified substring.
+
+Arguments:
+
+    pwszValue       - substring to find
+    dwStartIndex    - initial index.
+
+Return Value:
+
+    The index for the first character occurence in the string.
+
+    -1 if not found.
+
+--*/
+INT
+STRU::IndexOf(
+    __in PCWSTR         pwszValue,
+    __in DWORD          dwStartIndex
+    ) const
+{
+    HRESULT hr = S_OK;
+    INT nIndex = -1;
+    SIZE_T cchValue = 0;
+
+    // Validate input parameters
+    if( dwStartIndex >= QueryCCH() || !pwszValue )
+    {
+        goto Finished;
+    }
+
+    const WCHAR* pwChar = wcsstr( QueryStr() + dwStartIndex, pwszValue );
+
+    // Determine the index if found
+    if( pwChar )
+    {
+        // nIndex will be set to -1 on failure.
+        (VOID)SizeTToInt( pwChar - QueryStr(), &nIndex );
+    }
+
+Finished:
+
+    return nIndex;
+}
+
+
+/*++
+
+Routine Description:
+
+    Searches the string for the last occurrence of the specified character.
+
+Arguments:
+
+    charValue       - character to find
+    dwStartIndex    - initial index.
+
+Return Value:
+
+    The index for the last character occurence in the string.
+
+    -1 if not found.
+
+--*/
+INT
+STRU::LastIndexOf(
+    __in WCHAR          charValue,
+    __in DWORD          dwStartIndex
+    ) const
+{
+    INT nIndex = -1;
+
+    // Make sure that there are no buffer overruns.
+    if( dwStartIndex >= QueryCCH() )
+    {
+        goto Finished;
+    }
+
+    const WCHAR* pwChar = wcsrchr( QueryStr() + dwStartIndex, charValue );
+
+    // Determine the index if found
+    if( pwChar )
+    {
+        // nIndex will be set to -1 on failure.
+        (VOID)SizeTToInt( pwChar - QueryStr(), &nIndex );
+    }
+
+Finished:
+
+    return nIndex;
+}
+
+//static
+HRESULT
+STRU::ExpandEnvironmentVariables(
+    __in  PCWSTR                  pszString,
+    __out STRU *                  pstrExpandedString
+    )
+/*++
+
+Routine Description:
+
+    Expand the environment variables in a string
+
+Arguments:
+
+    pszString - String with environment variables to expand
+    pstrExpandedString - Receives expanded string on success
+
+Return Value:
+
+    HRESULT
+
+--*/
+{
+    HRESULT                 hr              = S_OK;
+    DWORD                   cchNewSize      = 0;
+
+    if ( pszString == NULL ||
+         pstrExpandedString == NULL )
+    {
+        DBG_ASSERT( FALSE );
+        hr = HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
+        goto Exit;
+    }
+
+    cchNewSize = ExpandEnvironmentStrings( pszString,
+                                           pstrExpandedString->QueryStr(),
+                                           pstrExpandedString->QuerySizeCCH() );
+    if ( cchNewSize == 0 )
+    {
+        hr = HRESULT_FROM_WIN32( GetLastError() );
+        goto Exit;
+    }
+
+    if ( cchNewSize > pstrExpandedString->QuerySizeCCH() )
+    {
+        hr = pstrExpandedString->Resize(
+            ( cchNewSize + 1 ) * sizeof( WCHAR )
+            );
+        if ( FAILED( hr ) )
+        {
+            goto Exit;
+        }
+
+        cchNewSize = ExpandEnvironmentStrings(
+            pszString,
+            pstrExpandedString->QueryStr(),
+            pstrExpandedString->QuerySizeCCH()
+            );
+
+        if ( cchNewSize == 0 ||
+             cchNewSize > pstrExpandedString->QuerySizeCCH() )
+        {
+            hr = HRESULT_FROM_WIN32( GetLastError() );
+            goto Exit;
+        }
+    }
+
+    pstrExpandedString->SyncWithBuffer();
+
+    hr = S_OK;
+
+Exit:
+
+    return hr;
+}
+
+#pragma warning(default:4267)
diff --git a/src/IISIntegration/src/AspNetCoreModuleV1/IISLib/stringu.h b/src/IISIntegration/src/AspNetCoreModuleV1/IISLib/stringu.h
new file mode 100644
index 0000000000000000000000000000000000000000..6f27c5421dc5b72bdc70ea434d51e86d1f8620b7
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV1/IISLib/stringu.h
@@ -0,0 +1,427 @@
+// 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 "buffer.h"
+#include <strsafe.h>
+
+class STRU
+{
+
+public:
+
+    STRU(
+        VOID
+    );
+
+    STRU(
+        __inout_ecount(cchInit) WCHAR* pbInit,
+        __in DWORD cchInit
+    );
+
+    BOOL
+    IsEmpty(
+        VOID
+    ) const;
+
+    BOOL
+    Equals(
+        __in const STRU *  pstrRhs,
+        __in BOOL           fIgnoreCase = FALSE
+    ) const
+    {
+        _ASSERTE( pstrRhs != NULL );
+        return Equals( pstrRhs->QueryStr(), fIgnoreCase );
+    }
+
+    BOOL
+    Equals(
+        __in const STRU &  strRhs,
+        __in BOOL           fIgnoreCase = FALSE
+    ) const
+    {
+        return Equals( strRhs.QueryStr(), fIgnoreCase );
+    }
+
+    BOOL
+    Equals(
+        __in PCWSTR pszRhs,
+        __in BOOL   fIgnoreCase = FALSE
+    ) const
+    {
+        _ASSERTE( NULL != pszRhs );
+        if ( NULL == pszRhs )
+        {
+            return FALSE;
+        }
+
+    #if defined( NTDDI_VERSION ) && NTDDI_VERSION >= NTDDI_LONGHORN
+
+        return ( CSTR_EQUAL == CompareStringOrdinal( QueryStr(),
+                                                     QueryCCH(),
+                                                     pszRhs,
+                                                     -1,
+                                                     fIgnoreCase ) );
+    #else
+
+        if( fIgnoreCase )
+        {
+            return ( 0 == _wcsicmp( QueryStr(), pszRhs ) );
+        }
+        return ( 0 == wcscmp( QueryStr(), pszRhs ) );
+
+    #endif
+    }
+
+
+    static
+    BOOL
+    Equals(
+        __in PCWSTR pwszLhs,
+        __in PCWSTR pwszRhs,
+        __in bool   fIgnoreCase = false
+    )
+    {
+        // Return FALSE if either or both strings are NULL.
+        if (!pwszLhs || !pwszRhs) return FALSE;
+
+    //
+    // This method performs a ordinal string comparison when OS is Vista or
+    // greater and a culture sensitive comparison if not (XP). This is
+    // consistent with the existing Equals implementation (see above).
+    //
+#if defined( NTDDI_VERSION ) && NTDDI_VERSION >= NTDDI_LONGHORN
+
+        return ( CSTR_EQUAL == CompareStringOrdinal( pwszLhs,
+                                                     -1,
+                                                     pwszRhs,
+                                                     -1,
+                                                     fIgnoreCase ) );
+#else
+
+        if( fIgnoreCase )
+        {
+            return ( 0 == _wcsicmp( pwszLhs, pwszRhs ) );
+        }
+        else
+        {
+            return ( 0 == wcscmp( pwszLhs, pwszRhs ) );
+        }
+
+#endif
+    }
+
+    VOID
+    Trim();
+
+    BOOL
+    StartsWith(
+        __in const STRU *   pStruPrefix,
+        __in bool           fIgnoreCase = FALSE
+    ) const
+    {
+        _ASSERTE( pStruPrefix != NULL );
+        return StartsWith( pStruPrefix->QueryStr(), fIgnoreCase );
+    }
+
+    BOOL
+    StartsWith(
+        __in const STRU &   struPrefix,
+        __in bool           fIgnoreCase = FALSE
+    ) const
+    {
+        return StartsWith( struPrefix.QueryStr(), fIgnoreCase );
+    }
+
+    BOOL
+    StartsWith(
+        __in PCWSTR         pwszPrefix,
+        __in bool           fIgnoreCase = FALSE
+    ) const;
+
+    BOOL
+    EndsWith(
+        __in const STRU *   pStruSuffix,
+        __in bool           fIgnoreCase = FALSE
+    ) const
+    {
+        _ASSERTE( pStruSuffix != NULL );
+        return EndsWith( pStruSuffix->QueryStr(), fIgnoreCase );
+    }
+
+    BOOL
+    EndsWith(
+        __in const STRU &   struSuffix,
+        __in bool           fIgnoreCase = FALSE
+    ) const
+    {
+        return EndsWith( struSuffix.QueryStr(), fIgnoreCase );
+    }
+
+    BOOL
+    EndsWith(
+        __in PCWSTR         pwszSuffix,
+        __in bool           fIgnoreCase = FALSE
+    ) const;
+
+    INT
+    IndexOf(
+        __in WCHAR          charValue,
+        __in DWORD          dwStartIndex = 0
+    ) const;
+
+    INT
+    IndexOf(
+        __in PCWSTR         pwszValue,
+        __in DWORD          dwStartIndex = 0
+    ) const;
+
+    INT
+    LastIndexOf(
+        __in WCHAR          charValue,
+        __in DWORD          dwStartIndex = 0
+    ) const;
+
+    DWORD
+    QueryCB(
+        VOID
+    ) const;
+
+    DWORD
+    QueryCCH(
+        VOID
+    ) const;
+
+    DWORD
+    QuerySizeCCH(
+        VOID
+    ) const;
+
+    __nullterminated
+    __ecount(this->m_cchLen)
+    WCHAR*
+    QueryStr(
+        VOID
+    ) const;
+
+    VOID
+    Reset(
+        VOID
+    );
+
+    HRESULT
+    Resize(
+        DWORD cchSize
+    );
+
+    HRESULT
+    SyncWithBuffer(
+        VOID
+    );
+
+    template<size_t size>
+    HRESULT
+    Copy(
+        __in PCWSTR const (&rgpszStrings)[size]
+    )
+    //
+    // Copies an array of strings declared as stack array. For example:
+    //
+    // LPCWSTR rgExample[] { L"one", L"two" };
+    // hr = str.Copy( rgExample );
+    //
+    {
+        Reset();
+
+        return AuxAppend( rgpszStrings, _countof( rgpszStrings ) );
+    }
+
+    HRESULT
+    Copy(
+        __in PCWSTR pszCopy
+    );
+
+    HRESULT
+    Copy(
+        __in_ecount(cchLen)
+        PCWSTR  pszCopy,
+        SIZE_T  cchLen
+    );
+
+    HRESULT
+    Copy(
+        __in const STRU * pstrRhs
+    );
+
+    HRESULT
+    Copy(
+        __in const STRU & str
+    );
+
+    HRESULT
+    CopyAndExpandEnvironmentStrings(
+        __in PCWSTR     pszSource
+    );
+
+    HRESULT
+    CopyA(
+        __in PCSTR  pszCopyA
+    );
+
+    HRESULT
+    CopyA(
+        __in_bcount(cchLen)
+        PCSTR   pszCopyA,
+        SIZE_T  cchLen,
+        UINT    CodePage = CP_UTF8
+    );
+
+    template<size_t size>
+    HRESULT
+    Append(
+        __in PCWSTR const (&rgpszStrings)[size]
+    )
+    //
+    // Appends an array of strings declared as stack array. For example:
+    //
+    // LPCWSTR rgExample[] { L"one", L"two" };
+    // hr = str.Append( rgExample );
+    //
+    {
+        return AuxAppend( rgpszStrings, _countof( rgpszStrings ) );
+    }
+
+    HRESULT
+    Append(
+        __in PCWSTR  pszAppend
+    );
+
+    HRESULT
+    Append(
+        __in_ecount(cchLen)
+        PCWSTR  pszAppend,
+        SIZE_T  cchLen
+    );
+
+    HRESULT
+    Append(
+        __in const STRU * pstrRhs
+    );
+
+    HRESULT
+    Append(
+        __in const STRU & strRhs
+    );
+
+    HRESULT
+    AppendA(
+        __in PCSTR  pszAppendA
+    );
+
+    HRESULT
+    AppendA(
+        __in_bcount(cchLen)
+        PCSTR   pszAppendA,
+        SIZE_T  cchLen,
+        UINT    CodePage = CP_UTF8
+    );
+
+    HRESULT
+    CopyToBuffer(
+        __out_bcount(*pcb) WCHAR*   pszBuffer,
+        PDWORD                      pcb
+    ) const;
+
+    HRESULT
+    SetLen(
+        __in DWORD cchLen
+    );
+
+    HRESULT
+    SafeSnwprintf(
+        __in PCWSTR pwszFormatString,
+        ...
+    );
+
+    HRESULT
+    SafeVsnwprintf(
+        __in PCWSTR pwszFormatString,
+        va_list     argsList
+    );
+
+    static
+    HRESULT  ExpandEnvironmentVariables(
+        __in PCWSTR                  pszString,
+        __out STRU *                 pstrExpandedString
+    );
+
+private:
+
+    //
+    // Avoid C++ errors. This object should never go through a copy
+    // constructor, unintended cast or assignment.
+    //
+    STRU( const STRU & );
+    STRU & operator = ( const STRU & );
+
+    HRESULT
+    AuxAppend(
+        __in_ecount(cNumStrings)
+        PCWSTR const    rgpszStrings[],
+        SIZE_T          cNumStrings
+    );
+
+    HRESULT
+    AuxAppend(
+        __in_bcount(cbStr)
+        const WCHAR*    pStr,
+        SIZE_T          cbStr,
+        DWORD           cbOffset
+    );
+
+    HRESULT
+    AuxAppendA(
+        __in_bcount(cbStr)
+        const CHAR*     pStr,
+        SIZE_T          cbStr,
+        DWORD           cbOffset,
+        UINT            CodePage
+    );
+
+    //
+    // Buffer with an inline buffer of 1,
+    // enough to hold null-terminating character.
+    //
+    BUFFER_T<WCHAR,1>   m_Buff;
+    DWORD               m_cchLen;
+};
+
+//
+// Helps to initialize an external buffer before
+// constructing the STRU object.
+//
+template<DWORD size>
+WCHAR* InitHelper(__out WCHAR (&psz)[size])
+{
+    psz[0] = L'\0';
+    return psz;
+}
+
+//
+// Heap operation reduction macros
+//
+#define STACK_STRU(name, size)  WCHAR __ach##name[size];\
+                                STRU name(InitHelper(__ach##name), sizeof(__ach##name)/sizeof(*__ach##name))
+
+#define INLINE_STRU(name, size) WCHAR  __ach##name[size];\
+                                STRU  name;
+
+#define INLINE_STRU_INIT(name) name(InitHelper(__ach##name), sizeof(__ach##name)/sizeof(*__ach##name))
+
+
+HRESULT
+MakePathCanonicalizationProof(
+    IN PCWSTR               pszName,
+    OUT STRU *              pstrPath
+);
diff --git a/src/IISIntegration/src/AspNetCoreModuleV1/IISLib/tracelog.c b/src/IISIntegration/src/AspNetCoreModuleV1/IISLib/tracelog.c
new file mode 100644
index 0000000000000000000000000000000000000000..f7b2da5e43574214d09916042f79f483e462e5a3
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV1/IISLib/tracelog.c
@@ -0,0 +1,235 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#include <windows.h>
+#include "pudebug.h"
+#include "tracelog.h"
+#include <intsafe.h>
+
+
+#define ALLOC_MEM(cb) (PVOID)LocalAlloc( LPTR, (cb) )
+#define FREE_MEM(ptr) (VOID)LocalFree( (HLOCAL)(ptr) )
+
+
+
+PTRACE_LOG
+CreateTraceLog(
+    IN LONG LogSize,
+    IN LONG ExtraBytesInHeader,
+    IN LONG EntrySize
+    )
+/*++
+
+Routine Description:
+
+    Creates a new (empty) trace log buffer.
+
+Arguments:
+
+    LogSize - The number of entries in the log.
+
+    ExtraBytesInHeader - The number of extra bytes to include in the
+        log header. This is useful for adding application-specific
+        data to the log.
+
+    EntrySize - The size (in bytes) of each entry.
+
+Return Value:
+
+    PTRACE_LOG - Pointer to the newly created log if successful,
+        NULL otherwise.
+
+--*/
+{
+
+    ULONG ulTotalSize = 0;
+    ULONG ulLogSize = 0;
+    ULONG ulEntrySize = 0;
+    ULONG ulTmpResult = 0;
+    ULONG ulExtraBytesInHeader = 0;
+    PTRACE_LOG log = NULL;
+    HRESULT hr = S_OK;
+
+    //
+    // Sanity check the parameters.
+    //
+
+    //DBG_ASSERT( LogSize > 0 );
+    //DBG_ASSERT( EntrySize > 0 );
+    //DBG_ASSERT( ExtraBytesInHeader >= 0 );
+    //DBG_ASSERT( ( EntrySize & 3 ) == 0 );
+
+    //
+    // converting to unsigned long. Since all these values are positive
+    // so its safe to cast them to their unsigned equivalent directly.
+    //
+    ulLogSize            = (ULONG) LogSize;
+    ulEntrySize          = (ULONG) EntrySize;
+    ulExtraBytesInHeader = (ULONG) ExtraBytesInHeader;
+
+    //
+    // Check if the multiplication operation will overflow a LONG 
+    // ulTotalSize = LogSize * EntrySize;
+    //
+    hr = ULongMult( ulLogSize, ulEntrySize, &ulTotalSize );
+    if ( FAILED(hr) )
+    { 
+        SetLastError( ERROR_ARITHMETIC_OVERFLOW );
+        return NULL;
+    }
+
+    //
+    // check for overflow in addition operation.
+    // ulTmpResult = sizeof(TRACE_LOG) + ulExtraBytesInHeader
+    //
+    hr = ULongAdd( (ULONG) sizeof(TRACE_LOG), ulExtraBytesInHeader, &ulTmpResult );
+    if ( FAILED(hr) )
+    { 
+        SetLastError( ERROR_ARITHMETIC_OVERFLOW );
+        return NULL;
+    }
+  
+    //
+    // check for overflow in addition operation.
+    // ulTotalSize = ulTotalSize + ulTmpResult;
+    //
+    hr = ULongAdd( ulTmpResult, ulTotalSize, &ulTotalSize );
+    if ( FAILED(hr) )
+    { 
+        SetLastError( ERROR_ARITHMETIC_OVERFLOW );
+        return NULL;
+    }
+
+    if ( ulTotalSize > (ULONG) 0x7FFFFFFF )
+    { 
+        SetLastError( ERROR_ARITHMETIC_OVERFLOW );
+        return NULL;
+    }
+
+    //
+    // Allocate & initialize the log structure.
+    //
+
+    log = (PTRACE_LOG)ALLOC_MEM( ulTotalSize );
+
+    //
+    // Initialize it.
+    //
+
+    if( log != NULL ) {
+
+        RtlZeroMemory( log, ulTotalSize );
+
+        log->Signature = TRACE_LOG_SIGNATURE;
+        log->LogSize = LogSize;
+        log->NextEntry = -1;
+        log->EntrySize = EntrySize;
+        log->LogBuffer = (PUCHAR)( log + 1 ) + ExtraBytesInHeader;
+    }
+
+    return log;
+
+}   // CreateTraceLog
+
+
+VOID
+DestroyTraceLog(
+    IN PTRACE_LOG Log
+    )
+/*++
+
+Routine Description:
+
+    Destroys a trace log buffer created with CreateTraceLog().
+
+Arguments:
+
+    Log - The trace log buffer to destroy.
+
+Return Value:
+
+    None.
+
+--*/
+{
+        if ( Log != NULL ) {
+        //DBG_ASSERT( Log->Signature == TRACE_LOG_SIGNATURE );
+
+        Log->Signature = TRACE_LOG_SIGNATURE_X;
+        FREE_MEM( Log );
+    }
+
+}   // DestroyTraceLog
+
+
+LONG
+WriteTraceLog(
+    IN PTRACE_LOG Log,
+    IN PVOID Entry
+    )
+/*++
+
+Routine Description:
+
+    Writes a new entry to the specified trace log.
+
+Arguments:
+
+    Log - The log to write to.
+
+    Entry - Pointer to the data to write. This buffer is assumed to be
+        Log->EntrySize bytes long.
+
+Return Value:
+
+    Index of entry in log.  This is useful for correlating the output
+    of !inetdbg.ref to a particular point in the output debug stream
+
+--*/
+{
+
+    PUCHAR target;
+    ULONG index;
+
+    //DBG_ASSERT( Log != NULL );
+    //DBG_ASSERT( Log->Signature == TRACE_LOG_SIGNATURE );
+    //DBG_ASSERT( Entry != NULL );
+
+    //
+    // Find the next slot, copy the entry to the slot.
+    //
+
+    index = ( (ULONG) InterlockedIncrement( &Log->NextEntry ) ) % (ULONG) Log->LogSize;
+
+    //DBG_ASSERT( index < (ULONG) Log->LogSize );
+
+    target = Log->LogBuffer + ( index * Log->EntrySize );
+
+    RtlCopyMemory(
+        target,
+        Entry,
+        Log->EntrySize
+        );
+
+    return index;
+}   // WriteTraceLog
+
+
+VOID
+ResetTraceLog(
+    IN PTRACE_LOG Log
+    )
+{
+
+    //DBG_ASSERT( Log != NULL );
+    //DBG_ASSERT( Log->Signature == TRACE_LOG_SIGNATURE );
+
+    RtlZeroMemory(
+        ( Log + 1 ),
+        Log->LogSize * Log->EntrySize
+        );
+
+    Log->NextEntry = -1;
+
+}   // ResetTraceLog
+
diff --git a/src/IISIntegration/src/AspNetCoreModuleV1/IISLib/tracelog.h b/src/IISIntegration/src/AspNetCoreModuleV1/IISLib/tracelog.h
new file mode 100644
index 0000000000000000000000000000000000000000..ed34bcffc90b52ca8bf464f8fdfd248ebb83554d
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV1/IISLib/tracelog.h
@@ -0,0 +1,105 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#ifndef _TRACELOG_H_
+#define _TRACELOG_H_
+
+
+#if defined(__cplusplus)
+extern "C" {
+#endif  // __cplusplus
+
+
+typedef struct _TRACE_LOG {
+
+    //
+    // Signature.
+    //
+
+    LONG Signature;
+
+    //
+    // The total number of entries available in the log.
+    //
+
+    LONG LogSize;
+
+    //
+    // The index of the next entry to use.
+    //
+
+    LONG NextEntry;
+
+    //
+    // The byte size of each entry.
+    //
+
+    LONG EntrySize;
+
+    //
+    // Pointer to the start of the circular buffer.
+    //
+
+    PUCHAR LogBuffer;
+
+    //
+    // The extra header bytes and actual log entries go here.
+    //
+    // BYTE ExtraHeaderBytes[ExtraBytesInHeader];
+    // BYTE Entries[LogSize][EntrySize];
+    //
+
+} TRACE_LOG, *PTRACE_LOG;
+
+
+//
+// Log header signature.
+//
+
+#define TRACE_LOG_SIGNATURE   ((DWORD)'gOlT')
+#define TRACE_LOG_SIGNATURE_X ((DWORD)'golX')
+
+
+//
+// This macro maps a TRACE_LOG pointer to a pointer to the 'extra'
+// data associated with the log.
+//
+
+#define TRACE_LOG_TO_EXTRA_DATA(log)    (PVOID)( (log) + 1 )
+
+
+//
+// Manipulators.
+//
+
+PTRACE_LOG
+CreateTraceLog(
+    IN LONG LogSize,
+    IN LONG ExtraBytesInHeader,
+    IN LONG EntrySize
+    );
+
+VOID
+DestroyTraceLog(
+    IN PTRACE_LOG Log
+    );
+
+LONG
+WriteTraceLog(
+    IN PTRACE_LOG Log,
+    IN PVOID Entry
+    );
+
+VOID
+ResetTraceLog(
+    IN PTRACE_LOG Log
+    );
+
+
+#if defined(__cplusplus)
+}   // extern "C"
+#endif  // __cplusplus
+
+
+#endif  // _TRACELOG_H_
+
diff --git a/src/IISIntegration/src/AspNetCoreModuleV1/IISLib/treehash.h b/src/IISIntegration/src/AspNetCoreModuleV1/IISLib/treehash.h
new file mode 100644
index 0000000000000000000000000000000000000000..baa50726ce61d2cf3bd5fee79da78d583cc86bc6
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV1/IISLib/treehash.h
@@ -0,0 +1,850 @@
+// 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 <crtdbg.h>
+#include "rwlock.h"
+#include "prime.h"
+
+template <class _Record>
+class TREE_HASH_NODE
+{
+    template <class _Record>
+    friend class TREE_HASH_TABLE;
+
+ private:
+    // Next node in the hash table look-aside
+    TREE_HASH_NODE<_Record> *_pNext;
+
+    // links in the tree structure
+    TREE_HASH_NODE *    _pParentNode;
+    TREE_HASH_NODE *    _pFirstChild;
+    TREE_HASH_NODE *    _pNextSibling;
+
+    // actual record
+    _Record *           _pRecord;
+
+    // hash value
+    PCWSTR              _pszPath;
+    DWORD               _dwHash;
+};
+
+template <class _Record>
+class TREE_HASH_TABLE
+{
+protected:
+    typedef BOOL
+    (PFN_DELETE_IF)(
+        _Record *           pRecord,
+        PVOID               pvContext
+    );
+
+    typedef VOID
+    (PFN_APPLY)(
+        _Record *           pRecord,
+        PVOID               pvContext
+    );
+
+public:
+    TREE_HASH_TABLE(
+        BOOL    fCaseSensitive
+    ) : _ppBuckets( NULL ),
+        _nBuckets( 0 ),
+        _nItems( 0 ),
+        _fCaseSensitive( fCaseSensitive )
+    {
+    }
+
+    virtual
+    ~TREE_HASH_TABLE();
+
+    virtual
+    VOID
+    ReferenceRecord(
+        _Record *   pRecord
+    ) = 0;
+
+    virtual
+    VOID
+    DereferenceRecord(
+        _Record *   pRecord
+    ) = 0;
+
+    virtual
+    PCWSTR
+    GetKey(
+        _Record *   pRecord
+    ) = 0;
+
+    DWORD
+    Count()
+    {
+        return _nItems;
+    }
+
+    virtual
+    VOID
+    Clear();
+
+    HRESULT
+    Initialize(
+        DWORD           nBucketSize
+    );
+
+    DWORD
+    CalcHash(
+        PCWSTR      pszKey
+    )
+    {
+        return _fCaseSensitive ? HashString(pszKey) : HashStringNoCase(pszKey);
+    }
+
+    virtual
+    VOID
+    FindKey(
+        PCWSTR      pszKey,
+        _Record **  ppRecord
+    );
+
+    virtual
+    HRESULT
+    InsertRecord(
+        _Record *   pRecord
+    );
+
+    virtual
+    VOID
+    DeleteKey(
+        PCWSTR      pszKey
+    );
+
+    virtual
+    VOID
+    DeleteIf(
+        PFN_DELETE_IF       pfnDeleteIf,
+        PVOID               pvContext
+    );
+
+    VOID
+    Apply(
+        PFN_APPLY           pfnApply,
+        PVOID               pvContext
+    );
+
+private:
+
+    BOOL
+    FindNodeInternal(
+        PCWSTR                      pszKey,
+        DWORD                       dwHash,
+        TREE_HASH_NODE<_Record> **  ppNode,
+        TREE_HASH_NODE<_Record> *** pppPreviousNodeNextPointer = NULL
+    );
+
+    HRESULT
+    AddNodeInternal(
+        PCWSTR                      pszPath,
+        DWORD                       dwHash,
+        _Record *                   pRecord,
+        TREE_HASH_NODE<_Record> *   pParentNode,
+        TREE_HASH_NODE<_Record> **  ppNewNode
+    );
+
+    HRESULT
+    AllocateNode(
+        PCWSTR                      pszPath,
+        DWORD                       dwHash,
+        _Record *                   pRecord,
+        TREE_HASH_NODE<_Record> *   pParentNode,
+        TREE_HASH_NODE<_Record> **  ppNewNode
+    );
+
+    VOID
+    DeleteNode(
+        TREE_HASH_NODE<_Record> *   pNode
+    )
+    {
+        if (pNode->_pRecord != NULL)
+        {
+            DereferenceRecord(pNode->_pRecord);
+            pNode->_pRecord = NULL;
+        }
+
+        HeapFree(GetProcessHeap(),
+                 0,
+                 pNode);
+    }
+
+    VOID
+    DeleteNodeInternal(
+        TREE_HASH_NODE<_Record> **  ppPreviousNodeNextPointer,
+        TREE_HASH_NODE<_Record> *   pNode
+    );
+
+    VOID
+    RehashTableIfNeeded(
+        VOID
+    );
+
+    TREE_HASH_NODE<_Record> **  _ppBuckets;
+    DWORD                       _nBuckets;
+    DWORD                       _nItems;
+    BOOL                        _fCaseSensitive;
+    CWSDRWLock                  _tableLock;
+};
+
+template <class _Record>
+HRESULT
+TREE_HASH_TABLE<_Record>::AllocateNode(
+    PCWSTR                      pszPath,
+    DWORD                       dwHash,
+    _Record *                   pRecord,
+    TREE_HASH_NODE<_Record> *   pParentNode,
+    TREE_HASH_NODE<_Record> **  ppNewNode
+)
+{
+    //
+    // Allocate enough extra space for pszPath
+    //
+    DWORD cchPath = (DWORD) wcslen(pszPath);
+    if (cchPath >= ((0xffffffff - sizeof(TREE_HASH_NODE<_Record>))/sizeof(WCHAR) - 1))
+    {
+        return HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
+    }
+    TREE_HASH_NODE<_Record> *pNode = (TREE_HASH_NODE<_Record> *)HeapAlloc(
+            GetProcessHeap(),
+            HEAP_ZERO_MEMORY,
+            sizeof(TREE_HASH_NODE<_Record>) + (cchPath+1)*sizeof(WCHAR));
+    if (pNode == NULL)
+    {
+        return HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
+    }
+
+    memcpy(pNode+1, pszPath, (cchPath+1)*sizeof(WCHAR));
+    pNode->_pszPath = (PCWSTR)(pNode+1);
+    pNode->_dwHash = dwHash;
+    pNode->_pNext = pNode->_pNextSibling = pNode->_pFirstChild = NULL;
+    pNode->_pParentNode = pParentNode;
+    pNode->_pRecord = pRecord;
+
+    *ppNewNode = pNode;
+    return S_OK;
+}
+
+template <class _Record>
+HRESULT
+TREE_HASH_TABLE<_Record>::Initialize(
+    DWORD   nBuckets
+)
+{
+    HRESULT hr = S_OK;
+
+    if ( nBuckets == 0 )
+    {
+        hr = E_INVALIDARG;
+        goto Failed;
+    }
+
+    hr = _tableLock.Init();
+    if ( FAILED( hr ) )
+    {
+        goto Failed;
+    }
+
+    if (nBuckets >= 0xffffffff/sizeof(TREE_HASH_NODE<_Record> *))
+    {
+        hr = E_INVALIDARG;
+        goto Failed;
+    }
+
+    _ppBuckets = (TREE_HASH_NODE<_Record> **)HeapAlloc(
+                            GetProcessHeap(),
+                            HEAP_ZERO_MEMORY,
+                            nBuckets*sizeof(TREE_HASH_NODE<_Record> *));
+    if (_ppBuckets == NULL)
+    {
+        hr = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
+        goto Failed;
+    }
+    _nBuckets = nBuckets;
+
+    return S_OK;
+
+Failed:
+
+    if (_ppBuckets)
+    {
+        HeapFree(GetProcessHeap(),
+                 0,
+                 _ppBuckets);
+        _ppBuckets = NULL;
+    }
+
+    return hr;
+}
+
+
+template <class _Record>
+TREE_HASH_TABLE<_Record>::~TREE_HASH_TABLE()
+{
+    if (_ppBuckets == NULL)
+    {
+        return;
+    }
+
+    _ASSERTE(_nItems == 0);
+
+    HeapFree(GetProcessHeap(),
+             0,
+             _ppBuckets);
+    _ppBuckets = NULL;
+    _nBuckets = 0;
+}
+
+template <class _Record>
+VOID
+TREE_HASH_TABLE<_Record>::Clear()
+{
+    TREE_HASH_NODE<_Record> *pCurrent;
+    TREE_HASH_NODE<_Record> *pNext;
+
+    _tableLock.ExclusiveAcquire();
+
+    for (DWORD i=0; i<_nBuckets; i++)
+    {
+        pCurrent = _ppBuckets[i];
+        _ppBuckets[i] = NULL;
+        while (pCurrent != NULL)
+        {
+            pNext = pCurrent->_pNext;
+            DeleteNode(pCurrent);
+            pCurrent = pNext;
+        }
+    }
+
+    _nItems = 0;
+    _tableLock.ExclusiveRelease();
+}
+
+template <class _Record>
+BOOL
+TREE_HASH_TABLE<_Record>::FindNodeInternal(
+    PCWSTR                  pszKey,
+    DWORD                   dwHash,
+    TREE_HASH_NODE<_Record> **   ppNode,
+    TREE_HASH_NODE<_Record> ***  pppPreviousNodeNextPointer
+)
+/*++
+  Return value indicates whether the item is found
+  key, dwHash - key and hash for the node to find
+  ppNode - on successful return, the node found, on failed return, the first
+  node with hash value greater than the node to be found
+  pppPreviousNodeNextPointer - the pointer to previous node's _pNext
+
+  This routine may be called under either read or write lock
+--*/
+{
+    TREE_HASH_NODE<_Record> **ppPreviousNodeNextPointer;
+    TREE_HASH_NODE<_Record> *pNode;
+    BOOL fFound = FALSE;
+
+    ppPreviousNodeNextPointer = _ppBuckets + (dwHash % _nBuckets);
+    pNode = *ppPreviousNodeNextPointer;
+    while (pNode != NULL)
+    {
+        if (pNode->_dwHash == dwHash)
+        {
+            if (CompareStringOrdinal(pszKey,
+                                     -1,
+                                     pNode->_pszPath,
+                                     -1,
+                                     !_fCaseSensitive) == CSTR_EQUAL)
+            {
+                fFound = TRUE;
+                break;
+            }
+        }
+        else if (pNode->_dwHash > dwHash)
+        {
+            break;
+        }
+
+        ppPreviousNodeNextPointer = &(pNode->_pNext);
+        pNode = *ppPreviousNodeNextPointer;
+    }
+
+    *ppNode = pNode;
+    if (pppPreviousNodeNextPointer != NULL)
+    {
+        *pppPreviousNodeNextPointer = ppPreviousNodeNextPointer;
+    }
+    return fFound;
+}
+
+template <class _Record>
+VOID
+TREE_HASH_TABLE<_Record>::FindKey(
+    PCWSTR              pszKey,
+    _Record **          ppRecord
+)
+{
+    TREE_HASH_NODE<_Record> *pNode;
+
+    *ppRecord = NULL;
+
+    DWORD dwHash = CalcHash(pszKey);
+
+    _tableLock.SharedAcquire();
+
+    if (FindNodeInternal(pszKey, dwHash, &pNode) &&
+        pNode->_pRecord != NULL)
+    {
+        ReferenceRecord(pNode->_pRecord);
+        *ppRecord = pNode->_pRecord;
+    }
+
+    _tableLock.SharedRelease();
+}
+
+template <class _Record>
+HRESULT
+TREE_HASH_TABLE<_Record>::AddNodeInternal(
+    PCWSTR                      pszPath,
+    DWORD                       dwHash,
+    _Record *                   pRecord,
+    TREE_HASH_NODE<_Record> *   pParentNode,
+    TREE_HASH_NODE<_Record> **  ppNewNode
+)
+/*++
+  Return value is HRESULT indicating sucess or failure
+  pszPath, dwHash, pRecord - path, hash value and record to be inserted
+  pParentNode - this will be the parent of the node being inserted
+  ppNewNode - on successful return, the new node created and inserted
+
+  This function may be called under a read or write lock
+--*/
+{
+    TREE_HASH_NODE<_Record> *pNewNode;
+    TREE_HASH_NODE<_Record> *pNextNode;
+    TREE_HASH_NODE<_Record> **ppNextPointer;
+    HRESULT hr;
+
+    //
+    // Ownership of pRecord is not transferred to pNewNode yet, so remember
+    // to either set it to null before deleting pNewNode or add an extra
+    // reference later - this is to make sure we do not do an extra ref/deref
+    // which users may view as getting flushed out of the hash-table
+    //
+    hr = AllocateNode(pszPath,
+                      dwHash,
+                      pRecord,
+                      pParentNode,
+                      &pNewNode);
+    if (FAILED(hr))
+    {
+        return hr;
+    }
+
+    do
+    {
+        //
+        // Find the right place to add this node
+        //
+
+        if (FindNodeInternal(pszPath, dwHash, &pNextNode, &ppNextPointer))
+        {
+            //
+            // If node already there, record may still need updating
+            //
+            if (pRecord != NULL &&
+                InterlockedCompareExchangePointer((PVOID *)&pNextNode->_pRecord,
+                                                  pRecord,
+                                                  NULL) == NULL)
+            {
+                ReferenceRecord(pRecord);
+                hr = S_OK;
+            }
+            else
+            {
+                hr = HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS);
+            }
+
+            // ownership of pRecord has either passed to existing record or
+            // not to anyone at all
+            pNewNode->_pRecord = NULL;
+            DeleteNode(pNewNode);
+            *ppNewNode = pNextNode;
+            return hr;
+        }
+
+        //
+        // If another node got inserted in betwen, we will have to retry
+        //
+        pNewNode->_pNext = pNextNode;
+    } while (InterlockedCompareExchangePointer((PVOID *)ppNextPointer,
+                                               pNewNode,
+                                               pNextNode) != pNextNode);
+    // pass ownership of pRecord now
+    if (pRecord != NULL)
+    {
+        ReferenceRecord(pRecord);
+        pRecord = NULL;
+    }
+    InterlockedIncrement((LONG *)&_nItems);
+
+    //
+    // update the parent
+    //
+    if (pParentNode != NULL)
+    {
+        ppNextPointer = &pParentNode->_pFirstChild;
+        do
+        {
+            pNextNode = *ppNextPointer;
+            pNewNode->_pNextSibling = pNextNode;
+        } while (InterlockedCompareExchangePointer((PVOID *)ppNextPointer,
+                                                   pNewNode,
+                                                   pNextNode) != pNextNode);
+    }
+
+    *ppNewNode = pNewNode;
+    return S_OK;
+}
+
+template <class _Record>
+HRESULT
+TREE_HASH_TABLE<_Record>::InsertRecord(
+    _Record *           pRecord
+)
+/*++
+  This method inserts a node for this record and also empty nodes for paths
+  in the heirarchy leading upto this path
+
+  The insert is done under only a read-lock - this is possible by keeping
+  the hashes in a bucket in increasing order and using interlocked operations
+  to actually insert the item in the hash-bucket lookaside list and the parent
+  children list
+
+  Returns HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS) if the record already exists.
+  Never leak this error to the end user because "*file* already exists" may be confusing.
+--*/
+{
+    PCWSTR pszKey = GetKey(pRecord);
+    STACK_STRU( strPartialPath, 256);
+    PWSTR pszPartialPath;
+    DWORD dwHash;
+    DWORD cchEnd;
+    HRESULT hr;
+    TREE_HASH_NODE<_Record> *pParentNode = NULL;
+
+    hr = strPartialPath.Copy(pszKey);
+    if (FAILED(hr))
+    {
+        goto Finished;
+    }
+    pszPartialPath = strPartialPath.QueryStr();
+
+    _tableLock.SharedAcquire();
+
+    //
+    // First find the lowest parent node present
+    //
+    for (cchEnd = strPartialPath.QueryCCH() - 1; cchEnd > 0; cchEnd--)
+    {
+        if (pszPartialPath[cchEnd] == L'/' || pszPartialPath[cchEnd] == L'\\')
+        {
+            pszPartialPath[cchEnd] = L'\0';
+
+            dwHash = CalcHash(pszPartialPath);
+            if (FindNodeInternal(pszPartialPath, dwHash, &pParentNode))
+            {
+                pszPartialPath[cchEnd] = pszKey[cchEnd];
+                break;
+            }
+            pParentNode = NULL;
+        }
+    }
+
+    //
+    // Now go ahead and add the rest of the tree (including our record)
+    //
+    for (; cchEnd <= strPartialPath.QueryCCH(); cchEnd++)
+    {
+        if (pszPartialPath[cchEnd] == L'\0')
+        {
+            dwHash = CalcHash(pszPartialPath);
+            hr = AddNodeInternal(
+                    pszPartialPath,
+                    dwHash,
+                    (cchEnd == strPartialPath.QueryCCH()) ? pRecord : NULL,
+                    pParentNode,
+                    &pParentNode);
+            if (FAILED(hr) &&
+                hr != HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS))
+            {
+                goto Finished;
+            }
+
+            pszPartialPath[cchEnd] = pszKey[cchEnd];
+        }
+    }
+
+Finished:
+    _tableLock.SharedRelease();
+
+    if (SUCCEEDED(hr))
+    {
+        RehashTableIfNeeded();
+    }
+
+    return hr;
+}
+
+template <class _Record>
+VOID
+TREE_HASH_TABLE<_Record>::DeleteNodeInternal(
+    TREE_HASH_NODE<_Record> **  ppNextPointer,
+    TREE_HASH_NODE<_Record> *   pNode
+)
+/*++
+  pNode is the node to be deleted
+  ppNextPointer is the pointer to the previous node's next pointer pointing
+  to this node
+
+  This function should be called under write-lock
+--*/
+{
+    //
+    // First remove this node from hash table
+    //
+    *ppNextPointer = pNode->_pNext;
+
+    //
+    // Now fixup parent
+    //
+    if (pNode->_pParentNode != NULL)
+    {
+        ppNextPointer = &pNode->_pParentNode->_pFirstChild;
+        while (*ppNextPointer != pNode)
+        {
+            ppNextPointer = &(*ppNextPointer)->_pNextSibling;
+        }
+        *ppNextPointer = pNode->_pNextSibling;
+    }
+
+    //
+    // Now remove all children recursively
+    //
+    TREE_HASH_NODE<_Record> *pChild = pNode->_pFirstChild;
+    TREE_HASH_NODE<_Record> *pNextChild;
+    while (pChild != NULL)
+    {
+        pNextChild = pChild->_pNextSibling;
+
+        ppNextPointer = _ppBuckets + (pChild->_dwHash % _nBuckets);
+        while (*ppNextPointer != pChild)
+        {
+            ppNextPointer = &(*ppNextPointer)->_pNext;
+        }
+        pChild->_pParentNode = NULL;
+        DeleteNodeInternal(ppNextPointer, pChild);
+
+        pChild = pNextChild;
+    }
+
+    DeleteNode(pNode);
+    _nItems--;
+}
+
+template <class _Record>
+VOID
+TREE_HASH_TABLE<_Record>::DeleteKey(
+    PCWSTR      pszKey
+)
+{
+    TREE_HASH_NODE<_Record> *pNode;
+    TREE_HASH_NODE<_Record> **ppPreviousNodeNextPointer;
+
+    DWORD dwHash = CalcHash(pszKey);
+
+    _tableLock.ExclusiveAcquire();
+
+    if (FindNodeInternal(pszKey, dwHash, &pNode, &ppPreviousNodeNextPointer))
+    {
+        DeleteNodeInternal(ppPreviousNodeNextPointer, pNode);
+    }
+
+    _tableLock.ExclusiveRelease();
+}
+
+template <class _Record>
+VOID
+TREE_HASH_TABLE<_Record>::DeleteIf(
+    PFN_DELETE_IF               pfnDeleteIf,
+    PVOID                       pvContext
+)
+{
+    TREE_HASH_NODE<_Record> *pNode;
+    TREE_HASH_NODE<_Record> **ppPreviousNodeNextPointer;
+    BOOL fDelete;
+
+    _tableLock.ExclusiveAcquire();
+
+    for (DWORD i=0; i<_nBuckets; i++)
+    {
+        ppPreviousNodeNextPointer = _ppBuckets + i;
+        pNode = *ppPreviousNodeNextPointer;
+        while (pNode != NULL)
+        {
+            //
+            // Non empty nodes deleted based on DeleteIf, empty nodes deleted
+            // if they have no children
+            //
+            fDelete = FALSE;
+            if (pNode->_pRecord != NULL)
+            {
+                if (pfnDeleteIf(pNode->_pRecord, pvContext))
+                {
+                    fDelete = TRUE;
+                }
+            }
+            else if (pNode->_pFirstChild == NULL)
+            {
+                fDelete =  TRUE;
+            }
+
+            if (fDelete)
+            {
+                if (pNode->_pFirstChild == NULL)
+                {
+                    DeleteNodeInternal(ppPreviousNodeNextPointer, pNode);
+                }
+                else
+                {
+                    DereferenceRecord(pNode->_pRecord);
+                    pNode->_pRecord = NULL;
+                }
+            }
+            else
+            {
+                ppPreviousNodeNextPointer = &pNode->_pNext;
+            }
+
+            pNode = *ppPreviousNodeNextPointer;
+        }
+    }
+
+    _tableLock.ExclusiveRelease();
+}
+
+template <class _Record>
+VOID
+TREE_HASH_TABLE<_Record>::Apply(
+    PFN_APPLY                   pfnApply,
+    PVOID                       pvContext
+)
+{
+    TREE_HASH_NODE<_Record> *pNode;
+
+    _tableLock.SharedAcquire();
+
+    for (DWORD i=0; i<_nBuckets; i++)
+    {
+        pNode = _ppBuckets[i];
+        while (pNode != NULL)
+        {
+            if (pNode->_pRecord != NULL)
+            {
+                pfnApply(pNode->_pRecord, pvContext);
+            }
+
+            pNode = pNode->_pNext;
+        }
+    }
+
+    _tableLock.SharedRelease();
+}
+
+template <class _Record>
+VOID
+TREE_HASH_TABLE<_Record>::RehashTableIfNeeded(
+    VOID
+)
+{
+    TREE_HASH_NODE<_Record> **ppBuckets;
+    DWORD nBuckets;
+    TREE_HASH_NODE<_Record> *pNode;
+    TREE_HASH_NODE<_Record> *pNextNode;
+    TREE_HASH_NODE<_Record> **ppNextPointer;
+    TREE_HASH_NODE<_Record> *pNewNextNode;
+    DWORD               nNewBuckets;
+
+    //
+    // If number of items has become too many, we will double the hash table
+    // size (we never reduce it however)
+    //
+    if (_nItems <= PRIME::GetPrime(2*_nBuckets))
+    {
+        return;
+    }
+
+    _tableLock.ExclusiveAcquire();
+
+    nNewBuckets = PRIME::GetPrime(2*_nBuckets);
+
+    if (_nItems <= nNewBuckets)
+    {
+        goto Finished;
+    }
+
+    nBuckets = nNewBuckets;
+    if (nBuckets >= 0xffffffff/sizeof(TREE_HASH_NODE<_Record> *))
+    {
+        goto Finished;
+    }
+    ppBuckets = (TREE_HASH_NODE<_Record> **)HeapAlloc(
+                        GetProcessHeap(),
+                        HEAP_ZERO_MEMORY,
+                        nBuckets*sizeof(TREE_HASH_NODE<_Record> *));
+    if (ppBuckets == NULL)
+    {
+        goto Finished;
+    }
+
+    //
+    // Take out nodes from the old hash table and insert in the new one, make
+    // sure to keep the hashes in increasing order
+    //
+    for (DWORD i=0; i<_nBuckets; i++)
+    {
+        pNode = _ppBuckets[i];
+        while (pNode != NULL)
+        {
+            pNextNode = pNode->_pNext;
+
+            ppNextPointer = ppBuckets + (pNode->_dwHash % nBuckets);
+            pNewNextNode = *ppNextPointer;
+            while (pNewNextNode != NULL &&
+                   pNewNextNode->_dwHash <= pNode->_dwHash)
+            {
+                ppNextPointer = &pNewNextNode->_pNext;
+                pNewNextNode = pNewNextNode->_pNext;
+            }
+            pNode->_pNext = pNewNextNode;
+            *ppNextPointer = pNode;
+
+            pNode = pNextNode;
+        }
+    }
+
+    HeapFree(GetProcessHeap(), 0, _ppBuckets);
+    _ppBuckets = ppBuckets;
+    _nBuckets = nBuckets;
+    ppBuckets = NULL;
+
+Finished:
+
+    _tableLock.ExclusiveRelease();
+}
+
diff --git a/src/IISIntegration/src/AspNetCoreModuleV1/IISLib/util.cxx b/src/IISIntegration/src/AspNetCoreModuleV1/IISLib/util.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..214ee65abfe40757bd1946555a83a0ca404bf42c
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV1/IISLib/util.cxx
@@ -0,0 +1,78 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#include "precomp.h"
+
+HRESULT
+MakePathCanonicalizationProof(
+    IN PCWSTR               pszName,
+    OUT STRU *              pstrPath
+)
+/*++
+
+Routine Description:
+
+    This functions adds a prefix
+    to the string, which is "\\?\UNC\" for a UNC path, and "\\?\" for
+    other paths.  This prefix tells Windows not to parse the path.
+
+Arguments:
+
+    IN  pszName     - The path to be converted
+    OUT pstrPath    - Output path created
+
+Return Values:
+
+    HRESULT
+
+--*/
+{
+    HRESULT hr;
+
+    if (pszName[0] == L'\\' && pszName[1] == L'\\')
+    {
+        //
+        // If the path is already canonicalized, just return
+        //
+
+        if ((pszName[2] == '?' || pszName[2] == '.') &&
+            pszName[3] == '\\')
+        {
+            hr = pstrPath->Copy(pszName);
+
+            if (SUCCEEDED(hr))
+            {
+                //
+                // If the path was in DOS form ("\\.\"),
+                // we need to change it to Win32 from ("\\?\")
+                //
+
+                pstrPath->QueryStr()[2] = L'?';
+            }
+
+            return hr;
+        }
+
+        pszName += 2;
+
+
+        if (FAILED(hr = pstrPath->Copy(L"\\\\?\\UNC\\")))
+        {
+            return hr;
+        }
+    }
+    else if (wcslen(pszName) > MAX_PATH)
+    {
+        if (FAILED(hr = pstrPath->Copy(L"\\\\?\\")))
+        {
+            return hr;
+        }
+    }
+    else
+    {
+        pstrPath->Reset();
+    }  
+
+    return pstrPath->Append(pszName);
+}
+
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/AspNetCore/AspNetCore.vcxproj b/src/IISIntegration/src/AspNetCoreModuleV2/AspNetCore/AspNetCore.vcxproj
new file mode 100644
index 0000000000000000000000000000000000000000..4660054b0bfc436f4c17922a6a669ec30fb16b44
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/AspNetCore/AspNetCore.vcxproj
@@ -0,0 +1,260 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="..\..\..\Build\Build.Settings" />
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|Win32">
+      <Configuration>Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Debug|x64">
+      <Configuration>Debug</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|x64">
+      <Configuration>Release</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{EC82302F-D2F0-4727-99D1-EABC0DD9DC3B}</ProjectGuid>
+    <Keyword>Win32Proj</Keyword>
+    <RootNamespace>AspNetCoreModule</RootNamespace>
+    <ProjectName>AspNetCore</ProjectName>
+    <TargetName>aspnetcore</TargetName>
+    <LinkIncremental>false</LinkIncremental>
+    <WindowsTargetPlatformVersion>10.0.15063.0</WindowsTargetPlatformVersion>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+    <ConfigurationType>DynamicLibrary</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <PlatformToolset>v141</PlatformToolset>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+    <ConfigurationType>DynamicLibrary</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <PlatformToolset>v141</PlatformToolset>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+    <ConfigurationType>DynamicLibrary</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <PlatformToolset>v141</PlatformToolset>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+    <ConfigurationType>DynamicLibrary</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <PlatformToolset>v141</PlatformToolset>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup>
+    <OutDir>$(MSBuildProjectDirectory)\bin\$(Configuration)\$(Platform)\</OutDir>
+  </PropertyGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level4</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;ASPNETCOREMODULE_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <PrecompiledHeaderFile>precomp.hxx</PrecompiledHeaderFile>
+      <PrecompiledHeaderOutputFile>$(IntDir)$(TargetName).pch</PrecompiledHeaderOutputFile>
+      <AdditionalIncludeDirectories>..\IISLib;.\Inc</AdditionalIncludeDirectories>
+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <SDLCheck>true</SDLCheck>
+      <WholeProgramOptimization>true</WholeProgramOptimization>
+      <PreprocessKeepComments>false</PreprocessKeepComments>
+      <ExceptionHandling>SyncCThrow</ExceptionHandling>
+      <StructMemberAlignment>8Bytes</StructMemberAlignment>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <RuntimeTypeInfo>false</RuntimeTypeInfo>
+      <OmitDefaultLibName>true</OmitDefaultLibName>
+      <CompileAs>CompileAsCpp</CompileAs>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <AdditionalDependencies>kernel32.lib;user32.lib;advapi32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;ahadmin.lib;rpcrt4.lib;winhttp.lib;pdh.lib;ws2_32.lib;wbemuuid.lib;iphlpapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
+      <ModuleDefinitionFile>Source.def</ModuleDefinitionFile>
+    </Link>
+    <ResourceCompile>
+      <AdditionalIncludeDirectories>..\Commonlib</AdditionalIncludeDirectories>
+    </ResourceCompile>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level4</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;ASPNETCOREMODULE_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <PrecompiledHeaderFile>precomp.hxx</PrecompiledHeaderFile>
+      <PrecompiledHeaderOutputFile>$(IntDir)$(TargetName).pch</PrecompiledHeaderOutputFile>
+      <AdditionalIncludeDirectories>..\IISLib;.\Inc</AdditionalIncludeDirectories>
+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <SDLCheck>true</SDLCheck>
+      <WholeProgramOptimization>true</WholeProgramOptimization>
+      <PreprocessKeepComments>false</PreprocessKeepComments>
+      <ExceptionHandling>SyncCThrow</ExceptionHandling>
+      <StructMemberAlignment>8Bytes</StructMemberAlignment>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <RuntimeTypeInfo>false</RuntimeTypeInfo>
+      <OmitDefaultLibName>true</OmitDefaultLibName>
+      <CompileAs>CompileAsCpp</CompileAs>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <AdditionalDependencies>kernel32.lib;user32.lib;advapi32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;ahadmin.lib;rpcrt4.lib;winhttp.lib;pdh.lib;ws2_32.lib;wbemuuid.lib;iphlpapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
+      <ModuleDefinitionFile>Source.def</ModuleDefinitionFile>
+    </Link>
+    <ResourceCompile>
+      <AdditionalIncludeDirectories>..\Commonlib</AdditionalIncludeDirectories>
+    </ResourceCompile>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <ClCompile>
+      <WarningLevel>Level4</WarningLevel>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <Optimization>MaxSpeed</Optimization>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;ASPNETCOREMODULE_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <AdditionalIncludeDirectories>..\IISLib;inc</AdditionalIncludeDirectories>
+      <PrecompiledHeaderFile>precomp.hxx</PrecompiledHeaderFile>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <SDLCheck>true</SDLCheck>
+      <WholeProgramOptimization>true</WholeProgramOptimization>
+      <PreprocessKeepComments>false</PreprocessKeepComments>
+      <ExceptionHandling>SyncCThrow</ExceptionHandling>
+      <StructMemberAlignment>8Bytes</StructMemberAlignment>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <RuntimeTypeInfo>false</RuntimeTypeInfo>
+      <OmitDefaultLibName>true</OmitDefaultLibName>
+      <CompileAs>CompileAsCpp</CompileAs>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation>false</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+      <ModuleDefinitionFile>Source.def</ModuleDefinitionFile>
+      <AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;ahadmin.lib;winhttp.lib;odbc32.lib;ws2_32.lib;odbccp32.lib;wbemuuid.lib;iphlpapi.lib;pdh.lib;rpcrt4.lib;%(AdditionalDependencies)</AdditionalDependencies>
+    </Link>
+    <ResourceCompile>
+      <AdditionalIncludeDirectories>..\Commonlib</AdditionalIncludeDirectories>
+    </ResourceCompile>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <ClCompile>
+      <WarningLevel>Level4</WarningLevel>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <Optimization>MaxSpeed</Optimization>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;ASPNETCOREMODULE_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <PrecompiledHeaderFile>precomp.hxx</PrecompiledHeaderFile>
+      <AdditionalIncludeDirectories>..\IISLib;inc</AdditionalIncludeDirectories>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <SDLCheck>true</SDLCheck>
+      <WholeProgramOptimization>true</WholeProgramOptimization>
+      <PreprocessKeepComments>false</PreprocessKeepComments>
+      <ExceptionHandling>SyncCThrow</ExceptionHandling>
+      <StructMemberAlignment>8Bytes</StructMemberAlignment>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <RuntimeTypeInfo>false</RuntimeTypeInfo>
+      <OmitDefaultLibName>true</OmitDefaultLibName>
+      <CompileAs>CompileAsCpp</CompileAs>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation>false</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+      <ModuleDefinitionFile>Source.def</ModuleDefinitionFile>
+      <AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;ahadmin.lib;rpcrt4.lib;winhttp.lib;pdh.lib;ws2_32.lib;wbemuuid.lib;iphlpapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
+    </Link>
+    <ResourceCompile>
+      <AdditionalIncludeDirectories>..\Commonlib</AdditionalIncludeDirectories>
+    </ResourceCompile>
+  </ItemDefinitionGroup>
+  <ItemGroup>
+    <ClInclude Include="Inc\applicationinfo.h" />
+    <ClInclude Include="Inc\appoffline.h" />
+    <ClInclude Include="inc\globalmodule.h" />
+    <ClInclude Include="Inc\applicationmanager.h" />
+    <ClInclude Include="Inc\filewatcher.h" />
+    <ClInclude Include="Inc\proxymodule.h" />
+    <ClInclude Include="Src\precomp.hxx" />
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="Src\applicationinfo.cpp" />
+    <ClCompile Include="Src\applicationmanager.cxx" />
+    <ClCompile Include="Src\dllmain.cpp" />
+    <ClCompile Include="Src\filewatcher.cxx" />
+    <ClCompile Include="src\globalmodule.cpp" />
+    <ClCompile Include="Src\proxymodule.cxx" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\CommonLib\CommonLib.vcxproj">
+      <Project>{55494e58-e061-4c4c-a0a8-837008e72f85}</Project>
+    </ProjectReference>
+    <ProjectReference Include="..\IISLib\IISLib.vcxproj">
+      <Project>{09d9d1d6-2951-4e14-bc35-76a23cf9391a}</Project>
+    </ProjectReference>
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="ancm.mof" />
+    <None Include="Source.def" />
+  </ItemGroup>
+  <ItemGroup>
+    <ResourceCompile Include="aspnetcoremodule.rc" />
+  </ItemGroup>
+  <ItemGroup>
+    <Content Include="aspnetcore_schema.xml">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="ancm.mof">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+  </ItemGroup>
+  <ItemGroup>
+    <Xml Include="aspnetcore_schema.xml" />
+  </ItemGroup>
+  <Import Project="..\..\..\build\native.targets" />
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  </ImportGroup>
+</Project>
\ No newline at end of file
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/AspNetCore/Inc/applicationinfo.h b/src/IISIntegration/src/AspNetCoreModuleV2/AspNetCore/Inc/applicationinfo.h
new file mode 100644
index 0000000000000000000000000000000000000000..f47b51786bfc9feaf52ea16e633de683f0980d51
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/AspNetCore/Inc/applicationinfo.h
@@ -0,0 +1,251 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#pragma once
+#define API_BUFFER_TOO_SMALL 0x80008098
+
+extern BOOL     g_fRecycleProcessCalled;
+
+typedef
+HRESULT
+(WINAPI * PFN_ASPNETCORE_CREATE_APPLICATION)(
+    _In_  IHttpServer        *pServer,
+    _In_  ASPNETCORE_CONFIG  *pConfig,
+    _Out_ APPLICATION       **pApplication
+    );
+
+typedef
+HRESULT
+(WINAPI * PFN_ASPNETCORE_CREATE_REQUEST_HANDLER)(
+    _In_  IHttpContext       *pHttpContext,
+    _In_  HTTP_MODULE_ID     *pModuleId,
+    _In_  APPLICATION        *pApplication,
+    _Out_ REQUEST_HANDLER   **pRequestHandler
+    );
+//
+// The key used for hash-table lookups, consists of the port on which the http process is created.
+//
+class APPLICATION_INFO_KEY
+{
+public:
+
+    APPLICATION_INFO_KEY(
+        VOID
+    ) : INLINE_STRU_INIT(m_struKey)
+    {
+    }
+
+    HRESULT
+        Initialize(
+            _In_ LPCWSTR pszKey
+        )
+    {
+        return m_struKey.Copy(pszKey);
+    }
+
+    BOOL
+        GetIsEqual(
+            const APPLICATION_INFO_KEY * key2
+        ) const
+    {
+        return m_struKey.Equals(key2->m_struKey);
+    }
+
+    DWORD CalcKeyHash() const
+    {
+        return Hash(m_struKey.QueryStr());
+    }
+
+private:
+
+    INLINE_STRU(m_struKey, 1024);
+};
+
+
+class APPLICATION_INFO
+{
+public:
+
+    APPLICATION_INFO(IHttpServer *pServer) :
+        m_pServer(pServer),
+        m_cRefs(1), m_fAppOfflineFound(FALSE),
+        m_pAppOfflineHtm(NULL), m_pFileWatcherEntry(NULL),
+        m_pConfiguration(NULL),
+        m_pfnAspNetCoreCreateApplication(NULL),
+        m_pfnAspNetCoreCreateRequestHandler(NULL)
+    {
+        InitializeSRWLock(&m_srwLock);
+    }
+
+    APPLICATION_INFO_KEY *
+    QueryApplicationInfoKey()
+    {
+        return &m_applicationInfoKey;
+    }
+
+    virtual
+    ~APPLICATION_INFO();
+
+    HRESULT
+    Initialize(
+        _In_ ASPNETCORE_CONFIG   *pConfiguration,
+        _In_ FILE_WATCHER        *pFileWatcher
+    );
+
+    VOID
+    ReferenceApplicationInfo() const
+    {
+        InterlockedIncrement(&m_cRefs);
+    }
+
+    VOID
+    DereferenceApplicationInfo() const
+    {
+        if (InterlockedDecrement(&m_cRefs) == 0)
+        {
+            delete this;
+        }
+    }
+
+    APP_OFFLINE_HTM* QueryAppOfflineHtm()
+    {
+        return m_pAppOfflineHtm;
+    }
+
+    BOOL
+    AppOfflineFound()
+    {
+        return m_fAppOfflineFound;
+    }
+
+    VOID
+    UpdateAppOfflineFileHandle();
+
+    HRESULT
+    StartMonitoringAppOffline();
+
+    ASPNETCORE_CONFIG*
+    QueryConfig()
+    {
+        return m_pConfiguration;
+    }
+
+    //
+    // ExtractApplication will increase the reference counter of the application
+    // Caller is responsible for dereference the application.
+    // Otherwise memory leak
+    //
+    VOID
+    ExtractApplication(APPLICATION** ppApplication)
+    {
+        AcquireSRWLockShared(&m_srwLock);
+        if (m_pApplication != NULL)
+        {
+            m_pApplication->ReferenceApplication();
+        }
+        *ppApplication = m_pApplication;
+        ReleaseSRWLockShared(&m_srwLock);
+    }
+
+    VOID
+    RecycleApplication();
+
+    VOID
+    ShutDownApplication();
+
+    HRESULT
+    EnsureApplicationCreated();
+
+    PFN_ASPNETCORE_CREATE_REQUEST_HANDLER
+    QueryCreateRequestHandler()
+    {
+        return m_pfnAspNetCoreCreateRequestHandler;
+    }
+
+private:
+    HRESULT FindRequestHandlerAssembly();
+    HRESULT FindNativeAssemblyFromGlobalLocation(STRU* struFilename);
+    HRESULT FindNativeAssemblyFromHostfxr(STRU* struFilename);
+
+    static VOID DoRecycleApplication(LPVOID lpParam);
+
+    mutable LONG            m_cRefs;
+    APPLICATION_INFO_KEY    m_applicationInfoKey;
+    BOOL                    m_fAppOfflineFound;
+    APP_OFFLINE_HTM        *m_pAppOfflineHtm;
+    FILE_WATCHER_ENTRY     *m_pFileWatcherEntry;
+    ASPNETCORE_CONFIG      *m_pConfiguration;
+    APPLICATION            *m_pApplication;
+    SRWLOCK                 m_srwLock;
+    IHttpServer            *m_pServer;
+    PFN_ASPNETCORE_CREATE_APPLICATION      m_pfnAspNetCoreCreateApplication;
+    PFN_ASPNETCORE_CREATE_REQUEST_HANDLER  m_pfnAspNetCoreCreateRequestHandler;
+};
+
+class APPLICATION_INFO_HASH :
+    public HASH_TABLE<APPLICATION_INFO, APPLICATION_INFO_KEY *>
+{
+
+public:
+
+    APPLICATION_INFO_HASH()
+    {}
+
+    APPLICATION_INFO_KEY *
+    ExtractKey(
+        APPLICATION_INFO *pApplicationInfo
+    )
+    {
+        return pApplicationInfo->QueryApplicationInfoKey();
+    }
+
+    DWORD
+    CalcKeyHash(
+        APPLICATION_INFO_KEY *key
+    )
+    {
+        return key->CalcKeyHash();
+    }
+
+    BOOL
+    EqualKeys(
+        APPLICATION_INFO_KEY *key1,
+        APPLICATION_INFO_KEY *key2
+    )
+    {
+        return key1->GetIsEqual(key2);
+    }
+
+    VOID
+    ReferenceRecord(
+        APPLICATION_INFO *pApplicationInfo
+    )
+    {
+        pApplicationInfo->ReferenceApplicationInfo();
+    }
+
+    VOID
+    DereferenceRecord(
+        APPLICATION_INFO *pApplicationInfo
+    )
+    {
+        pApplicationInfo->DereferenceApplicationInfo();
+    }
+
+    static
+    VOID
+    ReferenceCopyToTable(
+        APPLICATION_INFO *        pEntry,
+        PVOID                     pvData
+    )
+    {
+        APPLICATION_INFO_HASH *pHash = static_cast<APPLICATION_INFO_HASH *>(pvData);
+        DBG_ASSERT(pHash);
+        pHash->InsertRecord(pEntry);
+    }
+
+private:
+
+    APPLICATION_INFO_HASH(const APPLICATION_INFO_HASH &);
+    void operator=(const APPLICATION_INFO_HASH &);
+};
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/AspNetCore/Inc/applicationmanager.h b/src/IISIntegration/src/AspNetCoreModuleV2/AspNetCore/Inc/applicationmanager.h
new file mode 100644
index 0000000000000000000000000000000000000000..7201d7de4920e5421133ad6a9a1e78ee1d883ab1
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/AspNetCore/Inc/applicationmanager.h
@@ -0,0 +1,154 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#pragma once
+
+#define DEFAULT_HASH_BUCKETS 17
+
+//
+// This class will manage the lifecycle of all Asp.Net Core applciation
+// It should be global singleton.
+// Should always call GetInstance to get the object instance
+//
+
+struct CONFIG_CHANGE_CONTEXT
+{
+    PCWSTR   pstrPath;
+    MULTISZ  MultiSz;
+};
+
+class APPLICATION_MANAGER
+{
+public:
+
+    static
+    APPLICATION_MANAGER*
+    GetInstance(
+        VOID
+    )
+    {
+        if ( sm_pApplicationManager == NULL )
+        {
+            sm_pApplicationManager = new APPLICATION_MANAGER();
+        }
+
+        return sm_pApplicationManager;
+    }
+
+    static
+    VOID
+    Cleanup(
+        VOID
+    )
+    {
+        if(sm_pApplicationManager != NULL)
+        {
+            delete sm_pApplicationManager;
+            sm_pApplicationManager = NULL;
+        }
+    }
+
+    static
+    BOOL
+    FindConfigChangedApplication(
+        _In_ APPLICATION_INFO *     pEntry,
+        _In_ PVOID                  pvContext
+    );
+
+    static
+    VOID
+    ShutdownApplication(
+        _In_ APPLICATION_INFO *     pEntry,
+        _In_ PVOID                  pvContext
+    );
+
+    HRESULT
+    GetOrCreateApplicationInfo(
+        _In_ IHttpServer*          pServer,
+        _In_ ASPNETCORE_CONFIG*    pConfig,
+        _Out_ APPLICATION_INFO **  ppApplicationInfo
+    );
+
+    HRESULT
+    RecycleApplicationFromManager(
+        _In_ LPCWSTR pszApplicationId
+    );
+
+    VOID
+    ShutDown();
+
+    ~APPLICATION_MANAGER()
+    {
+        if (m_pFileWatcher != NULL)
+        {
+            delete m_pFileWatcher;
+            m_pFileWatcher = NULL;
+        }
+
+        if(m_pApplicationInfoHash != NULL)
+        {
+            m_pApplicationInfoHash->Clear();
+            delete m_pApplicationInfoHash;
+            m_pApplicationInfoHash = NULL;
+        }
+    }
+
+    FILE_WATCHER*
+    GetFileWatcher()
+    {
+        return m_pFileWatcher;
+    }
+
+    HRESULT Initialize()
+    {
+        HRESULT hr = S_OK;
+
+        if(m_pApplicationInfoHash == NULL)
+        {
+            m_pApplicationInfoHash = new APPLICATION_INFO_HASH();
+            if(m_pApplicationInfoHash == NULL)
+            {
+                hr = E_OUTOFMEMORY;
+                goto Finished;
+            }
+
+            hr = m_pApplicationInfoHash->Initialize(DEFAULT_HASH_BUCKETS);
+            if(FAILED(hr))
+            {
+                goto Finished;
+            }
+        }
+
+        if( m_pFileWatcher == NULL )
+        {
+            m_pFileWatcher = new FILE_WATCHER;
+            if(m_pFileWatcher == NULL)
+            {
+                hr = HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
+                goto Finished;
+            }
+
+            m_pFileWatcher->Create();
+        }
+
+    Finished:
+        return hr;
+    }
+
+private:
+    //
+    // we currently limit the size of m_pstrErrorInfo to 5000, be careful if you want to change its payload
+    // 
+    APPLICATION_MANAGER() : m_pApplicationInfoHash(NULL), 
+        m_pFileWatcher(NULL),
+        m_hostingModel(HOSTING_UNKNOWN)
+    {
+        InitializeSRWLock(&m_srwLock);
+    }
+
+    FILE_WATCHER               *m_pFileWatcher;
+    APPLICATION_INFO_HASH      *m_pApplicationInfoHash;
+    static APPLICATION_MANAGER *sm_pApplicationManager;
+    SRWLOCK                     m_srwLock;
+    APP_HOSTING_MODEL          m_hostingModel;
+};
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/AspNetCore/Inc/appoffline.h b/src/IISIntegration/src/AspNetCoreModuleV2/AspNetCore/Inc/appoffline.h
new file mode 100644
index 0000000000000000000000000000000000000000..85b6c13ea8d3e5072a9c605e43181086c1f34084
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/AspNetCore/Inc/appoffline.h
@@ -0,0 +1,101 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#pragma once
+class APP_OFFLINE_HTM
+{
+public:
+    APP_OFFLINE_HTM(LPCWSTR pszPath) : m_cRefs(1)
+    {
+        m_Path.Copy(pszPath);
+    }
+
+    VOID
+    ReferenceAppOfflineHtm() const
+    {
+        InterlockedIncrement(&m_cRefs);
+    }
+
+    VOID
+    DereferenceAppOfflineHtm() const
+    {
+        if (InterlockedDecrement(&m_cRefs) == 0)
+        {
+            delete this;
+        }
+    }
+
+    BOOL
+    Load(
+        VOID
+    )
+    {
+        BOOL            fResult = TRUE;
+        LARGE_INTEGER   li = { 0 };
+        CHAR           *pszBuff = NULL;
+        HANDLE         handle = INVALID_HANDLE_VALUE;
+
+        handle = CreateFile(m_Path.QueryStr(),
+            GENERIC_READ,
+            FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+            NULL,
+            OPEN_EXISTING,
+            FILE_ATTRIBUTE_NORMAL,
+            NULL);
+
+        if (handle == INVALID_HANDLE_VALUE)
+        {
+            if (HRESULT_FROM_WIN32(GetLastError()) == ERROR_FILE_NOT_FOUND)
+            {
+                fResult = FALSE;
+            }
+
+            // This Load() member function is supposed be called only when the change notification event of file creation or file modification happens.
+            // If file is currenlty locked exclusively by other processes, we might get INVALID_HANDLE_VALUE even though the file exists. In that case, we should return TRUE here.
+            goto Finished;
+        }
+
+        if (!GetFileSizeEx(handle, &li))
+        {
+            goto Finished;
+        }
+
+        if (li.HighPart != 0)
+        {
+            // > 4gb file size not supported
+            // todo: log a warning at event log
+            goto Finished;
+        }
+
+        DWORD bytesRead = 0;
+
+        if (li.LowPart > 0)
+        {
+            pszBuff = new CHAR[li.LowPart + 1];
+
+            if (ReadFile(handle, pszBuff, li.LowPart, &bytesRead, NULL))
+            {
+                m_Contents.Copy(pszBuff, bytesRead);
+            }
+        }
+
+    Finished:
+        if (handle != INVALID_HANDLE_VALUE)
+        {
+            CloseHandle(handle);
+            handle = INVALID_HANDLE_VALUE;
+        }
+
+        if (pszBuff != NULL)
+        {
+            delete[] pszBuff;
+            pszBuff = NULL;
+        }
+
+        return fResult;
+    }
+
+    mutable LONG        m_cRefs;
+    STRA                m_Contents;
+    STRU                m_Path;
+};
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/AspNetCore/Inc/filewatcher.h b/src/IISIntegration/src/AspNetCoreModuleV2/AspNetCore/Inc/filewatcher.h
new file mode 100644
index 0000000000000000000000000000000000000000..d8bde448a781858dbcefde2f2a71ac632fb2c844
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/AspNetCore/Inc/filewatcher.h
@@ -0,0 +1,127 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#pragma once
+
+#define FILE_WATCHER_SHUTDOWN_KEY           (ULONG_PTR)(-1)
+#define FILE_WATCHER_ENTRY_BUFFER_SIZE      4096
+#ifndef CONTAINING_RECORD
+//
+// Calculate the address of the base of the structure given its type, and an
+// address of a field within the structure.
+//
+
+#define CONTAINING_RECORD(address, type, field) \
+    ((type *)((PCHAR)(address)-(ULONG_PTR)(&((type *)0)->field)))
+
+#endif // !CONTAINING_RECORD
+#define FILE_NOTIFY_VALID_MASK          0x00000fff
+#define FILE_WATCHER_ENTRY_SIGNATURE       ((DWORD) 'FWES')
+#define FILE_WATCHER_ENTRY_SIGNATURE_FREE  ((DWORD) 'sewf')
+
+class APPLICATION_INFO;
+
+class FILE_WATCHER{
+public:
+
+    FILE_WATCHER();
+
+    ~FILE_WATCHER();
+
+    HRESULT Create();
+
+    HANDLE
+    QueryCompletionPort(
+        VOID
+    ) const
+    {
+        return m_hCompletionPort;
+    }
+
+    static
+    DWORD
+    WINAPI ChangeNotificationThread(LPVOID);
+
+    static
+    void
+    WINAPI FileWatcherCompletionRoutine
+    (
+        DWORD                   dwCompletionStatus,
+        DWORD                   cbCompletion,
+        OVERLAPPED *            pOverlapped
+    );
+
+private:
+    HANDLE               m_hCompletionPort;
+    HANDLE               m_hChangeNotificationThread;
+    volatile   BOOL      m_fThreadExit;
+};
+
+class FILE_WATCHER_ENTRY
+{
+public:
+    FILE_WATCHER_ENTRY(FILE_WATCHER *   pFileMonitor);
+
+    OVERLAPPED    _overlapped;
+
+    HRESULT
+    Create(
+        _In_ PCWSTR                  pszDirectoryToMonitor,
+        _In_ PCWSTR                  pszFileNameToMonitor,
+        _In_ APPLICATION_INFO*       pApplicationInfo,
+        _In_ HANDLE                  hImpersonationToken
+        );
+
+    VOID
+    ReferenceFileWatcherEntry() const
+    {
+        InterlockedIncrement(&_cRefs);
+    }
+
+    VOID
+    DereferenceFileWatcherEntry() const
+    {
+        if (InterlockedDecrement(&_cRefs) == 0)
+        {
+            delete this;
+        }
+    }
+
+    BOOL
+    QueryIsValid() const
+    {
+        return _fIsValid;
+    }
+
+    VOID
+    MarkEntryInValid()
+    {
+        _fIsValid = FALSE;
+    }
+
+    HRESULT Monitor();
+
+    VOID StopMonitor();
+
+    HRESULT
+    HandleChangeCompletion(
+        _In_ DWORD          dwCompletionStatus,
+        _In_ DWORD          cbCompletion
+        );
+
+private:
+    virtual ~FILE_WATCHER_ENTRY();
+
+    DWORD                   _dwSignature;
+    BUFFER                  _buffDirectoryChanges;
+    HANDLE                  _hImpersonationToken;
+    HANDLE                  _hDirectory;
+    FILE_WATCHER*           _pFileMonitor;
+    APPLICATION_INFO*       _pApplicationInfo;
+    STRU                    _strFileName;
+    STRU                    _strDirectoryName;
+    LONG                    _lStopMonitorCalled;
+    mutable LONG            _cRefs;
+    BOOL                    _fIsValid;
+    SRWLOCK                 _srwLock;
+};
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/AspNetCore/Inc/fx_ver.h b/src/IISIntegration/src/AspNetCoreModuleV2/AspNetCore/Inc/fx_ver.h
new file mode 100644
index 0000000000000000000000000000000000000000..f485ba5a6e7f9d38003df08a666f999349429f2f
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/AspNetCore/Inc/fx_ver.h
@@ -0,0 +1,49 @@
+// Copyright (c) .NET Foundation and contributors. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+#ifndef __FX_VER_H__
+#define __FX_VER_H__
+#include <string>
+
+// Note: This is not SemVer (esp., in comparing pre-release part, fx_ver_t does not
+// compare multiple dot separated identifiers individually.) ex: 1.0.0-beta.2 vs. 1.0.0-beta.11
+struct fx_ver_t
+{
+	fx_ver_t(int major, int minor, int patch);
+	fx_ver_t(int major, int minor, int patch, const std::wstring& pre);
+	fx_ver_t(int major, int minor, int patch, const std::wstring& pre, const std::wstring& build);
+
+	int get_major() const { return m_major; }
+	int get_minor() const { return m_minor; }
+	int get_patch() const { return m_patch; }
+
+	void set_major(int m) { m_major = m; }
+	void set_minor(int m) { m_minor = m; }
+	void set_patch(int p) { m_patch = p; }
+
+	bool is_prerelease() const { return !m_pre.empty(); }
+
+	std::wstring as_str() const;
+	std::wstring prerelease_glob() const;
+	std::wstring patch_glob() const;
+
+	bool operator ==(const fx_ver_t& b) const;
+	bool operator !=(const fx_ver_t& b) const;
+	bool operator <(const fx_ver_t& b) const;
+	bool operator >(const fx_ver_t& b) const;
+	bool operator <=(const fx_ver_t& b) const;
+	bool operator >=(const fx_ver_t& b) const;
+
+	static bool parse(const std::wstring& ver, fx_ver_t* fx_ver, bool parse_only_production = false);
+
+private:
+	int m_major;
+	int m_minor;
+	int m_patch;
+	std::wstring m_pre;
+	std::wstring m_build;
+
+	static int compare(const fx_ver_t&a, const fx_ver_t& b);
+};
+
+#endif // __FX_VER_H__
\ No newline at end of file
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/AspNetCore/Inc/globalmodule.h b/src/IISIntegration/src/AspNetCoreModuleV2/AspNetCore/Inc/globalmodule.h
new file mode 100644
index 0000000000000000000000000000000000000000..aca1857051793b926093d6b997f410dfb51c3ede
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/AspNetCore/Inc/globalmodule.h
@@ -0,0 +1,37 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#pragma once
+
+class ASPNET_CORE_GLOBAL_MODULE : public CGlobalModule
+{
+
+public:
+
+    ASPNET_CORE_GLOBAL_MODULE(
+        APPLICATION_MANAGER* pApplicationManager
+    );
+
+    ~ASPNET_CORE_GLOBAL_MODULE()
+    {
+    }
+
+    VOID Terminate()
+    {
+        // Remove the class from memory.
+        delete this;
+    }
+
+    GLOBAL_NOTIFICATION_STATUS
+    OnGlobalStopListening(
+        _In_ IGlobalStopListeningProvider * pProvider
+    );
+
+    GLOBAL_NOTIFICATION_STATUS
+    OnGlobalConfigurationChange(
+        _In_ IGlobalConfigurationChangeProvider * pProvider
+    );
+
+private:
+    APPLICATION_MANAGER * m_pApplicationManager;
+};
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/AspNetCore/Inc/proxymodule.h b/src/IISIntegration/src/AspNetCoreModuleV2/AspNetCore/Inc/proxymodule.h
new file mode 100644
index 0000000000000000000000000000000000000000..7e5f30a8eb83f901c1326b58fad9915224ebc03c
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/AspNetCore/Inc/proxymodule.h
@@ -0,0 +1,64 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#pragma once
+
+extern HTTP_MODULE_ID   g_pModuleId;
+extern IHttpServer     *g_pHttpServer;
+extern HMODULE          g_hAspnetCoreRH;
+
+class ASPNET_CORE_PROXY_MODULE : public CHttpModule
+{
+ public:
+
+     ASPNET_CORE_PROXY_MODULE();
+
+    ~ASPNET_CORE_PROXY_MODULE();
+
+    void * operator new(size_t size, IModuleAllocator * pPlacement)
+    {
+        return pPlacement->AllocateMemory(static_cast<DWORD>(size));
+    }
+
+    VOID
+    operator delete(
+        void *
+    )
+    {}
+
+    __override
+    REQUEST_NOTIFICATION_STATUS
+    OnExecuteRequestHandler(
+        IHttpContext *          pHttpContext,
+        IHttpEventProvider *    pProvider
+    );
+
+    __override
+    REQUEST_NOTIFICATION_STATUS
+    OnAsyncCompletion(
+        IHttpContext *          pHttpContext,
+        DWORD                   dwNotification,
+        BOOL                    fPostNotification,
+        IHttpEventProvider *    pProvider,
+        IHttpCompletionInfo *   pCompletionInfo
+    );
+
+ private:
+
+    APPLICATION_INFO *m_pApplicationInfo;
+    APPLICATION      *m_pApplication;
+    REQUEST_HANDLER  *m_pHandler;
+};
+
+class ASPNET_CORE_PROXY_MODULE_FACTORY : public IHttpModuleFactory
+{
+ public:
+    HRESULT
+    GetHttpModule(
+        CHttpModule **      ppModule,
+        IModuleAllocator *  pAllocator
+    );
+
+    VOID
+    Terminate();
+};
\ No newline at end of file
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/AspNetCore/Source.def b/src/IISIntegration/src/AspNetCoreModuleV2/AspNetCore/Source.def
new file mode 100644
index 0000000000000000000000000000000000000000..9aae10ab5d9a85608376c438ec770b90db3e5094
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/AspNetCore/Source.def
@@ -0,0 +1,4 @@
+LIBRARY aspnetcore
+
+EXPORTS
+    RegisterModule
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/AspNetCore/ancm.mof b/src/IISIntegration/src/AspNetCoreModuleV2/AspNetCore/ancm.mof
new file mode 100644
index 0000000000000000000000000000000000000000..5a50b1991468f301086ab362f2e188eff71f9bdb
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/AspNetCore/ancm.mof
@@ -0,0 +1,208 @@
+#pragma classflags("forceupdate")
+#pragma namespace ("\\\\.\\Root\\WMI")
+#pragma autorecover
+
+/*
+ * AspNetCore module trace events layout
+ * Uncomment the following class to run mof2trace to generate header file
+ * comment it back before checking it in */
+[Dynamic,
+  Description("IIS: WWW Server"),
+  Guid("{3a2a4e84-4c21-4981-ae10-3fda0d9b0f83}"),
+  locale("MS\\0x409")]
+class IIS_Trace:EventTrace
+{
+    [Description ("Enable Flags") : amended,
+        ValueDescriptions{
+            "AspNetCore module events" } : amended,
+        DefineValues{
+            "ETW_IIS_ANCM" },
+        Values{
+            "ANCM" },
+        ValueMap{
+            "0x10000" }
+    ]
+    uint32 Flags;
+
+    [Description ("Levels") : amended,
+        ValueDescriptions{
+            "Abnormal exit or termination",
+            "Severe errors",
+            "Warnings",
+            "Information",
+            "Detailed information" } : amended,
+         DefineValues{
+            "TRACE_LEVEL_FATAL",
+            "TRACE_LEVEL_ERROR",
+            "TRACE_LEVEL_WARNING",
+            "TRACE_LEVEL_INFORMATION",
+            "TRACE_LEVEL_VERBOSE" },
+        Values{
+            "Fatal",
+            "Error",
+            "Warning",
+            "Information",
+            "Verbose" },
+        ValueMap{
+            "0x1",
+            "0x2",
+            "0x3",
+            "0x4",
+            "0x5" },
+        ValueType("index")
+    ]
+    uint32 Level;
+};
+*/
+
+[Dynamic,
+ Description("ANCM runtime events") : amended,
+ Guid("{82ADEAD7-12B2-4781-BDCA-5A4B6C757191}"),
+ EventVersion(1),
+ DisplayName("ANCM"),
+ EventANCMRuntime,
+ locale("MS\\0x409")
+]
+class ANCM_Events:IIS_Trace
+{
+};
+
+[Dynamic,
+ Description("Start application success") : amended,
+ EventType(1),
+ EventLevel(4),
+ EventTypeName("ANCM_START_APPLICATION_SUCCESS") : amended
+]
+class ANCMAppStart:ANCM_Events
+{
+    [WmiDataId(1),
+     Description("Context ID") : amended,
+     extension("Guid"),
+     ActivityID,
+     read]
+     object  ContextId;
+    [WmiDataId(2),
+     Description("Application Description") : amended,
+     StringTermination("NullTerminated"),
+     format("w"),
+     read]
+     string AppDescription;
+};
+
+[Dynamic,
+ Description("Start application failed") : amended,
+ EventType(2),
+ EventLevel(2),
+ EventTypeName("ANCM_START_APPLICATION_FAIL") : amended
+]
+class ANCMAppStartFail:ANCM_Events
+{
+    [WmiDataId(1),
+     Description("Context ID") : amended,
+     extension("Guid"),
+     ActivityID,
+     read]
+     object  ContextId;
+    [WmiDataId(2),
+     Description("Application Start Failure Description") : amended,
+     StringTermination("NullTerminated"),
+     format("w"),
+     read]
+     string FailureDescription;
+};
+
+[Dynamic,
+ Description("Start forwarding request") : amended,
+ EventType(3),
+ EventLevel(4),
+ EventTypeName("ANCM_REQUEST_FORWARD_START") : amended
+]
+class ANCMForwardStart:ANCM_Events
+{
+    [WmiDataId(1),
+     Description("Context ID") : amended,
+     extension("Guid"),
+     ActivityID,
+     read]
+     object  ContextId;
+};
+
+[Dynamic,
+ Description("Finish forwarding request") : amended,
+ EventType(4),
+ EventLevel(4),
+ EventTypeName("ANCM_REQUEST_FORWARD_END") : amended
+]
+class ANCMForwardEnd:ANCM_Events
+{
+    [WmiDataId(1),
+     Description("Context ID") : amended,
+     extension("Guid"),
+     ActivityID,
+     read]
+     object  ContextId;
+};
+
+[Dynamic,
+ Description("Forwarding request failure") : amended,
+ EventType(5),
+ EventLevel(2),
+ EventTypeName("ANCM_REQUEST_FORWARD_FAIL") : amended
+]
+class ANCMForwardFail:ANCM_Events
+{
+    [WmiDataId(1),
+     Description("Context ID") : amended,
+     extension("Guid"),
+     ActivityID,
+     read]
+     object  ContextId;
+    [WmiDataId(2),
+     Description("Error code") : amended,
+     format("x"),
+     read]
+     uint32  ErrorCode;
+};
+
+[Dynamic,
+ Description("Receiving callback from WinHttp") : amended,
+ EventType(6),
+ EventLevel(4),
+ EventTypeName("ANCM_WINHTTP_CALLBACK") : amended
+]
+class ANCMWinHttpCallBack:ANCM_Events
+{
+    [WmiDataId(1),
+     Description("Context ID") : amended,
+     extension("Guid"),
+     ActivityID,
+     read]
+     object  ContextId;
+    [WmiDataId(2),
+     Description("InternetStatus") : amended,
+     format("x"),
+     read]
+     uint32  InternetStatus;
+};
+
+[Dynamic,
+ Description("Inprocess executing request failure") : amended,
+ EventType(7),
+ EventLevel(2),
+ EventTypeName("ANCM_EXECUTE_REQUEST_FAIL") : amended
+]
+class ANCMExecuteFailed:ANCM_Events
+{
+    [WmiDataId(1),
+     Description("Context ID") : amended,
+     extension("Guid"),
+     ActivityID,
+     read]
+     object  ContextId;
+    [WmiDataId(2),
+     Description("InternetStatus") : amended,
+     format("x"),
+     read]
+     uint32  ErrorCode;
+};
+
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/AspNetCore/aspnetcore_schema.xml b/src/IISIntegration/src/AspNetCoreModuleV2/AspNetCore/aspnetcore_schema.xml
new file mode 100644
index 0000000000000000000000000000000000000000..d65be071958cc6acf6e55f7e6f786c3ac61f2a3b
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/AspNetCore/aspnetcore_schema.xml
@@ -0,0 +1,47 @@
+<!--
+    
+    IIS Asp.Net Core Extension Schema
+    
+    ** Please DO NOT edit this file yourself. **
+    
+    If you want to add configuration sections to the schema, you may place 
+    them in .xml files similar to this one, in this directory. They will be 
+    picked up automatically on startup.
+
+-->
+
+<configSchema>
+    <sectionSchema name="system.webServer/aspNetCore">
+        <attribute name="processPath" type="string" expanded="true"/>
+        <attribute name="arguments" type="string" expanded="true" defaultValue=""/>
+        <attribute name="startupTimeLimit" type="uint" defaultValue="120" validationType="integerRange" validationParameter="0,3600"/>
+        <!-- in seconds -->
+        <attribute name="shutdownTimeLimit" type="uint" defaultValue="10" validationType="integerRange" validationParameter="0,600"/>
+        <!-- in seconds -->
+        <attribute name="rapidFailsPerMinute" type="uint" defaultValue="10" validationType="integerRange" validationParameter="0,100"/>
+        <attribute name="requestTimeout" type="timeSpan" defaultValue="00:02:00" validationType="timeSpanRange" validationParameter="0,1296000,1"/>
+        <attribute name="stdoutLogEnabled" type="bool" defaultValue="false" />
+        <attribute name="stdoutLogFile" type="string" defaultValue=".\aspnetcore-stdout" expanded="true"/>
+        <attribute name="processesPerApplication" type="uint" defaultValue="1" validationType="integerRange" validationParameter="1,100"/>
+        <attribute name="forwardWindowsAuthToken" type="bool" defaultValue="true" />
+        <attribute name="disableStartUpErrorPage" type="bool" defaultValue="false" />
+        <attribute name="hostingModel" type="string" />
+        <element name="recycleOnFileChange">
+            <collection addElement="file" clearElement="clear">
+                <attribute name="path" type="string" required="true" validationType="nonEmptyString" expanded="true"/>
+            </collection>
+        </element>
+        <element name="environmentVariables">
+            <collection addElement="environmentVariable" clearElement="clear" >
+                <attribute name="name" type="string" required="true" validationType="nonEmptyString"/>
+                <attribute name="value" type="string" required="true"/>
+            </collection>
+        </element>
+        <element name="handlerSettings">
+            <collection addElement="handlerSetting" clearElement="clear" >
+                <attribute name="name" type="string" required="true" validationType="nonEmptyString"/>
+               <attribute name="value" type="string" required="true"/>
+            </collection>
+        </element>
+    </sectionSchema>
+</configSchema>
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/AspNetCore/aspnetcoremodule.rc b/src/IISIntegration/src/AspNetCoreModuleV2/AspNetCore/aspnetcoremodule.rc
new file mode 100644
index 0000000000000000000000000000000000000000..9d0dfa7f832e3fc7577ea96b00e02f49ae5a0fd2
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/AspNetCore/aspnetcoremodule.rc
@@ -0,0 +1,120 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include <windows.h>
+#include "version.h"
+#include "..\CommonLib\Aspnetcore_msg.rc"
+#include "..\CommonLib\resources.h"
+/////////////////////////////////////////////////////////////////////////////
+// English (United States) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+
+#define FileDescription "IIS AspNetCore Module. Commit: " CommitHash
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// 11
+//
+
+//1 11
+//BEGIN
+//    0x0001, 0x0000, 0x03e8, 0x0000, 0x03ed, 0x0000, 0x0010, 0x0000, 0x0010, 
+//    0x0001, 0x0025, 0x0031, 0x000d, 0x000a, 0x0000, 0x0000, 0x0010, 0x0001, 
+//    0x0025, 0x0031, 0x000d, 0x000a, 0x0000, 0x0000, 0x0010, 0x0001, 0x0025, 
+//    0x0031, 0x000d, 0x000a, 0x0000, 0x0000, 0x0010, 0x0001, 0x0025, 0x0031, 
+//    0x000d, 0x000a, 0x0000, 0x0000, 0x0010, 0x0001, 0x0025, 0x0031, 0x000d, 
+//    0x000a, 0x0000, 0x0000, 0x0010, 0x0001, 0x0025, 0x0031, 0x000d, 0x000a, 
+//    0x0000, 0x0000
+//END
+
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE 
+BEGIN
+    "..\CommonLib\resources.h\0"
+END
+
+2 TEXTINCLUDE 
+BEGIN
+    "\0"
+END
+
+3 TEXTINCLUDE 
+BEGIN
+    "\r\n"
+    "\0"
+END
+
+#endif    // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION FileVersion
+ PRODUCTVERSION ProductVersion
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x40004L
+ FILETYPE 0x2L
+ FILESUBTYPE 0x0L
+BEGIN
+    BLOCK "StringFileInfo"
+    BEGIN
+        BLOCK "040904b0"
+        BEGIN
+            VALUE "CompanyName", "Microsoft Corporation"
+            VALUE "FileDescription", FileDescription
+            VALUE "FileVersion", FileVersionStr
+            VALUE "InternalName", "aspnetcore"
+            VALUE "LegalCopyright", "Copyright (C) Microsoft Corporation"
+            VALUE "OriginalFilename", "aspnetcore.dll"
+            VALUE "ProductName", "ASP.NET Core Module"
+            VALUE "ProductVersion", ProductVersionStr
+        END
+    END
+    BLOCK "VarFileInfo"
+    BEGIN
+        VALUE "Translation", 0x409, 1200
+    END
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// String Table
+//
+
+STRINGTABLE
+BEGIN
+    IDS_INVALID_PROPERTY    "Property name '%s' in system.webServer/aspNetCore section has invalid value '%s' which does not conform to the prescribed format"
+    IDS_SERVER_ERROR        "There was a connection error while trying to route the request."
+END
+
+#endif    // English (United States) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif    // not APSTUDIO_INVOKED
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/AspNetCore/src/applicationinfo.cpp b/src/IISIntegration/src/AspNetCoreModuleV2/AspNetCore/src/applicationinfo.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..63efb9e889db4a4de9ba2ac10b77bbde7c4480ea
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/AspNetCore/src/applicationinfo.cpp
@@ -0,0 +1,650 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#include "precomp.hxx"
+
+APPLICATION_INFO::~APPLICATION_INFO()
+{
+    if (m_pAppOfflineHtm != NULL)
+    {
+        m_pAppOfflineHtm->DereferenceAppOfflineHtm();
+        m_pAppOfflineHtm = NULL;
+    }
+
+    if (m_pFileWatcherEntry != NULL)
+    {
+        // Mark the entry as invalid,
+        // StopMonitor will close the file handle and trigger a FCN
+        // the entry will delete itself when processing this FCN 
+        m_pFileWatcherEntry->MarkEntryInValid();
+        m_pFileWatcherEntry->StopMonitor();
+        m_pFileWatcherEntry->DereferenceFileWatcherEntry();
+        m_pFileWatcherEntry = NULL;
+    }
+
+    if (m_pApplication != NULL)
+    {
+        // shutdown the application
+        m_pApplication->ShutDown();
+        m_pApplication->DereferenceApplication();
+        m_pApplication = NULL;
+    }
+
+    // configuration should be dereferenced after application shutdown
+    // since the former will use it during shutdown
+    if (m_pConfiguration != NULL)
+    {
+        // Need to dereference the configuration instance
+        m_pConfiguration->DereferenceConfiguration();
+        m_pConfiguration = NULL;
+    }
+}
+
+HRESULT
+APPLICATION_INFO::Initialize(
+    _In_ ASPNETCORE_CONFIG   *pConfiguration,
+    _In_ FILE_WATCHER        *pFileWatcher
+)
+{
+    HRESULT hr = S_OK;
+
+    DBG_ASSERT(pConfiguration);
+    DBG_ASSERT(pFileWatcher);
+
+    m_pConfiguration = pConfiguration;
+
+    // reference the configuration instance to prevent it will be not release
+    // earlier in case of configuration change and shutdown
+    m_pConfiguration->ReferenceConfiguration();
+
+    hr = m_applicationInfoKey.Initialize(pConfiguration->QueryConfigPath()->QueryStr());
+    if (FAILED(hr))
+    {
+        goto Finished;
+    }
+
+    if (m_pFileWatcherEntry == NULL)
+    {
+        m_pFileWatcherEntry = new FILE_WATCHER_ENTRY(pFileWatcher);
+        if (m_pFileWatcherEntry == NULL)
+        {
+            hr = E_OUTOFMEMORY;
+            goto Finished;
+        }
+    }
+
+    UpdateAppOfflineFileHandle();
+
+Finished:
+    return hr;
+}
+
+HRESULT
+APPLICATION_INFO::StartMonitoringAppOffline()
+{
+    HRESULT hr = S_OK;
+    if (m_pFileWatcherEntry != NULL)
+    {
+        hr = m_pFileWatcherEntry->Create(m_pConfiguration->QueryApplicationPhysicalPath()->QueryStr(), L"app_offline.htm", this, NULL);
+    }
+    return hr;
+}
+
+//
+// Called by the file watcher when the app_offline.htm's file status has been changed.
+// If it finds it, we will call recycle on the application.
+//
+VOID
+APPLICATION_INFO::UpdateAppOfflineFileHandle()
+{
+    STRU strFilePath;
+    UTILITY::ConvertPathToFullPath(L".\\app_offline.htm",
+        m_pConfiguration->QueryApplicationPhysicalPath()->QueryStr(),
+        &strFilePath);
+    APP_OFFLINE_HTM *pOldAppOfflineHtm = NULL;
+    APP_OFFLINE_HTM *pNewAppOfflineHtm = NULL;
+
+    ReferenceApplicationInfo();
+
+    if (INVALID_FILE_ATTRIBUTES == GetFileAttributes(strFilePath.QueryStr()) &&
+        GetLastError() == ERROR_FILE_NOT_FOUND)
+    {
+        // Check if app offline was originally present.
+        // if it was, log that app_offline has been dropped.
+        if (m_fAppOfflineFound)
+        {
+            STACK_STRU(strEventMsg, 256);
+            if (SUCCEEDED(strEventMsg.SafeSnwprintf(
+                ASPNETCORE_EVENT_RECYCLE_APPOFFLINE_REMOVED_MSG)))
+            {
+                UTILITY::LogEvent(g_hEventLog,
+                    EVENTLOG_INFORMATION_TYPE,
+                    ASPNETCORE_EVENT_RECYCLE_APPOFFLINE_REMOVED,
+                    strEventMsg.QueryStr());
+            }
+        }
+
+        m_fAppOfflineFound = FALSE;
+    }
+    else
+    {
+        pNewAppOfflineHtm = new APP_OFFLINE_HTM(strFilePath.QueryStr());
+
+        if (pNewAppOfflineHtm != NULL)
+        {
+            if (pNewAppOfflineHtm->Load())
+            {
+                //
+                // loaded the new app_offline.htm
+                //
+                pOldAppOfflineHtm = (APP_OFFLINE_HTM *)InterlockedExchangePointer((VOID**)&m_pAppOfflineHtm, pNewAppOfflineHtm);
+
+                if (pOldAppOfflineHtm != NULL)
+                {
+                    pOldAppOfflineHtm->DereferenceAppOfflineHtm();
+                    pOldAppOfflineHtm = NULL;
+                }
+            }
+            else
+            {
+                // ignored the new app_offline file because the file does not exist.
+                pNewAppOfflineHtm->DereferenceAppOfflineHtm();
+                pNewAppOfflineHtm = NULL;
+            }
+        }
+
+        m_fAppOfflineFound = TRUE;
+
+        // recycle the application
+        if (m_pApplication != NULL)
+        {
+            STACK_STRU(strEventMsg, 256);
+            if (SUCCEEDED(strEventMsg.SafeSnwprintf(
+                ASPNETCORE_EVENT_RECYCLE_APPOFFLINE_MSG,
+                m_pApplication->QueryConfig()->QueryApplicationPath()->QueryStr())))
+            {
+                UTILITY::LogEvent(g_hEventLog,
+                    EVENTLOG_INFORMATION_TYPE,
+                    ASPNETCORE_EVENT_RECYCLE_APPOFFLINE,
+                    strEventMsg.QueryStr());
+            }
+
+            RecycleApplication();
+        }
+    }
+
+    DereferenceApplicationInfo();
+}
+
+HRESULT
+APPLICATION_INFO::EnsureApplicationCreated()
+{
+    HRESULT             hr = S_OK;
+    BOOL                fLocked = FALSE;
+    APPLICATION*        pApplication = NULL;
+    STACK_STRU(struFileName, 300);  // >MAX_PATH
+    STRU                struHostFxrDllLocation;
+
+    if (m_pApplication != NULL)
+    {
+        goto Finished;
+    }
+
+    if (m_pApplication == NULL)
+    {
+        AcquireSRWLockExclusive(&m_srwLock);
+        fLocked = TRUE;
+        if (m_pApplication != NULL)
+        {
+            goto Finished;
+        }
+
+        //
+        // in case of app offline, we don't want to create a new application now
+        //
+        if (!m_fAppOfflineFound)
+        {
+
+            // Move the request handler check inside of the lock
+            // such that only one request finds and loads it.
+            // FindRequestHandlerAssembly obtains a global lock, but after releasing the lock,
+            // there is a period where we could call
+
+            hr = FindRequestHandlerAssembly();
+            if (FAILED(hr))
+            {
+                goto Finished;
+            }
+
+            if (m_pfnAspNetCoreCreateApplication == NULL)
+            {
+                hr = HRESULT_FROM_WIN32(ERROR_INVALID_FUNCTION);
+                goto Finished;
+            }
+
+            hr = m_pfnAspNetCoreCreateApplication(m_pServer, m_pConfiguration, &pApplication);
+            if (FAILED(hr))
+            {
+                goto Finished;
+            }
+            m_pApplication = pApplication;
+        }
+    }
+
+Finished:
+    if (fLocked)
+    {
+        ReleaseSRWLockExclusive(&m_srwLock);
+    }
+    return hr;
+}
+
+HRESULT
+APPLICATION_INFO::FindRequestHandlerAssembly()
+{
+    HRESULT             hr = S_OK;
+    BOOL                fLocked = FALSE;
+    STACK_STRU(struFileName, 256);
+
+    if (g_fAspnetcoreRHLoadedError)
+    {
+        hr = E_APPLICATION_ACTIVATION_EXEC_FAILURE;
+        goto Finished;
+    }
+    else if (!g_fAspnetcoreRHAssemblyLoaded)
+    {
+        AcquireSRWLockExclusive(&g_srwLock);
+        fLocked = TRUE;
+        if (g_fAspnetcoreRHLoadedError)
+        {
+            hr = E_APPLICATION_ACTIVATION_EXEC_FAILURE;
+            goto Finished;
+        }
+        if (g_fAspnetcoreRHAssemblyLoaded)
+        {
+            goto Finished;
+        }
+
+        if (m_pConfiguration->QueryHostingModel() == APP_HOSTING_MODEL::HOSTING_IN_PROCESS)
+        {
+            if (FAILED(hr = FindNativeAssemblyFromHostfxr(&struFileName)))
+            {
+                STACK_STRU(strEventMsg, 256);
+                if (SUCCEEDED(strEventMsg.SafeSnwprintf(
+                    ASPNETCORE_EVENT_INPROCESS_RH_MISSING_MSG)))
+                {
+                    UTILITY::LogEvent(g_hEventLog,
+                        EVENTLOG_INFORMATION_TYPE,
+                        ASPNETCORE_EVENT_INPROCESS_RH_MISSING,
+                        strEventMsg.QueryStr());
+                }
+
+                goto Finished;
+            }
+        }
+        else
+        {
+            if (FAILED(hr = FindNativeAssemblyFromGlobalLocation(&struFileName)))
+            {
+                STACK_STRU(strEventMsg, 256);
+                if (SUCCEEDED(strEventMsg.SafeSnwprintf(
+                    ASPNETCORE_EVENT_OUT_OF_PROCESS_RH_MISSING_MSG)))
+                {
+                    UTILITY::LogEvent(g_hEventLog,
+                        EVENTLOG_INFORMATION_TYPE,
+                        ASPNETCORE_EVENT_OUT_OF_PROCESS_RH_MISSING,
+                        strEventMsg.QueryStr());
+                }
+
+                goto Finished;
+            }
+        }
+
+        g_hAspnetCoreRH = LoadLibraryW(struFileName.QueryStr());
+        if (g_hAspnetCoreRH == NULL)
+        {
+            hr = HRESULT_FROM_WIN32(GetLastError());
+            goto Finished;
+        }
+
+        g_pfnAspNetCoreCreateApplication = (PFN_ASPNETCORE_CREATE_APPLICATION)
+            GetProcAddress(g_hAspnetCoreRH, "CreateApplication");
+        if (g_pfnAspNetCoreCreateApplication == NULL)
+        {
+            hr = HRESULT_FROM_WIN32(GetLastError());
+            goto Finished;
+        }
+
+        g_pfnAspNetCoreCreateRequestHandler = (PFN_ASPNETCORE_CREATE_REQUEST_HANDLER)
+            GetProcAddress(g_hAspnetCoreRH, "CreateRequestHandler");
+        if (g_pfnAspNetCoreCreateRequestHandler == NULL)
+        {
+            hr = HRESULT_FROM_WIN32(GetLastError());
+            goto Finished;
+        }
+        g_fAspnetcoreRHAssemblyLoaded = TRUE;
+    }
+
+Finished:
+    //
+    // Question: we remember the load failure so that we will not try again.
+    // User needs to check whether the fuction pointer is NULL 
+    //
+    m_pfnAspNetCoreCreateApplication = g_pfnAspNetCoreCreateApplication;
+    m_pfnAspNetCoreCreateRequestHandler = g_pfnAspNetCoreCreateRequestHandler;
+    if (!g_fAspnetcoreRHLoadedError && FAILED(hr))
+    {
+        g_fAspnetcoreRHLoadedError = TRUE;
+    }
+
+    if (fLocked)
+    {
+        ReleaseSRWLockExclusive(&g_srwLock);
+    }
+    return hr;
+}
+
+HRESULT
+APPLICATION_INFO::FindNativeAssemblyFromGlobalLocation(STRU* struFilename)
+{
+    HRESULT hr = S_OK;
+    DWORD dwSize = MAX_PATH;
+    BOOL  fDone = FALSE;
+    DWORD dwPosition = 0;
+
+    // Though we could call LoadLibrary(L"aspnetcorerh.dll") relying the OS to solve
+    // the path (the targeted dll is the same folder of w3wp.exe/iisexpress)
+    // let's still load with full path to avoid security issue
+    if (FAILED(hr = struFilename->Resize(dwSize + 20)))
+    {
+        goto Finished;
+    }
+
+    while (!fDone)
+    {
+        DWORD dwReturnedSize = GetModuleFileNameW(g_hModule, struFilename->QueryStr(), dwSize);
+        if (dwReturnedSize == 0)
+        {
+            hr = HRESULT_FROM_WIN32(GetLastError());
+            fDone = TRUE;
+            goto Finished;
+        }
+        else if ((dwReturnedSize == dwSize) && (GetLastError() == ERROR_INSUFFICIENT_BUFFER))
+        {
+            dwSize *= 2; // smaller buffer. increase the buffer and retry
+            if (FAILED(hr = struFilename->Resize(dwSize + 20))) // + 20 for aspnetcorerh.dll
+            {
+                goto Finished;
+            }
+        }
+        else
+        {
+            fDone = TRUE;
+        }
+    }
+
+    if (FAILED(hr = struFilename->SyncWithBuffer()))
+    {
+        goto Finished;
+    }
+    dwPosition = struFilename->LastIndexOf(L'\\', 0);
+    struFilename->QueryStr()[dwPosition] = L'\0';
+
+    if (FAILED(hr = struFilename->SyncWithBuffer()) ||
+        FAILED(hr = struFilename->Append(L"\\")) ||
+        FAILED(hr = struFilename->Append(g_pwzAspnetcoreRequestHandlerName)))
+    {
+        goto Finished;
+    }
+
+Finished:
+    return hr;
+}
+
+// 
+// Tries to find aspnetcorerh.dll from the application
+// Calls into hostfxr.dll to find it.
+// Will leave hostfxr.dll loaded as it will be used again to call hostfxr_main.
+// 
+HRESULT
+APPLICATION_INFO::FindNativeAssemblyFromHostfxr(
+    STRU* struFilename
+)
+{
+    HRESULT     hr = S_OK;
+    STRU        struApplicationFullPath;
+    STRU        struNativeSearchPaths;
+    STRU        struNativeDllLocation;
+    HMODULE     hmHostFxrDll = NULL;
+    INT         intHostFxrExitCode = 0;
+    INT         intIndex = -1;
+    INT         intPrevIndex = 0;
+    BOOL        fFound = FALSE;
+    DWORD       dwBufferSize = 1024 * 10;
+    DWORD       dwRequiredBufferSize = 0;
+
+    DBG_ASSERT(struFileName != NULL);
+
+    hmHostFxrDll = LoadLibraryW(m_pConfiguration->QueryHostFxrFullPath());
+
+    if (hmHostFxrDll == NULL)
+    {
+        // Could not load hostfxr
+        hr = HRESULT_FROM_WIN32(GetLastError());
+        goto Finished;
+    }
+
+    hostfxr_get_native_search_directories_fn pFnHostFxrSearchDirectories = (hostfxr_get_native_search_directories_fn)
+        GetProcAddress(hmHostFxrDll, "hostfxr_get_native_search_directories");
+
+    if (pFnHostFxrSearchDirectories == NULL)
+    {
+        // Host fxr version is incorrect (need a higher version).
+        // TODO log error 
+        hr = E_FAIL;
+        goto Finished;
+    }
+
+    if (FAILED(hr = struNativeSearchPaths.Resize(dwBufferSize)))
+    {
+        goto Finished;
+    }
+
+    while (TRUE)
+    {
+        intHostFxrExitCode = pFnHostFxrSearchDirectories(
+            m_pConfiguration->QueryHostFxrArgCount(),
+            m_pConfiguration->QueryHostFxrArguments(),
+            struNativeSearchPaths.QueryStr(),
+            dwBufferSize,
+            &dwRequiredBufferSize
+        );
+
+        if (intHostFxrExitCode == 0)
+        {
+            break;
+        }
+        else if (dwRequiredBufferSize > dwBufferSize)
+        {
+            dwBufferSize = dwRequiredBufferSize + 1; // for null terminator
+
+            if (FAILED(hr = struNativeSearchPaths.Resize(dwBufferSize)))
+            {
+                goto Finished;
+            }
+        }
+        else
+        {
+            hr = E_FAIL;
+            // Log "Error finding native search directories from aspnetcore application.
+            goto Finished;
+        }
+    }
+
+    if (FAILED(hr = struNativeSearchPaths.SyncWithBuffer()))
+    {
+        goto Finished;
+    }
+
+    fFound = FALSE;
+
+    // The native search directories are semicolon delimited.
+    // Split on semicolons, append aspnetcorerh.dll, and check if the file exists.
+    while ((intIndex = struNativeSearchPaths.IndexOf(L";", intPrevIndex)) != -1)
+    {
+        if (FAILED(hr = struNativeDllLocation.Copy(&struNativeSearchPaths.QueryStr()[intPrevIndex], intIndex - intPrevIndex)))
+        {
+            goto Finished;
+        }
+
+        if (!struNativeDllLocation.EndsWith(L"\\"))
+        {
+            if (FAILED(hr = struNativeDllLocation.Append(L"\\")))
+            {
+                goto Finished;
+            }
+        }
+
+        if (FAILED(hr = struNativeDllLocation.Append(g_pwzAspnetcoreRequestHandlerName)))
+        {
+            goto Finished;
+        }
+
+        if (UTILITY::CheckIfFileExists(struNativeDllLocation.QueryStr()))
+        {
+            if (FAILED(hr = struFilename->Copy(struNativeDllLocation)))
+            {
+                goto Finished;
+            }
+            fFound = TRUE;
+            break;
+        }
+
+        intPrevIndex = intIndex + 1;
+    }
+
+    if (!fFound)
+    {
+        hr = E_FAIL;
+        goto Finished;
+    }
+
+Finished:
+    if (FAILED(hr) && hmHostFxrDll != NULL)
+    {
+        FreeLibrary(hmHostFxrDll);
+    }
+    return hr;
+}
+
+VOID
+APPLICATION_INFO::RecycleApplication()
+{
+    APPLICATION* pApplication = NULL;
+    HANDLE       hThread = INVALID_HANDLE_VALUE;
+    BOOL         fLockAcquired = FALSE;
+
+    if (m_pApplication != NULL)
+    {
+        AcquireSRWLockExclusive(&m_srwLock);
+        fLockAcquired = TRUE;
+        if (m_pApplication != NULL)
+        {
+            pApplication = m_pApplication;
+            if (pApplication->QueryConfig()->QueryHostingModel() == HOSTING_OUT_PROCESS)
+            {
+                //
+                // For inprocess, need to set m_pApplication to NULL first to
+                // avoid mapping new request to the recycled application.
+                // Outofprocess application instance will be created for new request
+                // For inprocess, as recycle will lead to shutdown later, leave m_pApplication
+                // to not block incoming requests till worker process shutdown
+                //
+                m_pApplication = NULL;
+            }
+            else
+            {
+                //
+                // For inprocess, need hold the application till shutdown is called
+                // Bump the reference counter as DoRecycleApplication will do dereference
+                //
+                pApplication->ReferenceApplication();
+            }
+
+            hThread = CreateThread(
+                NULL,       // default security attributes
+                0,          // default stack size
+                (LPTHREAD_START_ROUTINE)DoRecycleApplication,
+                pApplication,       // thread function arguments
+                0,          // default creation flags
+                NULL);      // receive thread identifier
+        }
+
+        if (hThread == NULL)
+        {
+            if (!g_fRecycleProcessCalled)
+            {
+                g_fRecycleProcessCalled = TRUE;
+                g_pHttpServer->RecycleProcess(L"On Demand by AspNetCore Module for recycle application failure");
+            }
+        }
+        else 
+        {
+            // Closing a thread handle does not terminate the associated thread or remove the thread object.
+            CloseHandle(hThread);
+        }
+
+        if (fLockAcquired)
+        {
+            ReleaseSRWLockExclusive(&m_srwLock);
+        }
+    }
+}
+
+
+VOID
+APPLICATION_INFO::DoRecycleApplication(
+    LPVOID lpParam)
+{
+    APPLICATION* pApplication = static_cast<APPLICATION*>(lpParam);
+
+    // No lock required
+
+    if (pApplication != NULL)
+    {
+        // Recycle will call shutdown for out of process
+        pApplication->Recycle();
+
+        // Decrement the ref count as we reference it in RecycleApplication.
+        pApplication->DereferenceApplication();
+    }
+}
+
+
+VOID
+APPLICATION_INFO::ShutDownApplication()
+{
+    APPLICATION* pApplication = NULL;
+    BOOL         fLockAcquired = FALSE;
+
+    // pApplication can be NULL due to app_offline
+    if (m_pApplication != NULL)
+    {
+        AcquireSRWLockExclusive(&m_srwLock);
+        fLockAcquired = TRUE;
+        if (m_pApplication != NULL)
+        {
+            pApplication = m_pApplication;
+
+            // Set m_pApplication to NULL first to prevent anyone from using it
+            m_pApplication = NULL;
+            pApplication->ShutDown();
+            pApplication->DereferenceApplication();
+        }
+
+        if (fLockAcquired)
+        {
+            ReleaseSRWLockExclusive(&m_srwLock);
+        }
+    }
+}
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/AspNetCore/src/applicationmanager.cxx b/src/IISIntegration/src/AspNetCoreModuleV2/AspNetCore/src/applicationmanager.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..fd83a19818a9908d5ca1dfbf2af623bc7bd1fe34
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/AspNetCore/src/applicationmanager.cxx
@@ -0,0 +1,458 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#include "precomp.hxx"
+
+// The application manager is a singleton across ANCM.
+APPLICATION_MANAGER* APPLICATION_MANAGER::sm_pApplicationManager = NULL;
+
+//
+// Retrieves the application info from the application manager
+// Will create the application info if it isn't initalized
+//
+HRESULT
+APPLICATION_MANAGER::GetOrCreateApplicationInfo(
+    _In_ IHttpServer*          pServer,
+    _In_ ASPNETCORE_CONFIG*    pConfig,
+    _Out_ APPLICATION_INFO **  ppApplicationInfo
+)
+{
+    HRESULT                hr = S_OK;
+    APPLICATION_INFO      *pApplicationInfo = NULL;
+    APPLICATION_INFO_KEY   key;
+    BOOL                   fExclusiveLock = FALSE;
+    BOOL                   fMixedHostingModelError = FALSE;
+    BOOL                   fDuplicatedInProcessApp = FALSE;
+    PCWSTR                 pszApplicationId = NULL;
+    STACK_STRU ( strEventMsg, 256 );
+
+    DBG_ASSERT(pServer);
+    DBG_ASSERT(pConfig);
+    DBG_ASSERT(ppApplicationInfo);
+
+    *ppApplicationInfo = NULL;
+
+    // The configuration path is unique for each application and is used for the 
+    // key in the applicationInfoHash.
+    pszApplicationId = pConfig->QueryConfigPath()->QueryStr(); 
+    hr = key.Initialize(pszApplicationId);
+    if (FAILED(hr))
+    {
+        goto Finished;
+    }
+
+    // When accessing the m_pApplicationInfoHash, we need to acquire the application manager
+    // lock to avoid races on setting state.
+    AcquireSRWLockShared(&m_srwLock);
+    if (g_fInShutdown)
+    {
+        ReleaseSRWLockShared(&m_srwLock);
+        hr = HRESULT_FROM_WIN32(ERROR_SERVER_SHUTDOWN_IN_PROGRESS);
+        goto Finished;
+    }
+    m_pApplicationInfoHash->FindKey(&key, ppApplicationInfo);
+    ReleaseSRWLockShared(&m_srwLock);
+
+    if (*ppApplicationInfo == NULL)
+    {
+        // Check which hosting model we want to support 
+        switch (pConfig->QueryHostingModel())
+        {
+        case HOSTING_IN_PROCESS:
+            if (m_pApplicationInfoHash->Count() > 0)
+            {
+                // Only one inprocess app is allowed per IIS worker process
+                fDuplicatedInProcessApp = TRUE;
+                hr = HRESULT_FROM_WIN32(ERROR_APP_INIT_FAILURE);
+                goto Finished;
+            }
+            break;
+
+        case HOSTING_OUT_PROCESS:
+            break;
+
+        default:
+            hr = E_UNEXPECTED;
+            goto Finished;
+        }
+        pApplicationInfo = new APPLICATION_INFO(pServer);
+        if (pApplicationInfo == NULL)
+        {
+            hr = E_OUTOFMEMORY;
+            goto Finished;
+        }
+
+        AcquireSRWLockExclusive(&m_srwLock);
+        fExclusiveLock = TRUE;
+        if (g_fInShutdown)
+        {
+            // Already in shuting down. No need to create the application
+            hr = HRESULT_FROM_WIN32(ERROR_SERVER_SHUTDOWN_IN_PROGRESS);
+            goto Finished;
+        }
+        m_pApplicationInfoHash->FindKey(&key, ppApplicationInfo);
+
+        if (*ppApplicationInfo != NULL)
+        {
+            // someone else created the application
+            delete pApplicationInfo;
+            pApplicationInfo = NULL;
+            goto Finished;
+        }
+
+        // hosting model check. We do not allow mixed scenario for now
+        // could be changed in the future
+        if (m_hostingModel != HOSTING_UNKNOWN)
+        {
+            if (m_hostingModel != pConfig->QueryHostingModel())
+            {
+                // hosting model does not match, error out
+                fMixedHostingModelError = TRUE;
+                hr = HRESULT_FROM_WIN32(ERROR_APP_INIT_FAILURE);
+                goto Finished;
+            }
+        }
+
+        hr = pApplicationInfo->Initialize(pConfig, m_pFileWatcher);
+        if (FAILED(hr))
+        {
+            goto Finished;
+        }
+
+        hr = m_pApplicationInfoHash->InsertRecord( pApplicationInfo );
+        if (FAILED(hr))
+        {
+            goto Finished;
+        }
+
+        //
+        // first application will decide which hosting model allowed by this process
+        //
+        if (m_hostingModel == HOSTING_UNKNOWN)
+        {
+            m_hostingModel = pConfig->QueryHostingModel();
+        }
+
+        *ppApplicationInfo = pApplicationInfo;
+        pApplicationInfo->StartMonitoringAppOffline();
+
+        // Release the locko after starting to monitor for app offline to avoid races with it being dropped.
+        ReleaseSRWLockExclusive(&m_srwLock);
+
+        fExclusiveLock = FALSE;
+        pApplicationInfo = NULL;
+    }
+
+Finished:
+
+    if (fExclusiveLock)
+    {
+        ReleaseSRWLockExclusive(&m_srwLock);
+    }
+
+    if (pApplicationInfo != NULL)
+    {
+        pApplicationInfo->DereferenceApplicationInfo();
+        pApplicationInfo = NULL;
+    }
+
+    if (FAILED(hr))
+    {
+        if (fDuplicatedInProcessApp)
+        {
+            if (SUCCEEDED(strEventMsg.SafeSnwprintf(
+                ASPNETCORE_EVENT_DUPLICATED_INPROCESS_APP_MSG,
+                pszApplicationId)))
+            {
+                UTILITY::LogEvent(g_hEventLog,
+                    EVENTLOG_ERROR_TYPE,
+                    ASPNETCORE_EVENT_DUPLICATED_INPROCESS_APP,
+                    strEventMsg.QueryStr());
+            }
+        }
+        else if (fMixedHostingModelError)
+        {
+            if (SUCCEEDED(strEventMsg.SafeSnwprintf(
+                ASPNETCORE_EVENT_MIXED_HOSTING_MODEL_ERROR_MSG,
+                pszApplicationId,
+                pConfig->QueryHostingModel())))
+            {
+                UTILITY::LogEvent(g_hEventLog,
+                    EVENTLOG_ERROR_TYPE,
+                    ASPNETCORE_EVENT_MIXED_HOSTING_MODEL_ERROR,
+                    strEventMsg.QueryStr());
+            }
+        }
+        else
+        {
+            if (SUCCEEDED(strEventMsg.SafeSnwprintf(
+                ASPNETCORE_EVENT_ADD_APPLICATION_ERROR_MSG,
+                pszApplicationId,
+                hr)))
+            {
+                UTILITY::LogEvent(g_hEventLog,
+                    EVENTLOG_ERROR_TYPE,
+                    ASPNETCORE_EVENT_ADD_APPLICATION_ERROR,
+                    strEventMsg.QueryStr());
+            }
+        }
+    }
+
+    return hr;
+}
+
+
+//
+// If the application's configuration was changed,
+// append the configuration path to the config change context.
+//
+BOOL
+APPLICATION_MANAGER::FindConfigChangedApplication(
+    _In_ APPLICATION_INFO *     pEntry,
+    _In_ PVOID                  pvContext)
+{
+    DBG_ASSERT(pEntry);
+    DBG_ASSERT(pvContext);
+
+    // Config Change context contains the original config path that changed
+    // and a multiStr containing 
+    CONFIG_CHANGE_CONTEXT* pContext = static_cast<CONFIG_CHANGE_CONTEXT*>(pvContext);
+    STRU* pstruConfigPath = pEntry->QueryConfig()->QueryConfigPath();
+
+    // check if the application path contains our app/subapp by seeing if the config path
+    // starts with the notification path.
+    BOOL fChanged = pstruConfigPath->StartsWith(pContext->pstrPath, true);
+    if (fChanged)
+    {
+        DWORD dwLen = (DWORD)wcslen(pContext->pstrPath);
+        WCHAR wChar = pstruConfigPath->QueryStr()[dwLen];
+
+        // We need to check that the last character of the config path
+        // is either a null terminator or a slash.
+        // This checks the case where the config path was
+        // MACHINE/WEBROOT/site and your site path is MACHINE/WEBROOT/siteTest
+        if (wChar != L'\0' && wChar != L'/')
+        {
+            // not current app or sub app
+            fChanged = FALSE;
+        }
+        else
+        {
+            pContext->MultiSz.Append(*pstruConfigPath);
+        }
+    }
+    return fChanged;
+}
+
+//
+// Finds any applications affected by a configuration change and calls Recycle on them
+// InProcess:  Triggers g_httpServer->RecycleProcess() and keep the application inside of the manager.
+//             This will cause a shutdown event to occur through the global stop listening event.
+// OutOfProcess: Removes all applications in the application manager and calls Recycle, which will call Shutdown,
+//             on each application.
+// 
+HRESULT
+APPLICATION_MANAGER::RecycleApplicationFromManager(
+    _In_ LPCWSTR pszApplicationId
+)
+{
+    HRESULT                 hr = S_OK;
+    APPLICATION_INFO_KEY    key;
+    DWORD                   dwPreviousCounter = 0;
+    APPLICATION_INFO_HASH*  table = NULL;
+    CONFIG_CHANGE_CONTEXT   context;
+    BOOL                    fKeepTable = FALSE;
+
+    if (g_fInShutdown)
+    {
+        // We are already shutting down, ignore this event as a global configuration change event
+        // can occur after global stop listening for some reason.
+        return hr;
+    }
+
+    AcquireSRWLockExclusive(&m_srwLock);
+    if (g_fInShutdown)
+    {
+        ReleaseSRWLockExclusive(&m_srwLock);
+        return hr;
+    }
+
+    hr = key.Initialize(pszApplicationId);
+    if (FAILED(hr))
+    {
+        goto Finished;
+    }
+    // Make a shallow copy of existing hashtable as we may need to remove nodes
+    // This will be used for finding differences in which applications are affected by a config change.
+    table = new APPLICATION_INFO_HASH();
+
+    if (table == NULL)
+    {
+        hr = E_OUTOFMEMORY;
+        goto Finished;
+    }
+
+    // few application expected, small bucket size for hash table
+    if (FAILED(hr = table->Initialize(17 /*prime*/)))
+    {
+        goto Finished;
+    }
+
+    context.pstrPath = pszApplicationId;
+
+    // Keep track of the preview count of applications to know whether there are applications to delete
+    dwPreviousCounter = m_pApplicationInfoHash->Count();
+
+    // We don't want to hold the application manager lock for long time as it will block all incoming requests
+    // Don't call application shutdown inside the lock
+    m_pApplicationInfoHash->Apply(APPLICATION_INFO_HASH::ReferenceCopyToTable, static_cast<PVOID>(table));
+    DBG_ASSERT(dwPreviousCounter == table->Count());
+    
+    // Removed the applications which are impacted by the configurtion change
+    m_pApplicationInfoHash->DeleteIf(FindConfigChangedApplication, (PVOID)&context);
+
+    if (dwPreviousCounter != m_pApplicationInfoHash->Count())
+    {
+        if (m_hostingModel == HOSTING_IN_PROCESS)
+        {
+            // When we are inprocess, we need to keep the application the
+            // application manager that is being deleted. This is because we will always need to recycle the worker
+            // process and any requests that hit this worker process must be rejected (while out of process can
+            // start a new dotnet process). We will immediately call Recycle after this call.
+            DBG_ASSERT(m_pApplicationInfoHash->Count() == 0);
+            delete m_pApplicationInfoHash;
+
+            // We don't want to delete the table as m_pApplicationInfoHash = table
+            fKeepTable = TRUE;
+            m_pApplicationInfoHash = table;
+        }
+    }
+
+    if (m_pApplicationInfoHash->Count() == 0)
+    {
+        m_hostingModel = HOSTING_UNKNOWN;
+    }
+
+    ReleaseSRWLockExclusive(&m_srwLock);
+
+    // If we receive a request at this point.
+    // OutOfProcess: we will create a new application with new configuration
+    // InProcess: the request would have to be rejected, as we are about to call g_HttpServer->RecycleProcess
+    // on the worker proocess
+    if (!context.MultiSz.IsEmpty())
+    {
+        PCWSTR path = context.MultiSz.First();
+        // Iterate through each of the paths that were shut down,
+        // calling RecycleApplication on each of them.
+        while (path != NULL)
+        {
+            APPLICATION_INFO* pRecord;
+
+            // Application got recycled. Log an event
+            STACK_STRU(strEventMsg, 256);
+            if (SUCCEEDED(strEventMsg.SafeSnwprintf(
+                ASPNETCORE_EVENT_RECYCLE_CONFIGURATION_MSG,
+                path)))
+            {
+                UTILITY::LogEvent(g_hEventLog,
+                    EVENTLOG_INFORMATION_TYPE,
+                    ASPNETCORE_EVENT_RECYCLE_CONFIGURATION,
+                    strEventMsg.QueryStr());
+            }
+
+            hr = key.Initialize(path);
+            if (FAILED(hr))
+            {
+                goto Finished;
+            }
+
+            table->FindKey(&key, &pRecord);
+            DBG_ASSERT(pRecord != NULL);
+
+            // RecycleApplication is called on a separate thread. 
+            pRecord->RecycleApplication();
+            pRecord->DereferenceApplicationInfo();
+            path = context.MultiSz.Next(path);
+        }
+    }
+
+Finished:
+    if (table != NULL && !fKeepTable)
+    {
+        table->Clear();
+        delete table;
+    }
+
+    if (FAILED(hr))
+    {
+        // Failed to recycle an application. Log an event
+        STACK_STRU(strEventMsg, 256);
+        if  (SUCCEEDED(strEventMsg.SafeSnwprintf(
+                ASPNETCORE_EVENT_RECYCLE_FAILURE_CONFIGURATION_MSG,
+                pszApplicationId)))
+        {
+            UTILITY::LogEvent(g_hEventLog,
+                EVENTLOG_ERROR_TYPE,
+                ASPNETCORE_EVENT_RECYCLE_APP_FAILURE,
+                strEventMsg.QueryStr());
+        }
+        // Need to recycle the process as we cannot recycle the application
+        if (!g_fRecycleProcessCalled)
+        {
+            g_fRecycleProcessCalled = TRUE;
+            g_pHttpServer->RecycleProcess(L"AspNetCore Recycle Process on Demand Due Application Recycle Error");
+        }
+    }
+
+    return hr;
+}
+
+//
+// Shutsdown all applications in the application hashtable
+// Only called by OnGlobalStopListening.
+// 
+VOID
+APPLICATION_MANAGER::ShutDown()
+{
+    // We are guaranteed to only have one outstanding OnGlobalStopListening event at a time
+    // However, it is possible to receive multiple OnGlobalStopListening events
+    // Protect against this by checking if we already shut down.
+    g_fInShutdown = TRUE;
+    if (m_pApplicationInfoHash != NULL)
+    {
+        if (m_pFileWatcher != NULL)
+        {
+            delete  m_pFileWatcher;
+            m_pFileWatcher = NULL;
+        }
+
+        DBG_ASSERT(m_pApplicationInfoHash);
+        // During shutdown we lock until we delete the application 
+        AcquireSRWLockExclusive(&m_srwLock);
+
+        // Call shutdown on each application in the application manager
+        m_pApplicationInfoHash->Apply(ShutdownApplication, NULL);
+        m_pApplicationInfoHash->Clear();
+        delete m_pApplicationInfoHash;
+        m_pApplicationInfoHash = NULL;
+
+        ReleaseSRWLockExclusive(&m_srwLock);
+    }
+}
+
+//
+// Calls shutdown on each application. ApplicationManager's lock is held for duration of
+// each shutdown call, guaranteeing another application cannot be created.
+//
+// static
+VOID
+APPLICATION_MANAGER::ShutdownApplication(
+    _In_ APPLICATION_INFO *     pEntry,
+    _In_ PVOID                  pvContext
+)
+{
+    UNREFERENCED_PARAMETER(pvContext);
+    DBG_ASSERT(pEntry != NULL);
+
+    pEntry->ShutDownApplication();
+}
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/AspNetCore/src/dllmain.cpp b/src/IISIntegration/src/AspNetCoreModuleV2/AspNetCore/src/dllmain.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..2e4f87e542e035e6bfb8a5de47659af045a28fcd
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/AspNetCore/src/dllmain.cpp
@@ -0,0 +1,254 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#include "precomp.hxx"
+#include <IPHlpApi.h>
+
+HTTP_MODULE_ID      g_pModuleId = NULL;
+IHttpServer *       g_pHttpServer = NULL;
+HANDLE              g_hEventLog = NULL;
+BOOL                g_fRecycleProcessCalled = FALSE;
+PCWSTR              g_pszModuleName = NULL;
+HINSTANCE           g_hModule;
+HMODULE             g_hAspnetCoreRH = NULL;
+BOOL                g_fAspnetcoreRHAssemblyLoaded = FALSE;
+BOOL                g_fAspnetcoreRHLoadedError = FALSE;
+BOOL                g_fInShutdown = FALSE;
+DWORD               g_dwAspNetCoreDebugFlags = 0;
+DWORD               g_dwActiveServerProcesses = 0;
+SRWLOCK             g_srwLock;
+DWORD               g_dwDebugFlags = 0;
+PCSTR               g_szDebugLabel = "ASPNET_CORE_MODULE";
+PCWSTR              g_pwzAspnetcoreRequestHandlerName = L"aspnetcorerh.dll";
+PFN_ASPNETCORE_CREATE_APPLICATION      g_pfnAspNetCoreCreateApplication;
+PFN_ASPNETCORE_CREATE_REQUEST_HANDLER  g_pfnAspNetCoreCreateRequestHandler;
+
+VOID
+StaticCleanup()
+{
+    APPLICATION_MANAGER::Cleanup();
+    if (g_hEventLog != NULL)
+    {
+        DeregisterEventSource(g_hEventLog);
+        g_hEventLog = NULL;
+    }
+}
+
+BOOL WINAPI DllMain(HMODULE hModule,
+    DWORD  ul_reason_for_call,
+    LPVOID lpReserved
+    )
+{
+    UNREFERENCED_PARAMETER(lpReserved);
+
+    switch (ul_reason_for_call)
+    {
+    case DLL_PROCESS_ATTACH:
+        g_hModule = hModule;
+        DisableThreadLibraryCalls(hModule);
+        break;
+    case DLL_PROCESS_DETACH:
+        // IIS can cause dll detach to occur before we receive global notifications
+        // For example, when we switch the bitness of the worker process, 
+        // this is a bug in IIS. To try to avoid AVs, we will set a global flag
+        g_fInShutdown = TRUE;
+        StaticCleanup();
+    default:
+        break;
+    }
+
+    return TRUE;
+}
+
+HRESULT
+__stdcall
+RegisterModule(
+DWORD                           dwServerVersion,
+IHttpModuleRegistrationInfo *   pModuleInfo,
+IHttpServer *                   pHttpServer
+)
+/*++
+
+Routine description:
+
+Function called by IIS immediately after loading the module, used to let
+IIS know what notifications the module is interested in
+
+Arguments:
+
+dwServerVersion - IIS version the module is being loaded on
+pModuleInfo - info regarding this module
+pHttpServer - callback functions which can be used by the module at
+any point
+
+Return value:
+
+HRESULT
+
+--*/
+{
+    HRESULT                             hr = S_OK;
+    HKEY                                hKey;
+    BOOL                                fDisableANCM = FALSE;
+    ASPNET_CORE_PROXY_MODULE_FACTORY *  pFactory = NULL;
+    ASPNET_CORE_GLOBAL_MODULE *         pGlobalModule = NULL;
+    APPLICATION_MANAGER *               pApplicationManager = NULL;
+
+    UNREFERENCED_PARAMETER(dwServerVersion);
+
+#ifdef DEBUG
+    CREATE_DEBUG_PRINT_OBJECT("Asp.Net Core Module");
+    g_dwDebugFlags = DEBUG_FLAGS_ANY;
+#endif // DEBUG
+
+    CREATE_DEBUG_PRINT_OBJECT;
+
+    //LoadGlobalConfiguration();
+
+    InitializeSRWLock(&g_srwLock);
+
+    g_pModuleId = pModuleInfo->GetId();
+    g_pszModuleName = pModuleInfo->GetName();
+    g_pHttpServer = pHttpServer;
+
+    if (g_pHttpServer->IsCommandLineLaunch())
+    {
+        g_hEventLog = RegisterEventSource(NULL, ASPNETCORE_IISEXPRESS_EVENT_PROVIDER);
+    }
+    else
+    {
+        g_hEventLog = RegisterEventSource(NULL, ASPNETCORE_EVENT_PROVIDER);
+    }
+
+    // check whether the feature is disabled due to security reason
+    if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
+        L"SOFTWARE\\Microsoft\\IIS Extensions\\IIS AspNetCore Module\\Parameters",
+        0,
+        KEY_READ,
+        &hKey) == NO_ERROR)
+    {
+        DWORD dwType;
+        DWORD dwData;
+        DWORD cbData;
+
+        cbData = sizeof(dwData);
+        if ((RegQueryValueEx(hKey,
+            L"DisableANCM",
+            NULL,
+            &dwType,
+            (LPBYTE)&dwData,
+            &cbData) == NO_ERROR) &&
+            (dwType == REG_DWORD))
+        {
+            fDisableANCM = (dwData != 0);
+        }
+
+        cbData = sizeof(dwData);
+        if ((RegQueryValueEx(hKey,
+            L"DebugFlags",
+            NULL,
+            &dwType,
+            (LPBYTE)&dwData,
+            &cbData) == NO_ERROR) &&
+            (dwType == REG_DWORD))
+        {
+            g_dwAspNetCoreDebugFlags = dwData;
+        }
+
+        RegCloseKey(hKey);
+    }
+
+    if (fDisableANCM)
+    {
+        // Logging
+        STACK_STRU(strEventMsg, 256);
+        if (SUCCEEDED(strEventMsg.SafeSnwprintf(
+            ASPNETCORE_EVENT_MODULE_DISABLED_MSG)))
+        {
+            UTILITY::LogEvent(g_hEventLog,
+                              EVENTLOG_WARNING_TYPE,
+                              ASPNETCORE_EVENT_MODULE_DISABLED,
+                              strEventMsg.QueryStr());
+        }
+        // this will return 500 error to client
+        // as we did not register the module
+        goto Finished;
+    }
+
+    //
+    // Create the factory before any static initialization.
+    // The ASPNET_CORE_PROXY_MODULE_FACTORY::Terminate method will clean any
+    // static object initialized.
+    //
+    pFactory = new ASPNET_CORE_PROXY_MODULE_FACTORY;
+
+    if (pFactory == NULL)
+    {
+        hr = E_OUTOFMEMORY;
+        goto Finished;
+    }
+
+    hr = pModuleInfo->SetRequestNotifications(
+                                  pFactory,
+                                  RQ_EXECUTE_REQUEST_HANDLER,
+                                  0);
+    if (FAILED(hr))
+    {
+        goto Finished;
+    }
+
+    pFactory = NULL;
+    pApplicationManager = APPLICATION_MANAGER::GetInstance();
+    if(pApplicationManager == NULL)
+    {
+        hr = E_OUTOFMEMORY;
+        goto Finished;
+    }
+    
+    hr = pApplicationManager->Initialize();
+    if(FAILED(hr))
+     {
+        goto Finished;
+    }
+    pGlobalModule = NULL;
+
+    pGlobalModule = new ASPNET_CORE_GLOBAL_MODULE(pApplicationManager);
+    if (pGlobalModule == NULL)
+    {
+        hr = E_OUTOFMEMORY;
+        goto Finished;
+    }
+
+    hr = pModuleInfo->SetGlobalNotifications(
+                              pGlobalModule,
+                              GL_CONFIGURATION_CHANGE | // Configuration change trigers IIS application stop
+                              GL_STOP_LISTENING);   // worker process stop or recycle
+
+    if (FAILED(hr))
+    {
+        goto Finished;
+    }
+    pGlobalModule = NULL;
+
+    hr = ALLOC_CACHE_HANDLER::StaticInitialize();
+    if (FAILED(hr))
+    {
+        goto Finished;
+    }
+
+Finished:
+    if (pGlobalModule != NULL)
+    {
+        delete pGlobalModule;
+        pGlobalModule = NULL;
+    }
+
+    if (pFactory != NULL)
+    {
+        pFactory->Terminate();
+        pFactory = NULL;
+    }
+
+    return hr;
+}
+
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/AspNetCore/src/filewatcher.cxx b/src/IISIntegration/src/AspNetCoreModuleV2/AspNetCore/src/filewatcher.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..4d3174937f0229fe2a68ffa801a58c31ac04584b
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/AspNetCore/src/filewatcher.cxx
@@ -0,0 +1,497 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#include "precomp.hxx"
+
+FILE_WATCHER::FILE_WATCHER() :
+    m_hCompletionPort(NULL),
+    m_hChangeNotificationThread(NULL),
+    m_fThreadExit(FALSE)
+{
+}
+
+FILE_WATCHER::~FILE_WATCHER()
+{
+    if (m_hChangeNotificationThread != NULL)
+    {
+        DWORD dwRetryCounter = 20;      // totally wait for 1s
+        DWORD dwExitCode = STILL_ACTIVE;
+
+        // signal the file watch thread to exit
+        PostQueuedCompletionStatus(m_hCompletionPort, 0, FILE_WATCHER_SHUTDOWN_KEY, NULL);
+        while (!m_fThreadExit && dwRetryCounter > 0)
+        {
+            if (GetExitCodeThread(m_hChangeNotificationThread, &dwExitCode))
+            {
+                if (dwExitCode == STILL_ACTIVE)
+                {
+                    // the file watcher thread will set m_fThreadExit before exit
+                    WaitForSingleObject(m_hChangeNotificationThread, 50);
+                }
+            }
+            else
+            {
+                // fail to get thread status
+                // call terminitethread
+                TerminateThread(m_hChangeNotificationThread, 1);
+                m_fThreadExit = TRUE;
+            }
+            dwRetryCounter--;
+        }
+
+        if (!m_fThreadExit)
+        {
+            TerminateThread(m_hChangeNotificationThread, 1);
+        }
+
+        CloseHandle(m_hChangeNotificationThread);
+        m_hChangeNotificationThread = NULL;
+    }
+
+    if (NULL != m_hCompletionPort)
+    {
+        CloseHandle(m_hCompletionPort);
+        m_hCompletionPort = NULL;
+    }
+}
+
+HRESULT
+FILE_WATCHER::Create(
+    VOID
+)
+{
+    HRESULT                 hr = S_OK;
+
+    m_hCompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE,
+        NULL,
+        0,
+        0);
+
+    if (m_hCompletionPort == NULL)
+    {
+        hr = HRESULT_FROM_WIN32(GetLastError());
+        goto Finished;
+    }
+
+    m_hChangeNotificationThread = CreateThread(NULL,
+        0,
+        ChangeNotificationThread,
+        this,
+        0,
+        NULL);
+
+    if (m_hChangeNotificationThread == NULL)
+    {
+        hr = HRESULT_FROM_WIN32(GetLastError());
+
+        CloseHandle(m_hCompletionPort);
+        m_hCompletionPort = NULL;
+
+        goto Finished;
+    }
+
+Finished:
+    return hr;
+}
+
+DWORD
+WINAPI
+FILE_WATCHER::ChangeNotificationThread(
+    LPVOID  pvArg
+)
+/*++
+
+Routine Description:
+
+IO completion thread
+
+Arguments:
+
+None
+
+Return Value:
+
+Win32 error
+
+--*/
+{
+    FILE_WATCHER *       pFileMonitor;
+    BOOL                 fSuccess = FALSE;
+    DWORD                cbCompletion = 0;
+    OVERLAPPED *         pOverlapped = NULL;
+    DWORD                dwErrorStatus;
+    ULONG_PTR            completionKey;
+
+    pFileMonitor = (FILE_WATCHER*)pvArg;
+    DBG_ASSERT(pFileMonitor != NULL);
+
+    while (TRUE)
+    {
+        fSuccess = GetQueuedCompletionStatus(
+            pFileMonitor->m_hCompletionPort,
+            &cbCompletion,
+            &completionKey,
+            &pOverlapped,
+            INFINITE);
+
+        DBG_ASSERT(fSuccess);
+        dwErrorStatus = fSuccess ? ERROR_SUCCESS : GetLastError();
+
+        if (completionKey == FILE_WATCHER_SHUTDOWN_KEY)
+        {
+            break;
+        }
+
+        DBG_ASSERT(pOverlapped != NULL);
+        if (pOverlapped != NULL)
+        {
+            FileWatcherCompletionRoutine(
+                dwErrorStatus,
+                cbCompletion,
+                pOverlapped);
+        }
+        pOverlapped = NULL;
+        cbCompletion = 0;
+    }
+
+    pFileMonitor->m_fThreadExit = TRUE;
+    ExitThread(0);
+}
+
+VOID
+WINAPI
+FILE_WATCHER::FileWatcherCompletionRoutine(
+    DWORD                   dwCompletionStatus,
+    DWORD                   cbCompletion,
+    OVERLAPPED *            pOverlapped
+)
+/*++
+
+Routine Description:
+
+Called when ReadDirectoryChangesW() completes
+
+Arguments:
+
+dwCompletionStatus - Error of completion
+cbCompletion - Bytes of completion
+pOverlapped - State of completion
+
+Return Value:
+
+None
+
+--*/
+{
+    FILE_WATCHER_ENTRY *     pMonitorEntry;
+    pMonitorEntry = CONTAINING_RECORD(pOverlapped, FILE_WATCHER_ENTRY, _overlapped);
+
+    DBG_ASSERT(pMonitorEntry != NULL);
+
+    pMonitorEntry->HandleChangeCompletion(dwCompletionStatus, cbCompletion);
+
+    if (pMonitorEntry->QueryIsValid())
+    {
+        //
+        // Continue monitoring
+        //
+        pMonitorEntry->Monitor();
+    }
+    //
+    // Deference the counter not matter whether the monitor is valid
+    // Valid: Monitor increases the counter, need to reduce one
+    // InValid: Reduce the counter to free the entry
+    //
+    pMonitorEntry->DereferenceFileWatcherEntry();
+
+}
+
+
+FILE_WATCHER_ENTRY::FILE_WATCHER_ENTRY(FILE_WATCHER *   pFileMonitor) :
+    _pFileMonitor(pFileMonitor),
+    _hDirectory(INVALID_HANDLE_VALUE),
+    _hImpersonationToken(NULL),
+    _pApplicationInfo(NULL),
+    _lStopMonitorCalled(0),
+    _cRefs(1),
+    _fIsValid(TRUE)
+{
+    _dwSignature = FILE_WATCHER_ENTRY_SIGNATURE;
+    InitializeSRWLock(&_srwLock);
+}
+
+FILE_WATCHER_ENTRY::~FILE_WATCHER_ENTRY()
+{
+    _dwSignature = FILE_WATCHER_ENTRY_SIGNATURE_FREE;
+
+    if (_hDirectory != INVALID_HANDLE_VALUE)
+    {
+        CloseHandle(_hDirectory);
+        _hDirectory = INVALID_HANDLE_VALUE;
+    }
+
+    if (_hImpersonationToken != NULL)
+    {
+        CloseHandle(_hImpersonationToken);
+        _hImpersonationToken = NULL;
+    }
+}
+
+#pragma warning(disable:4100)
+
+HRESULT
+FILE_WATCHER_ENTRY::HandleChangeCompletion(
+    _In_ DWORD          dwCompletionStatus,
+    _In_ DWORD          cbCompletion
+)
+/*++
+
+Routine Description:
+
+Handle change notification (see if any of associated config files
+need to be flushed)
+
+Arguments:
+
+dwCompletionStatus - Completion status
+cbCompletion - Bytes of completion
+
+Return Value:
+
+HRESULT
+
+--*/
+{
+    HRESULT                     hr = S_OK;
+    FILE_NOTIFY_INFORMATION *   pNotificationInfo;
+    BOOL                        fFileChanged = FALSE;
+
+    AcquireSRWLockExclusive(&_srwLock);
+    if (!_fIsValid)
+    {
+        goto Finished;
+    }
+
+    // When directory handle is closed then HandleChangeCompletion  
+    // happens with cbCompletion = 0 and dwCompletionStatus = 0  
+    // From documentation it is not clear if that combination  
+    // of return values is specific to closing handles or whether  
+    // it could also mean an error condition. Hence we will maintain  
+    // explicit flag that will help us determine if entry
+    // is being shutdown (StopMonitor() called)
+    //
+    if (_lStopMonitorCalled)
+    {
+        goto Finished;
+    }
+
+    //
+    // There could be a FCN overflow
+    // Let assume the file got changed instead of checking files 
+    // Othersie we have to cache the file info 
+    //
+    if (cbCompletion == 0)
+    {
+        fFileChanged = TRUE;
+    }
+    else
+    {
+        pNotificationInfo = (FILE_NOTIFY_INFORMATION*)_buffDirectoryChanges.QueryPtr();
+        DBG_ASSERT(pNotificationInfo != NULL);
+
+        while (pNotificationInfo != NULL)
+        {
+            //
+            // check whether the monitored file got changed
+            //
+            if (_wcsnicmp(pNotificationInfo->FileName,
+                _strFileName.QueryStr(),
+                pNotificationInfo->FileNameLength / sizeof(WCHAR)) == 0)
+            {
+                fFileChanged = TRUE;
+                break;
+            }
+            //
+            // Advance to next notification
+            //
+            if (pNotificationInfo->NextEntryOffset == 0)
+            {
+                pNotificationInfo = NULL;
+            }
+            else
+            {
+                pNotificationInfo = (FILE_NOTIFY_INFORMATION*)
+                    ((PBYTE)pNotificationInfo +
+                        pNotificationInfo->NextEntryOffset);
+            }
+        }
+    }
+
+    if (fFileChanged)
+    {
+        //
+        // so far we only monitoring app_offline
+        //
+        _pApplicationInfo->UpdateAppOfflineFileHandle();
+    }
+
+Finished:
+    ReleaseSRWLockExclusive(&_srwLock);
+    return hr;
+}
+
+#pragma warning( error : 4100 )
+
+HRESULT
+FILE_WATCHER_ENTRY::Monitor(VOID)
+{
+    HRESULT hr = S_OK;
+    DWORD   cbRead;
+
+    AcquireSRWLockExclusive(&_srwLock);
+    ReferenceFileWatcherEntry();
+    ZeroMemory(&_overlapped, sizeof(_overlapped));
+
+    if (!ReadDirectoryChangesW(_hDirectory,
+        _buffDirectoryChanges.QueryPtr(),
+        _buffDirectoryChanges.QuerySize(),
+        FALSE,        // Watching sub dirs. Set to False now as only monitoring app_offline
+        FILE_NOTIFY_VALID_MASK & ~FILE_NOTIFY_CHANGE_LAST_ACCESS,
+        &cbRead,
+        &_overlapped,
+        NULL))
+    {
+        hr = HRESULT_FROM_WIN32(GetLastError());
+        DereferenceFileWatcherEntry();
+    }
+
+    ReleaseSRWLockExclusive(&_srwLock);
+    return hr;
+}
+
+VOID
+FILE_WATCHER_ENTRY::StopMonitor(VOID)
+{
+    //
+    // Flag that monitoring is being stopped so that
+    // we know that HandleChangeCompletion() call
+    // can be ignored
+    //
+    InterlockedExchange(&_lStopMonitorCalled, 1);
+
+    if (_hDirectory != INVALID_HANDLE_VALUE)
+    {
+        AcquireSRWLockExclusive(&_srwLock);
+        if (_hDirectory != INVALID_HANDLE_VALUE)
+        {
+            CloseHandle(_hDirectory);
+            _hDirectory = INVALID_HANDLE_VALUE;
+            DereferenceFileWatcherEntry();
+        }
+        ReleaseSRWLockExclusive(&_srwLock);
+    }
+}
+
+HRESULT
+FILE_WATCHER_ENTRY::Create(
+    _In_ PCWSTR                  pszDirectoryToMonitor,
+    _In_ PCWSTR                  pszFileNameToMonitor,
+    _In_ APPLICATION_INFO*       pApplicationInfo,
+    _In_ HANDLE                  hImpersonationToken
+)
+{
+    HRESULT             hr = S_OK;
+    BOOL                fRet = FALSE;
+
+    if (pszDirectoryToMonitor == NULL ||
+        pszFileNameToMonitor == NULL ||
+        pApplicationInfo == NULL)
+    {
+        DBG_ASSERT(FALSE);
+        hr = HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
+        goto Finished;
+    }
+
+    //
+    //remember the application
+    //
+    _pApplicationInfo = pApplicationInfo;
+
+    if (FAILED(hr = _strFileName.Copy(pszFileNameToMonitor)))
+    {
+        goto Finished;
+    }
+
+    if (FAILED(hr = _strDirectoryName.Copy(pszDirectoryToMonitor)))
+    {
+        goto Finished;
+    }
+
+    //
+    // Resize change buffer to something "reasonable"
+    //
+    if (!_buffDirectoryChanges.Resize(FILE_WATCHER_ENTRY_BUFFER_SIZE))
+    {
+        hr = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
+        goto Finished;
+    }
+
+    if (hImpersonationToken != NULL)
+    {
+        fRet = DuplicateHandle(GetCurrentProcess(),
+            hImpersonationToken,
+            GetCurrentProcess(),
+            &_hImpersonationToken,
+            0,
+            FALSE,
+            DUPLICATE_SAME_ACCESS);
+
+        if (!fRet)
+        {
+            hr = HRESULT_FROM_WIN32(GetLastError());
+            goto Finished;
+        }
+    }
+    else
+    {
+        if (_hImpersonationToken != NULL)
+        {
+            CloseHandle(_hImpersonationToken);
+            _hImpersonationToken = NULL;
+        }
+    }
+
+    _hDirectory = CreateFileW(
+        _strDirectoryName.QueryStr(),
+        FILE_LIST_DIRECTORY,
+        FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+        NULL,
+        OPEN_EXISTING,
+        FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED,
+        NULL);
+
+    if (_hDirectory == INVALID_HANDLE_VALUE)
+    {
+        hr = HRESULT_FROM_WIN32(GetLastError());
+        goto Finished;
+    }
+
+    if (CreateIoCompletionPort(
+        _hDirectory,
+        _pFileMonitor->QueryCompletionPort(),
+        NULL,
+        0) == NULL)
+    {
+        hr = HRESULT_FROM_WIN32(GetLastError());
+        goto Finished;
+    }
+
+    //
+    // Start monitoring
+    //
+    hr = Monitor();
+
+Finished:
+
+    return hr;
+}
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/AspNetCore/src/globalmodule.cpp b/src/IISIntegration/src/AspNetCoreModuleV2/AspNetCore/src/globalmodule.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..f4c6257bb486f95eeb58b35e3400d5d74e7fee9c
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/AspNetCore/src/globalmodule.cpp
@@ -0,0 +1,65 @@
+#include "precomp.hxx"
+
+ASPNET_CORE_GLOBAL_MODULE::ASPNET_CORE_GLOBAL_MODULE(
+    APPLICATION_MANAGER* pApplicationManager)
+{
+    m_pApplicationManager = pApplicationManager;
+}
+
+//
+// Is called when IIS decided to terminate worker process
+// Shut down all core apps
+//
+GLOBAL_NOTIFICATION_STATUS
+ASPNET_CORE_GLOBAL_MODULE::OnGlobalStopListening(
+    _In_ IGlobalStopListeningProvider * pProvider
+)
+{
+    UNREFERENCED_PARAMETER(pProvider);
+
+    if (g_fInShutdown)
+    {
+        // Avoid receiving two shutudown notifications.
+        return GL_NOTIFICATION_CONTINUE;
+    }
+
+    DBG_ASSERT(m_pApplicationManager);
+    // we should let application manager to shutdown all allication
+    // and dereference it as some requests may still reference to application manager
+    m_pApplicationManager->ShutDown();
+    m_pApplicationManager = NULL;
+
+    // Return processing to the pipeline.
+    return GL_NOTIFICATION_CONTINUE;
+}
+
+//
+// Is called when configuration changed
+// Recycled the corresponding core app if its configuration changed
+//
+GLOBAL_NOTIFICATION_STATUS
+ASPNET_CORE_GLOBAL_MODULE::OnGlobalConfigurationChange(
+    _In_ IGlobalConfigurationChangeProvider * pProvider
+)
+{
+    if (g_fInShutdown)
+    {
+        return GL_NOTIFICATION_CONTINUE;
+    }
+    // Retrieve the path that has changed.
+    PCWSTR pwszChangePath = pProvider->GetChangePath();
+
+    // Test for an error.
+    if (NULL != pwszChangePath &&
+        _wcsicmp(pwszChangePath, L"MACHINE") != 0 &&
+        _wcsicmp(pwszChangePath, L"MACHINE/WEBROOT") != 0)
+    {
+        if (m_pApplicationManager != NULL)
+        {
+            m_pApplicationManager->RecycleApplicationFromManager(pwszChangePath);
+        }
+    }
+
+    // Return processing to the pipeline.
+    return GL_NOTIFICATION_CONTINUE;
+}
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/AspNetCore/src/precomp.hxx b/src/IISIntegration/src/AspNetCoreModuleV2/AspNetCore/src/precomp.hxx
new file mode 100644
index 0000000000000000000000000000000000000000..574244ba356c780da0ce2c0ed608f438fe6f0472
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/AspNetCore/src/precomp.hxx
@@ -0,0 +1,159 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#pragma once
+#pragma warning( disable : 4091)
+
+//
+// System related headers
+//
+#define _WINSOCKAPI_
+
+#define NTDDI_VERSION 0x06010000
+#define WINVER 0x0601
+#define _WIN32_WINNT 0x0601
+
+#include <windows.h>
+#include <atlbase.h>
+#include <pdh.h>
+
+//#include <ntassert.h>
+#include <Shlobj.h>
+#include <httpserv.h>
+
+// This should remove our issue of compiling for win7 without header files.
+// We  force the Windows 8 version check logic in iiswebsocket.h to succeed even though we're compiling for Windows 7.
+// Then, we set the version defines back to Windows 7 to for the remainder of the compilation.
+#undef NTDDI_VERSION
+#undef WINVER
+#undef _WIN32_WINNT
+#define NTDDI_VERSION 0x06020000
+#define WINVER 0x0602
+#define _WIN32_WINNT 0x0602
+#include <iiswebsocket.h>
+#undef NTDDI_VERSION
+#undef WINVER
+#undef _WIN32_WINNT
+
+#define NTDDI_VERSION 0x06010000
+#define WINVER 0x0601
+#define _WIN32_WINNT 0x0601
+
+#include <httptrace.h>
+#include <winhttp.h>
+
+#include <cstdlib>
+#include <vector>
+#include <wchar.h>
+
+//
+// Option available starting Windows 8.
+// 111 is the value in SDK on May 15, 2012.
+//
+#ifndef WINHTTP_OPTION_ASSURED_NON_BLOCKING_CALLBACKS
+#define WINHTTP_OPTION_ASSURED_NON_BLOCKING_CALLBACKS 111
+#endif
+
+#ifdef max
+#undef max
+template<typename T> inline T max(T a, T b)
+{
+    return a > b ? a : b;
+}
+#endif
+
+#ifdef min
+#undef min
+template<typename T> inline T min(T a, T b)
+{
+    return a < b ? a : b;
+}
+#endif
+
+inline bool IsSpace(char ch)
+{
+    switch(ch)
+    {
+    case 32: // ' '
+    case 9:  // '\t'
+    case 10: // '\n'
+    case 13: // '\r'
+    case 11: // '\v'
+    case 12: // '\f'
+        return true;
+    default:
+        return false;
+    }
+}
+
+#include <hashfn.h>
+#include <hashtable.h>
+#include "stringa.h"
+#include "stringu.h"
+#include "dbgutil.h"
+#include "ahutil.h"
+#include "multisz.h"
+#include "multisza.h"
+#include "base64.h"
+#include <listentry.h>
+#include <datetime.h>
+#include <reftrace.h>
+#include <acache.h>
+#include <time.h>
+
+#include "..\..\CommonLib\environmentvariablehash.h"
+#include "..\..\CommonLib\aspnetcoreconfig.h"
+#include "..\..\CommonLib\hostfxr_utility.h"
+#include "..\..\CommonLib\application.h"
+#include "..\..\CommonLib\utility.h"
+#include "..\..\CommonLib\debugutil.h"
+#include "..\..\CommonLib\requesthandler.h"
+#include "..\..\CommonLib\resources.h"
+#include "..\..\CommonLib\aspnetcore_msg.h"
+//#include "aspnetcore_event.h"
+#include "appoffline.h"
+#include "filewatcher.h"
+#include "applicationinfo.h"
+#include "applicationmanager.h"
+#include "globalmodule.h"
+#include "proxymodule.h"
+#include "applicationinfo.h"
+
+
+FORCEINLINE
+DWORD
+WIN32_FROM_HRESULT(
+    HRESULT hr
+)
+{
+    if ((FAILED(hr)) &&
+        (HRESULT_FACILITY(hr) == FACILITY_WIN32))
+    {
+        return HRESULT_CODE(hr);
+    }
+    return hr;
+}
+
+FORCEINLINE
+HRESULT
+HRESULT_FROM_GETLASTERROR()
+{
+    return  ( GetLastError() != NO_ERROR ) 
+           ? HRESULT_FROM_WIN32( GetLastError() )
+           : E_FAIL;
+}
+
+extern PVOID        g_pModuleId;
+extern BOOL         g_fAspnetcoreRHAssemblyLoaded;
+extern BOOL         g_fAspnetcoreRHLoadedError;
+extern BOOL         g_fInShutdown;
+extern BOOL         g_fEnableReferenceCountTracing;
+extern DWORD        g_dwActiveServerProcesses;
+extern HINSTANCE    g_hModule;
+extern HMODULE      g_hAspnetCoreRH;
+extern SRWLOCK      g_srwLock;
+extern PCWSTR       g_pwzAspnetcoreRequestHandlerName;
+extern HANDLE       g_hEventLog;
+extern PFN_ASPNETCORE_CREATE_APPLICATION      g_pfnAspNetCoreCreateApplication;
+extern PFN_ASPNETCORE_CREATE_REQUEST_HANDLER  g_pfnAspNetCoreCreateRequestHandler;
+#pragma warning( error : 4091)
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/AspNetCore/src/proxymodule.cxx b/src/IISIntegration/src/AspNetCoreModuleV2/AspNetCore/src/proxymodule.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..8ab880339a8f473da84b7d11c19d620a0adb8da7
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/AspNetCore/src/proxymodule.cxx
@@ -0,0 +1,211 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#include "precomp.hxx"
+
+__override
+HRESULT
+ASPNET_CORE_PROXY_MODULE_FACTORY::GetHttpModule(
+    CHttpModule **      ppModule,
+    IModuleAllocator *  pAllocator
+)
+{
+    ASPNET_CORE_PROXY_MODULE *pModule = new (pAllocator) ASPNET_CORE_PROXY_MODULE();
+    if (pModule == NULL)
+    {
+        return E_OUTOFMEMORY;
+    }
+
+    *ppModule = pModule;
+    return S_OK;
+}
+
+__override
+VOID
+ASPNET_CORE_PROXY_MODULE_FACTORY::Terminate(
+    VOID
+)
+/*++
+
+Routine description:
+
+    Function called by IIS for global (non-request-specific) notifications
+
+Arguments:
+
+    None.
+
+Return value:
+
+    None
+
+--*/
+{
+   /* FORWARDING_HANDLER::StaticTerminate();
+
+    WEBSOCKET_HANDLER::StaticTerminate();*/
+
+    ALLOC_CACHE_HANDLER::StaticTerminate();
+
+    delete this;
+}
+
+ASPNET_CORE_PROXY_MODULE::ASPNET_CORE_PROXY_MODULE(
+) : m_pApplicationInfo(NULL), m_pHandler(NULL)
+{
+}
+
+ASPNET_CORE_PROXY_MODULE::~ASPNET_CORE_PROXY_MODULE()
+{
+    if (m_pApplicationInfo != NULL)
+    {
+        m_pApplicationInfo->DereferenceApplicationInfo();
+        m_pApplicationInfo = NULL;
+    }
+
+    if (m_pHandler != NULL)
+    {
+        m_pHandler->DereferenceRequestHandler();
+        m_pHandler = NULL;
+    }
+}
+
+__override
+REQUEST_NOTIFICATION_STATUS
+ASPNET_CORE_PROXY_MODULE::OnExecuteRequestHandler(
+    IHttpContext *          pHttpContext,
+    IHttpEventProvider *
+)
+{
+    HRESULT hr = S_OK;
+    ASPNETCORE_CONFIG     *pConfig = NULL;
+    APPLICATION_MANAGER   *pApplicationManager = NULL;
+    REQUEST_NOTIFICATION_STATUS retVal = RQ_NOTIFICATION_CONTINUE;
+    APPLICATION* pApplication = NULL;
+    STACK_STRU(struFileName, 256);
+    if (g_fInShutdown)
+    {
+        hr = HRESULT_FROM_WIN32(ERROR_SERVER_SHUTDOWN_IN_PROGRESS);
+        goto Finished;
+    }
+
+    hr = ASPNETCORE_CONFIG::GetConfig(g_pHttpServer, g_pModuleId, pHttpContext, g_hEventLog, &pConfig);
+    if (FAILED(hr))
+    {
+        goto Finished;
+    }
+
+    pApplicationManager = APPLICATION_MANAGER::GetInstance();
+    if (pApplicationManager == NULL)
+    {
+        hr = E_OUTOFMEMORY;
+        goto Finished;
+    }
+
+    hr = pApplicationManager->GetOrCreateApplicationInfo(
+        g_pHttpServer,
+        pConfig,
+        &m_pApplicationInfo);
+    if (FAILED(hr))
+    {
+        goto Finished;
+    }
+
+    // app_offline check to avoid loading aspnetcorerh.dll unnecessarily
+    if (m_pApplicationInfo->AppOfflineFound())
+    {
+        // servicing app_offline
+        HTTP_DATA_CHUNK   DataChunk;
+        IHttpResponse    *pResponse = NULL;
+        APP_OFFLINE_HTM  *pAppOfflineHtm = NULL;
+
+        pResponse = pHttpContext->GetResponse();
+        pAppOfflineHtm = m_pApplicationInfo->QueryAppOfflineHtm();
+        DBG_ASSERT(pAppOfflineHtm);
+        DBG_ASSERT(pResponse);
+
+        // Ignore failure hresults as nothing we can do
+        // Set fTrySkipCustomErrors to true as we want client see the offline content
+        pResponse->SetStatus(503, "Service Unavailable", 0, hr, NULL, TRUE);
+        pResponse->SetHeader("Content-Type",
+            "text/html",
+            (USHORT)strlen("text/html"),
+            FALSE
+        );
+
+        DataChunk.DataChunkType = HttpDataChunkFromMemory;
+        DataChunk.FromMemory.pBuffer = (PVOID)pAppOfflineHtm->m_Contents.QueryStr();
+        DataChunk.FromMemory.BufferLength = pAppOfflineHtm->m_Contents.QueryCB();
+        pResponse->WriteEntityChunkByReference(&DataChunk);
+
+        retVal = RQ_NOTIFICATION_FINISH_REQUEST;
+        goto Finished;
+    }
+
+    // make sure assmebly is loaded and application is created
+    hr = m_pApplicationInfo->EnsureApplicationCreated();
+    if (FAILED(hr))
+    {
+        goto Finished;
+    }
+
+    m_pApplicationInfo->ExtractApplication(&pApplication);
+
+    // make sure application is in running state
+    // cannot recreate the application as we cannot reload clr for inprocess
+    if (pApplication != NULL &&
+        pApplication->QueryStatus() != APPLICATION_STATUS::RUNNING &&
+        pApplication->QueryStatus() != APPLICATION_STATUS::STARTING)
+    {
+        hr = HRESULT_FROM_WIN32(ERROR_SERVER_DISABLED);
+        goto Finished;
+    }
+
+    // Create RequestHandler and process the request
+    hr = m_pApplicationInfo->QueryCreateRequestHandler()(pHttpContext,
+                    (HTTP_MODULE_ID*) &g_pModuleId,
+                    pApplication,
+                    &m_pHandler);
+
+    if (FAILED(hr))
+    {
+        goto Finished;
+    }
+
+    retVal = m_pHandler->OnExecuteRequestHandler();
+
+Finished: 
+    if (FAILED(hr))
+    {
+        retVal = RQ_NOTIFICATION_FINISH_REQUEST;
+        if (hr == HRESULT_FROM_WIN32(ERROR_SERVER_SHUTDOWN_IN_PROGRESS))
+        {
+            pHttpContext->GetResponse()->SetStatus(503, "Service Unavailable", 0, hr);
+        }
+        else
+        {
+            pHttpContext->GetResponse()->SetStatus(500, "Internal Server Error", 0, hr);
+        }
+    }
+
+    if (pApplication != NULL)
+    {
+        pApplication->DereferenceApplication();
+    }
+    return retVal;
+}
+
+__override
+REQUEST_NOTIFICATION_STATUS
+ASPNET_CORE_PROXY_MODULE::OnAsyncCompletion(
+    IHttpContext *,
+    DWORD,
+    BOOL,
+    IHttpEventProvider *,
+    IHttpCompletionInfo *   pCompletionInfo
+)
+{
+    return m_pHandler->OnAsyncCompletion(
+        pCompletionInfo->GetCompletionBytes(),
+        pCompletionInfo->GetCompletionStatus());
+}
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/CommonLib/CommonLib.vcxproj b/src/IISIntegration/src/AspNetCoreModuleV2/CommonLib/CommonLib.vcxproj
new file mode 100644
index 0000000000000000000000000000000000000000..1ab1ef971c15c5858469f35ba59019f7000c203a
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/CommonLib/CommonLib.vcxproj
@@ -0,0 +1,226 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|Win32">
+      <Configuration>Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Debug|x64">
+      <Configuration>Debug</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|x64">
+      <Configuration>Release</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <VCProjectVersion>15.0</VCProjectVersion>
+    <ProjectGuid>{55494E58-E061-4C4C-A0A8-837008E72F85}</ProjectGuid>
+    <Keyword>Win32Proj</Keyword>
+    <RootNamespace>NewCommon</RootNamespace>
+    <WindowsTargetPlatformVersion>10.0.15063.0</WindowsTargetPlatformVersion>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+    <ConfigurationType>StaticLibrary</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <PlatformToolset>v141</PlatformToolset>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+    <ConfigurationType>StaticLibrary</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <PlatformToolset>v141</PlatformToolset>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+    <ConfigurationType>StaticLibrary</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <PlatformToolset>v141</PlatformToolset>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+    <ConfigurationType>StaticLibrary</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <PlatformToolset>v141</PlatformToolset>
+    <WholeProgramOptimization>false</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Label="Shared">
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <LinkIncremental>true</LinkIncremental>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <LinkIncremental>true</LinkIncremental>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <LinkIncremental>false</LinkIncremental>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <LinkIncremental>false</LinkIncremental>
+    <IncludePath>C:\AspNetCoreModule\src\IISLib;$(IncludePath)</IncludePath>
+  </PropertyGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>Use</PrecompiledHeader>
+      <WarningLevel>Level4</WarningLevel>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <Optimization>Disabled</Optimization>
+      <SDLCheck>false</SDLCheck>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <ConformanceMode>true</ConformanceMode>
+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+      <ShowIncludes>false</ShowIncludes>
+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <ClCompile>
+      <PrecompiledHeader>Use</PrecompiledHeader>
+      <WarningLevel>Level4</WarningLevel>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <Optimization>Disabled</Optimization>
+      <SDLCheck>false</SDLCheck>
+      <PreprocessorDefinitions>_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <ConformanceMode>true</ConformanceMode>
+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+      <MinimalRebuild>false</MinimalRebuild>
+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+      <ShowIncludes>false</ShowIncludes>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>Use</PrecompiledHeader>
+      <WarningLevel>Level4</WarningLevel>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <Optimization>MaxSpeed</Optimization>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <SDLCheck>false</SDLCheck>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <ConformanceMode>true</ConformanceMode>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+      <ShowIncludes>false</ShowIncludes>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <ClCompile>
+      <PrecompiledHeader>Use</PrecompiledHeader>
+      <WarningLevel>Level4</WarningLevel>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <Optimization>MaxSpeed</Optimization>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <SDLCheck>false</SDLCheck>
+      <PreprocessorDefinitions>NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <ConformanceMode>true</ConformanceMode>
+      <AdditionalIncludeDirectories>
+      </AdditionalIncludeDirectories>
+      <AdditionalUsingDirectories>
+      </AdditionalUsingDirectories>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+      <ShowIncludes>false</ShowIncludes>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+    </Link>
+    <Lib>
+      <AdditionalLibraryDirectories>..\iislib</AdditionalLibraryDirectories>
+    </Lib>
+  </ItemDefinitionGroup>
+  <ItemGroup>
+    <ClInclude Include="application.h" />
+    <ClInclude Include="aspnetcoreconfig.h" />
+    <ClInclude Include="debugutil.h" />
+    <ClInclude Include="disconnectcontext.h" />
+    <ClInclude Include="environmentvariablehash.h" />
+    <ClInclude Include="fx_ver.h" />
+    <ClInclude Include="hostfxr_utility.h" />
+    <ClInclude Include="requesthandler.h" />
+    <ClInclude Include="resources.h" />
+    <ClInclude Include="SRWLockWrapper.h" />
+    <ClInclude Include="stdafx.h" />
+    <ClInclude Include="utility.h" />
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="application.cpp" />
+    <ClCompile Include="aspnetcoreconfig.cxx" />
+    <ClCompile Include="fx_ver.cxx" />
+    <ClCompile Include="hostfxr_utility.cpp" />
+    <ClCompile Include="requesthandler.cxx" />
+    <ClCompile Include="SRWLockWrapper.cpp" />
+    <ClCompile Include="stdafx.cpp">
+      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
+      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
+      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
+      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
+    </ClCompile>
+    <ClCompile Include="utility.cxx" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\IISLib\IISLib.vcxproj">
+      <Project>{4787a64f-9a3e-4867-a55a-70cb4b2b2ffe}</Project>
+    </ProjectReference>
+  </ItemGroup>
+  <ItemGroup>
+    <CustomBuild Include="aspnetcore_msg.mc">
+      <FileType>Document</FileType>
+      <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">mc %(FullPath)</Command>
+      <Message Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Compiling Event Messages ...</Message>
+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(Filename).rc;%(Filename).h;MSG0409.bin</Outputs>
+      <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">mc %(FullPath)</Command>
+      <Message Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Compiling Event Messages ...</Message>
+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">%(Filename).rc;%(Filename).h;MSG0409.bin</Outputs>
+      <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">mc %(FullPath)</Command>
+      <Message Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Compiling Event Messages ...</Message>
+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(Filename).rc;%(Filename).h;MSG0409.bin</Outputs>
+      <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">mc %(FullPath)</Command>
+      <Message Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Compiling Event Messages ...</Message>
+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">%(Filename).rc;%(Filename).h;MSG0409.bin</Outputs>
+    </CustomBuild>
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  </ImportGroup>
+</Project>
\ No newline at end of file
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/CommonLib/SRWLockWrapper.cpp b/src/IISIntegration/src/AspNetCoreModuleV2/CommonLib/SRWLockWrapper.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..3fd0be51f44f1fe8051e9379f141a8b930c8c724
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/CommonLib/SRWLockWrapper.cpp
@@ -0,0 +1,13 @@
+#include "stdafx.h"
+#include "SRWLockWrapper.h"
+
+SRWLockWrapper::SRWLockWrapper(const SRWLOCK& lock)
+    : m_lock(lock)
+{
+    AcquireSRWLockExclusive(const_cast<SRWLOCK*>(&m_lock));
+}
+
+SRWLockWrapper::~SRWLockWrapper()
+{
+    ReleaseSRWLockExclusive(const_cast<SRWLOCK*>(&m_lock));
+}
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/CommonLib/SRWLockWrapper.h b/src/IISIntegration/src/AspNetCoreModuleV2/CommonLib/SRWLockWrapper.h
new file mode 100644
index 0000000000000000000000000000000000000000..2ae57cb2f86e3e8f99f301f3df59a321eef27b19
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/CommonLib/SRWLockWrapper.h
@@ -0,0 +1,9 @@
+#pragma once
+class SRWLockWrapper
+{
+public:
+	SRWLockWrapper(const SRWLOCK& lock);
+	~SRWLockWrapper();
+private:
+    const SRWLOCK& m_lock;
+};
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/CommonLib/application.cpp b/src/IISIntegration/src/AspNetCoreModuleV2/CommonLib/application.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..b68c09326648c34dfb3ae9094300a2cf31a06f04
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/CommonLib/application.cpp
@@ -0,0 +1,50 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#include "stdafx.h"
+
+APPLICATION::APPLICATION(
+    _In_ IHttpServer* pHttpServer,
+    _In_ ASPNETCORE_CONFIG* pConfig) :
+    m_cRefs(1),
+    m_pConfig(pConfig),
+    m_status(APPLICATION_STATUS::UNKNOWN)
+{
+    UNREFERENCED_PARAMETER(pHttpServer);
+}
+
+APPLICATION::~APPLICATION()
+{
+}
+
+APPLICATION_STATUS
+APPLICATION::QueryStatus()
+{
+    return m_status;
+}
+
+ASPNETCORE_CONFIG*
+APPLICATION::QueryConfig()
+{
+    return m_pConfig;
+}
+
+VOID
+APPLICATION::ReferenceApplication()
+const
+{
+    InterlockedIncrement(&m_cRefs);
+}
+
+VOID
+APPLICATION::DereferenceApplication()
+const
+{
+    DBG_ASSERT(m_cRefs != 0);
+
+    LONG cRefs = 0;
+    if ((cRefs = InterlockedDecrement(&m_cRefs)) == 0)
+    {
+        delete this;
+    }
+}
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/CommonLib/application.h b/src/IISIntegration/src/AspNetCoreModuleV2/CommonLib/application.h
new file mode 100644
index 0000000000000000000000000000000000000000..43c9dafd0c5adad94dfb9dd8a9d921dbc6e5f073
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/CommonLib/application.h
@@ -0,0 +1,53 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#pragma once
+
+enum APPLICATION_STATUS
+{
+    UNKNOWN = 0,
+    STARTING,
+    RUNNING,
+    SHUTDOWN,
+    FAIL
+};
+
+class  ASPNETCORE_CONFIG;
+
+class APPLICATION
+{
+public:
+    APPLICATION(
+        _In_ IHttpServer* pHttpServer,
+        _In_ ASPNETCORE_CONFIG* pConfig);
+
+    virtual
+    VOID
+    ShutDown() = 0;
+
+    virtual
+    VOID
+    Recycle() = 0;
+
+    virtual
+    ~APPLICATION();
+
+    APPLICATION_STATUS
+    QueryStatus();
+
+    ASPNETCORE_CONFIG*
+    QueryConfig();
+
+    VOID
+    ReferenceApplication()
+    const;
+
+    VOID
+    DereferenceApplication()
+    const;
+
+protected:
+    mutable LONG            m_cRefs;
+    volatile APPLICATION_STATUS m_status;
+    ASPNETCORE_CONFIG*      m_pConfig;
+};
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/CommonLib/aspnetcore_msg.mc b/src/IISIntegration/src/AspNetCoreModuleV2/CommonLib/aspnetcore_msg.mc
new file mode 100644
index 0000000000000000000000000000000000000000..96cf5fec0c68498ba84a0f4207495ced21000e34
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/CommonLib/aspnetcore_msg.mc
@@ -0,0 +1,217 @@
+;/*++
+;
+; Copyright (c) .NET Foundation. All rights reserved.
+; Licensed under the MIT License. See License.txt in the project root for license information.
+;
+;Module Name:
+;
+;    aspnetcore_msg.mc
+;
+;Abstract:
+;
+;    Asp.Net Core Module localizable messages.
+;
+;--*/
+;
+;
+;#ifndef _ASPNETCORE_MSG_H_
+;#define _ASPNETCORE_MSG_H_
+;
+
+SeverityNames=(Success=0x0
+               Informational=0x1
+               Warning=0x2
+               Error=0x3
+              )
+
+MessageIdTypedef=DWORD
+
+Messageid=1000
+SymbolicName=ASPNETCORE_EVENT_PROCESS_START_ERROR
+Language=English
+%1
+.
+
+Messageid=1001
+SymbolicName=ASPNETCORE_EVENT_PROCESS_START_SUCCESS
+Language=English
+%1
+.
+
+Messageid=1002
+SymbolicName=ASPNETCORE_EVENT_PROCESS_CRASH
+Language=English
+%1
+.
+
+Messageid=1003
+SymbolicName=ASPNETCORE_EVENT_RAPID_FAIL_COUNT_EXCEEDED
+Language=English
+%1
+.
+
+Messageid=1004
+SymbolicName=ASPNETCORE_EVENT_CONFIG_ERROR
+Language=English
+%1
+.
+
+Messageid=1005
+SymbolicName=ASPNETCORE_EVENT_GRACEFUL_SHUTDOWN_FAILURE
+Language=English
+%1
+.
+
+Messageid=1006
+SymbolicName=ASPNETCORE_EVENT_SENT_SHUTDOWN_HTTP_REQUEST
+Language=English
+%1
+.
+
+Messageid=1007
+SymbolicName=ASPNETCORE_EVENT_LOAD_CLR_FALIURE
+Language=English
+%1
+.
+
+Messageid=1008
+SymbolicName=ASPNETCORE_EVENT_DUPLICATED_INPROCESS_APP
+Language=English
+%1
+.
+
+Messageid=1009
+SymbolicName=ASPNETCORE_EVENT_MIXED_HOSTING_MODEL_ERROR
+Language=English
+%1
+.
+
+Messageid=1010
+SymbolicName=ASPNETCORE_EVENT_ADD_APPLICATION_ERROR
+Language=English
+%1
+.
+
+Messageid=1011
+SymbolicName=ASPNETCORE_EVENT_INPROCESS_THREAD_EXIT
+Language=English
+%1
+.
+
+Messageid=1012
+SymbolicName=ASPNETCORE_EVENT_RECYCLE_APPOFFLINE
+Language=English
+%1
+.
+
+Messageid=1013
+SymbolicName=ASPNETCORE_EVENT_MODULE_DISABLED
+Language=English
+%1
+.
+
+Messageid=1014
+SymbolicName=ASPNETCORE_EVENT_INPROCESS_FULL_FRAMEWORK_APP
+Language=English
+%1
+.
+
+Messageid=1015
+SymbolicName=ASPNETCORE_EVENT_PORTABLE_APP_DOTNET_MISSING
+Language=English
+%1
+.
+
+Messageid=1016
+SymbolicName=ASPNETCORE_EVENT_HOSTFXR_DIRECTORY_NOT_FOUND
+Language=English
+%1
+.
+
+Messageid=1017
+SymbolicName=ASPNETCORE_EVENT_HOSTFXR_DLL_NOT_FOUND
+Language=English
+%1
+.
+
+Messageid=1018
+SymbolicName=ASPNETCORE_EVENT_INPROCESS_THREAD_EXCEPTION
+Language=English
+%1
+.
+
+Messageid=1019
+SymbolicName=ASPNETCORE_EVENT_APPLICATION_EXE_NOT_FOUND
+Language=English
+%1
+.
+
+Messageid=1020
+SymbolicName=ASPNETCORE_EVENT_PROCESS_START_FAILURE
+Language=English
+%1
+.
+
+Messageid=1021
+SymbolicName=ASPNETCORE_EVENT_RECYCLE_CONFIGURATION
+Language=English
+%1
+.
+
+Messageid=1022
+SymbolicName=ASPNETCORE_EVENT_RECYCLE_APP_FAILURE
+Language=English
+%1
+.
+
+Messageid=1023
+SymbolicName=ASPNETCORE_EVENT_APP_IN_SHUTDOWN
+Language=English
+%1
+.
+
+Messageid=1024
+SymbolicName=ASPNETCORE_EVENT_RECYCLE_APPOFFLINE_REMOVED
+Language=English
+%1
+.
+
+Messageid=1025
+SymbolicName=ASPNETCORE_EVENT_GENERAL_INFO_MSG
+Language=English
+%1
+.
+
+Messageid=1026
+SymbolicName=ASPNETCORE_EVENT_GENERAL_WARNING_MSG
+Language=English
+%1
+.
+
+Messageid=1027
+SymbolicName=ASPNETCORE_EVENT_GENERAL_ERROR_MSG
+Language=English
+%1
+.
+
+Messageid=1028
+SymbolicName=ASPNETCORE_EVENT_INPROCESS_RH_MISSING
+Language=English
+%1
+.
+
+Messageid=1029
+SymbolicName=ASPNETCORE_EVENT_OUT_OF_PROCESS_RH_MISSING
+Language=English
+%1
+.
+
+Messageid=1030
+SymbolicName=ASPNETCORE_EVENT_PROCESS_SHUTDOWN
+Language=English
+%1
+.
+
+;
+;#endif     // _ASPNETCORE_MODULE_MSG_H_
+;
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/CommonLib/aspnetcore_msg.rc b/src/IISIntegration/src/AspNetCoreModuleV2/CommonLib/aspnetcore_msg.rc
new file mode 100644
index 0000000000000000000000000000000000000000..0abcb0fa2c5715345b85e7bdbe1d79a9f2410b23
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/CommonLib/aspnetcore_msg.rc
@@ -0,0 +1,2 @@
+LANGUAGE 0x9,0x1
+1 11 "MSG00001.bin"
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/CommonLib/aspnetcoreconfig.cxx b/src/IISIntegration/src/AspNetCoreModuleV2/CommonLib/aspnetcoreconfig.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..97a7d0c63eb7a1cb2e1614e014c9380a97829031
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/CommonLib/aspnetcoreconfig.cxx
@@ -0,0 +1,609 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#include "stdafx.h"
+#include "aspnetcoreconfig.h"
+#include "debugutil.h"
+
+ASPNETCORE_CONFIG::~ASPNETCORE_CONFIG()
+{
+    if (m_ppStrArguments != NULL)
+    {
+        delete[] m_ppStrArguments;
+        m_ppStrArguments = NULL;
+    }
+
+    if (m_pEnvironmentVariables != NULL)
+    {
+        m_pEnvironmentVariables->Clear();
+        delete m_pEnvironmentVariables;
+        m_pEnvironmentVariables = NULL;
+    }
+}
+
+VOID
+ASPNETCORE_CONFIG::ReferenceConfiguration(
+    VOID
+) const
+{
+    InterlockedIncrement(&m_cRefs);
+}
+
+VOID
+ASPNETCORE_CONFIG::DereferenceConfiguration(
+    VOID
+) const
+{
+    DBG_ASSERT(m_cRefs != 0);
+    LONG cRefs = 0;
+    if ((cRefs = InterlockedDecrement(&m_cRefs)) == 0)
+    {
+        delete this;
+    }
+}
+
+HRESULT
+ASPNETCORE_CONFIG::GetConfig(
+    _In_  IHttpServer             *pHttpServer,
+    _In_  HTTP_MODULE_ID           pModuleId,
+    _In_  IHttpContext            *pHttpContext,
+    _In_  HANDLE                   hEventLog,
+    _Out_ ASPNETCORE_CONFIG      **ppAspNetCoreConfig
+)
+{
+    HRESULT                 hr = S_OK;
+    IHttpApplication       *pHttpApplication = pHttpContext->GetApplication();
+    ASPNETCORE_CONFIG      *pAspNetCoreConfig = NULL;
+    STRU                    struHostFxrDllLocation;
+    PWSTR*                  pwzArgv;
+    DWORD                   dwArgCount;
+
+    if (ppAspNetCoreConfig == NULL)
+    {
+        hr = E_INVALIDARG;
+        goto Finished;
+    }
+
+    *ppAspNetCoreConfig = NULL;
+
+    // potential bug if user sepcific config at virtual dir level
+    pAspNetCoreConfig = (ASPNETCORE_CONFIG*)
+        pHttpApplication->GetModuleContextContainer()->GetModuleContext(pModuleId);
+
+    if (pAspNetCoreConfig != NULL)
+    {
+        *ppAspNetCoreConfig = pAspNetCoreConfig;
+        pAspNetCoreConfig = NULL;
+        goto Finished;
+    }
+
+    pAspNetCoreConfig = new ASPNETCORE_CONFIG;
+    if (pAspNetCoreConfig == NULL)
+    {
+        hr = E_OUTOFMEMORY;
+        goto Finished;
+    }
+
+    hr = pAspNetCoreConfig->Populate(pHttpServer, pHttpContext);
+    if (FAILED(hr))
+    {
+        goto Finished;
+    }
+
+    // Modify config for inprocess.
+    if (pAspNetCoreConfig->QueryHostingModel() == APP_HOSTING_MODEL::HOSTING_IN_PROCESS)
+    {
+        if (FAILED(hr = HOSTFXR_UTILITY::GetHostFxrParameters(
+            hEventLog,
+            pAspNetCoreConfig->QueryProcessPath()->QueryStr(),
+            pAspNetCoreConfig->QueryApplicationPhysicalPath()->QueryStr(),
+            pAspNetCoreConfig->QueryArguments()->QueryStr(),
+            &struHostFxrDllLocation,
+            &dwArgCount,
+            &pwzArgv)))
+        {
+            goto Finished;
+        }
+
+        if (FAILED(hr = pAspNetCoreConfig->SetHostFxrFullPath(struHostFxrDllLocation.QueryStr())))
+        {
+            goto Finished;
+        }
+
+        pAspNetCoreConfig->SetHostFxrArguments(dwArgCount, pwzArgv);
+    }
+
+    hr = pHttpApplication->GetModuleContextContainer()->
+        SetModuleContext(pAspNetCoreConfig, pModuleId);
+    if (FAILED(hr))
+    {
+        if (hr == HRESULT_FROM_WIN32(ERROR_ALREADY_ASSIGNED))
+        {
+            delete pAspNetCoreConfig;
+
+            pAspNetCoreConfig = (ASPNETCORE_CONFIG*)pHttpApplication->
+                GetModuleContextContainer()->
+                GetModuleContext(pModuleId);
+
+            _ASSERT(pAspNetCoreConfig != NULL);
+
+            hr = S_OK;
+        }
+        else
+        {
+            goto Finished;
+        }
+    }
+    else
+    {
+        DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO,
+            "ASPNETCORE_CONFIG::GetConfig, set config to ModuleContext");
+        // set appliction info here instead of inside Populate()
+        // as the destructor will delete the backend process
+        hr = pAspNetCoreConfig->QueryApplicationPath()->Copy(pHttpApplication->GetApplicationId());
+        if (FAILED(hr))
+        {
+            goto Finished;
+        }
+    }
+
+    *ppAspNetCoreConfig = pAspNetCoreConfig;
+    pAspNetCoreConfig = NULL;
+
+Finished:
+
+    if (pAspNetCoreConfig != NULL)
+    {
+        delete pAspNetCoreConfig;
+        pAspNetCoreConfig = NULL;
+    }
+
+    return hr;
+}
+
+HRESULT
+ASPNETCORE_CONFIG::Populate(
+    IHttpServer    *pHttpServer,
+    IHttpContext   *pHttpContext
+)
+{
+    STACK_STRU(strHostingModel, 300);
+    HRESULT                         hr = S_OK;
+    STRU                            strEnvName;
+    STRU                            strEnvValue;
+    STRU                            strExpandedEnvValue;
+    STRU                            strApplicationFullPath;
+    IAppHostAdminManager           *pAdminManager = NULL;
+    IAppHostElement                *pAspNetCoreElement = NULL;
+    IAppHostElement                *pWindowsAuthenticationElement = NULL;
+    IAppHostElement                *pBasicAuthenticationElement = NULL;
+    IAppHostElement                *pAnonymousAuthenticationElement = NULL;
+    IAppHostElement                *pWebSocketElement = NULL;
+    IAppHostElement                *pEnvVarList = NULL;
+    IAppHostElement                *pEnvVar = NULL;
+    IAppHostElementCollection      *pEnvVarCollection = NULL;
+    ULONGLONG                       ullRawTimeSpan = 0;
+    ENUM_INDEX                      index;
+    ENVIRONMENT_VAR_ENTRY*          pEntry = NULL;
+    DWORD                           dwCounter = 0;
+    DWORD                           dwPosition = 0;
+    WCHAR*                          pszPath = NULL;
+    BSTR                            bstrWindowAuthSection = NULL;
+    BSTR                            bstrBasicAuthSection = NULL;
+    BSTR                            bstrAnonymousAuthSection = NULL;
+    BSTR                            bstrAspNetCoreSection = NULL;
+    BSTR                            bstrWebsocketSection = NULL;
+
+    m_pEnvironmentVariables = new ENVIRONMENT_VAR_HASH();
+    if (m_pEnvironmentVariables == NULL)
+    {
+        hr = E_OUTOFMEMORY;
+        goto Finished;
+    }
+    if (FAILED(hr = m_pEnvironmentVariables->Initialize(37 /*prime*/)))
+    {
+        delete m_pEnvironmentVariables;
+        m_pEnvironmentVariables = NULL;
+        goto Finished;
+    }
+
+    pAdminManager = pHttpServer->GetAdminManager();
+    hr = m_struConfigPath.Copy(pHttpContext->GetApplication()->GetAppConfigPath());
+    if (FAILED(hr))
+    {
+        goto Finished;
+    }
+
+    hr = m_struApplicationPhysicalPath.Copy(pHttpContext->GetApplication()->GetApplicationPhysicalPath());
+    if (FAILED(hr))
+    {
+        goto Finished;
+    }
+
+    pszPath = m_struConfigPath.QueryStr();
+    while (pszPath[dwPosition] != NULL)
+    {
+        if (pszPath[dwPosition] == '/')
+        {
+            dwCounter++;
+            if (dwCounter == 4)
+                break;
+        }
+        dwPosition++;
+    }
+
+    if (dwCounter == 4)
+    {
+        hr = m_struApplicationVirtualPath.Copy(pszPath + dwPosition);
+    }
+    else
+    {
+        hr = m_struApplicationVirtualPath.Copy(L"/");
+    }
+
+    // Will setup the application virtual path.
+    if (FAILED(hr))
+    {
+        goto Finished;
+    }
+
+    bstrWindowAuthSection = SysAllocString(CS_WINDOWS_AUTHENTICATION_SECTION);
+    if (bstrWindowAuthSection == NULL)
+    {
+        hr = E_OUTOFMEMORY;
+        goto Finished;
+    }
+
+    hr = pAdminManager->GetAdminSection(bstrWindowAuthSection,
+        m_struConfigPath.QueryStr(),
+        &pWindowsAuthenticationElement);
+    if (FAILED(hr))
+    {
+        // assume the corresponding authen was not enabled
+        // as the section may get deleted by user in some HWC case
+        // ToDo: log a warning to event log
+        m_fWindowsAuthEnabled = FALSE;
+    }
+    else
+    {
+        hr = GetElementBoolProperty(pWindowsAuthenticationElement,
+            CS_ENABLED,
+            &m_fWindowsAuthEnabled);
+        if (FAILED(hr))
+        {
+            goto Finished;
+        }
+    }
+
+    bstrBasicAuthSection = SysAllocString(CS_BASIC_AUTHENTICATION_SECTION);
+    if (bstrBasicAuthSection == NULL)
+    {
+        hr = E_OUTOFMEMORY;
+        goto Finished;
+    }
+    hr = pAdminManager->GetAdminSection(bstrBasicAuthSection,
+        m_struConfigPath.QueryStr(),
+        &pBasicAuthenticationElement);
+    if (FAILED(hr))
+    {
+        m_fBasicAuthEnabled = FALSE;
+    }
+    else
+    {
+        hr = GetElementBoolProperty(pBasicAuthenticationElement,
+            CS_ENABLED,
+            &m_fBasicAuthEnabled);
+        if (FAILED(hr))
+        {
+            goto Finished;
+        }
+    }
+    bstrAnonymousAuthSection = SysAllocString(CS_ANONYMOUS_AUTHENTICATION_SECTION);
+    if (bstrAnonymousAuthSection == NULL)
+    {
+        hr = E_OUTOFMEMORY;
+        goto Finished;
+    }
+    hr = pAdminManager->GetAdminSection(bstrAnonymousAuthSection,
+        m_struConfigPath.QueryStr(),
+        &pAnonymousAuthenticationElement);
+    if (FAILED(hr))
+    {
+        m_fAnonymousAuthEnabled = FALSE;
+    }
+    else
+    {
+        hr = GetElementBoolProperty(pAnonymousAuthenticationElement,
+            CS_ENABLED,
+            &m_fAnonymousAuthEnabled);
+        if (FAILED(hr))
+        {
+            goto Finished;
+        }
+    }
+
+    bstrWebsocketSection = SysAllocString(CS_WEBSOCKET_SECTION);
+    if (bstrWebsocketSection == NULL)
+    {
+        hr = E_OUTOFMEMORY;
+        goto Finished;
+    }
+
+    hr = pAdminManager->GetAdminSection(bstrWebsocketSection,
+        m_struConfigPath.QueryStr(),
+        &pWebSocketElement);
+    if (FAILED(hr))
+    {
+        m_fWebSocketEnabled = FALSE;
+    }
+    else
+    {
+        hr = GetElementBoolProperty(pWebSocketElement,
+            CS_ENABLED,
+            &m_fWebSocketEnabled);
+        if (FAILED(hr))
+        {
+            goto Finished;
+        }
+    }
+
+    bstrAspNetCoreSection = SysAllocString(CS_ASPNETCORE_SECTION);
+    if (bstrAspNetCoreSection == NULL)
+    {
+        hr = E_OUTOFMEMORY;
+        goto Finished;
+    }
+    hr = pAdminManager->GetAdminSection(bstrAspNetCoreSection,
+        m_struConfigPath.QueryStr(),
+        &pAspNetCoreElement);
+    if (FAILED(hr))
+    {
+        goto Finished;
+    }
+
+    hr = GetElementStringProperty(pAspNetCoreElement,
+        CS_ASPNETCORE_PROCESS_EXE_PATH,
+        &m_struProcessPath);
+    if (FAILED(hr))
+    {
+        goto Finished;
+    }
+
+    hr = GetElementStringProperty(pAspNetCoreElement,
+        CS_ASPNETCORE_HOSTING_MODEL,
+        &strHostingModel);
+    if (FAILED(hr))
+    {
+        // Swallow this error for backward compatability
+        // Use default behavior for empty string
+        hr = S_OK;
+    }
+
+    if (strHostingModel.IsEmpty() || strHostingModel.Equals(L"outofprocess", TRUE))
+    {
+        m_hostingModel = HOSTING_OUT_PROCESS;
+    }
+    else if (strHostingModel.Equals(L"inprocess", TRUE))
+    {
+        m_hostingModel = HOSTING_IN_PROCESS;
+    }
+    else
+    {
+        // block unknown hosting value
+        hr = HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
+        goto Finished;
+    }
+
+    hr = GetElementStringProperty(pAspNetCoreElement,
+        CS_ASPNETCORE_PROCESS_ARGUMENTS,
+        &m_struArguments);
+    if (FAILED(hr))
+    {
+        goto Finished;
+    }
+
+    hr = GetElementDWORDProperty(pAspNetCoreElement,
+        CS_ASPNETCORE_RAPID_FAILS_PER_MINUTE,
+        &m_dwRapidFailsPerMinute);
+    if (FAILED(hr))
+    {
+        goto Finished;
+    }
+
+    //
+    // rapidFailsPerMinute cannot be greater than 100.
+    //
+    if (m_dwRapidFailsPerMinute > MAX_RAPID_FAILS_PER_MINUTE)
+    {
+        m_dwRapidFailsPerMinute = MAX_RAPID_FAILS_PER_MINUTE;
+    }
+
+    hr = GetElementDWORDProperty(pAspNetCoreElement,
+        CS_ASPNETCORE_PROCESSES_PER_APPLICATION,
+        &m_dwProcessesPerApplication);
+    if (FAILED(hr))
+    {
+        goto Finished;
+    }
+
+    hr = GetElementDWORDProperty(
+        pAspNetCoreElement,
+        CS_ASPNETCORE_PROCESS_STARTUP_TIME_LIMIT,
+        &m_dwStartupTimeLimitInMS
+    );
+    if (FAILED(hr))
+    {
+        goto Finished;
+    }
+
+    m_dwStartupTimeLimitInMS *= MILLISECONDS_IN_ONE_SECOND;
+
+    hr = GetElementDWORDProperty(
+        pAspNetCoreElement,
+        CS_ASPNETCORE_PROCESS_SHUTDOWN_TIME_LIMIT,
+        &m_dwShutdownTimeLimitInMS
+    );
+    if (FAILED(hr))
+    {
+        goto Finished;
+    }
+    m_dwShutdownTimeLimitInMS *= MILLISECONDS_IN_ONE_SECOND;
+
+    hr = GetElementBoolProperty(pAspNetCoreElement,
+        CS_ASPNETCORE_FORWARD_WINDOWS_AUTH_TOKEN,
+        &m_fForwardWindowsAuthToken);
+    if (FAILED(hr))
+    {
+        goto Finished;
+    }
+
+    hr = GetElementBoolProperty(pAspNetCoreElement,
+        CS_ASPNETCORE_DISABLE_START_UP_ERROR_PAGE,
+        &m_fDisableStartUpErrorPage);
+    if (FAILED(hr))
+    {
+        goto Finished;
+    }
+
+    hr = GetElementRawTimeSpanProperty(
+        pAspNetCoreElement,
+        CS_ASPNETCORE_WINHTTP_REQUEST_TIMEOUT,
+        &ullRawTimeSpan
+    );
+    if (FAILED(hr))
+    {
+        goto Finished;
+    }
+
+    m_dwRequestTimeoutInMS = (DWORD)TIMESPAN_IN_MILLISECONDS(ullRawTimeSpan);
+
+    hr = GetElementBoolProperty(pAspNetCoreElement,
+        CS_ASPNETCORE_STDOUT_LOG_ENABLED,
+        &m_fStdoutLogEnabled);
+    if (FAILED(hr))
+    {
+        goto Finished;
+    }
+    hr = GetElementStringProperty(pAspNetCoreElement,
+        CS_ASPNETCORE_STDOUT_LOG_FILE,
+        &m_struStdoutLogFile);
+    if (FAILED(hr))
+    {
+        goto Finished;
+    }
+
+    hr = GetElementChildByName(pAspNetCoreElement,
+        CS_ASPNETCORE_ENVIRONMENT_VARIABLES,
+        &pEnvVarList);
+    if (FAILED(hr))
+    {
+        goto Finished;
+    }
+
+    hr = pEnvVarList->get_Collection(&pEnvVarCollection);
+    if (FAILED(hr))
+    {
+        goto Finished;
+    }
+
+    for (hr = FindFirstElement(pEnvVarCollection, &index, &pEnvVar);
+        SUCCEEDED(hr);
+        hr = FindNextElement(pEnvVarCollection, &index, &pEnvVar))
+    {
+        if (hr == S_FALSE)
+        {
+            hr = S_OK;
+            break;
+        }
+
+        if (FAILED(hr = GetElementStringProperty(pEnvVar,
+            CS_ASPNETCORE_ENVIRONMENT_VARIABLE_NAME,
+            &strEnvName)) ||
+            FAILED(hr = GetElementStringProperty(pEnvVar,
+                CS_ASPNETCORE_ENVIRONMENT_VARIABLE_VALUE,
+                &strEnvValue)) ||
+            FAILED(hr = strEnvName.Append(L"=")) ||
+            FAILED(hr = STRU::ExpandEnvironmentVariables(strEnvValue.QueryStr(), &strExpandedEnvValue)))
+        {
+            goto Finished;
+        }
+
+        pEntry = new ENVIRONMENT_VAR_ENTRY();
+        if (pEntry == NULL)
+        {
+            hr = E_OUTOFMEMORY;
+            goto Finished;
+        }
+
+        if (FAILED(hr = pEntry->Initialize(strEnvName.QueryStr(), strExpandedEnvValue.QueryStr())) ||
+            FAILED(hr = m_pEnvironmentVariables->InsertRecord(pEntry)))
+        {
+            goto Finished;
+        }
+        strEnvName.Reset();
+        strEnvValue.Reset();
+        strExpandedEnvValue.Reset();
+        pEnvVar->Release();
+        pEnvVar = NULL;
+        pEntry->Dereference();
+        pEntry = NULL;
+    }
+
+Finished:
+
+    if (pAspNetCoreElement != NULL)
+    {
+        pAspNetCoreElement->Release();
+        pAspNetCoreElement = NULL;
+    }
+
+    if (pWebSocketElement != NULL)
+    {
+        pWebSocketElement->Release();
+        pWebSocketElement = NULL;
+    }
+
+    if (pWindowsAuthenticationElement != NULL)
+    {
+        pWindowsAuthenticationElement->Release();
+        pWindowsAuthenticationElement = NULL;
+    }
+
+    if (pAnonymousAuthenticationElement != NULL)
+    {
+        pAnonymousAuthenticationElement->Release();
+        pAnonymousAuthenticationElement = NULL;
+    }
+
+    if (pBasicAuthenticationElement != NULL)
+    {
+        pBasicAuthenticationElement->Release();
+        pBasicAuthenticationElement = NULL;
+    }
+
+    if (pEnvVarList != NULL)
+    {
+        pEnvVarList->Release();
+        pEnvVarList = NULL;
+    }
+
+    if (pEnvVar != NULL)
+    {
+        pEnvVar->Release();
+        pEnvVar = NULL;
+    }
+
+    if (pEnvVarCollection != NULL)
+    {
+        pEnvVarCollection->Release();
+        pEnvVarCollection = NULL;
+    }
+
+    if (pEntry != NULL)
+    {
+        pEntry->Dereference();
+        pEntry = NULL;
+    }
+
+    return hr;
+}
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/CommonLib/aspnetcoreconfig.h b/src/IISIntegration/src/AspNetCoreModuleV2/CommonLib/aspnetcoreconfig.h
new file mode 100644
index 0000000000000000000000000000000000000000..655dcdc3856738e5e87cdc9af093dff06cdd9835
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/CommonLib/aspnetcoreconfig.h
@@ -0,0 +1,332 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#pragma once
+#define CS_ROOTWEB_CONFIG                                L"MACHINE/WEBROOT/APPHOST/"
+#define CS_ROOTWEB_CONFIG_LEN                            _countof(CS_ROOTWEB_CONFIG)-1
+#define CS_ASPNETCORE_SECTION                            L"system.webServer/aspNetCore"
+#define CS_WINDOWS_AUTHENTICATION_SECTION                L"system.webServer/security/authentication/windowsAuthentication"
+#define CS_BASIC_AUTHENTICATION_SECTION                  L"system.webServer/security/authentication/basicAuthentication"
+#define CS_ANONYMOUS_AUTHENTICATION_SECTION              L"system.webServer/security/authentication/anonymousAuthentication"
+#define CS_WEBSOCKET_SECTION                             L"system.webServer/webSocket"
+#define CS_ENABLED                                       L"enabled"
+#define CS_ASPNETCORE_PROCESS_EXE_PATH                   L"processPath"
+#define CS_ASPNETCORE_PROCESS_ARGUMENTS                  L"arguments"
+#define CS_ASPNETCORE_PROCESS_STARTUP_TIME_LIMIT         L"startupTimeLimit"
+#define CS_ASPNETCORE_PROCESS_SHUTDOWN_TIME_LIMIT        L"shutdownTimeLimit"
+#define CS_ASPNETCORE_WINHTTP_REQUEST_TIMEOUT            L"requestTimeout"
+#define CS_ASPNETCORE_RAPID_FAILS_PER_MINUTE             L"rapidFailsPerMinute"
+#define CS_ASPNETCORE_STDOUT_LOG_ENABLED                 L"stdoutLogEnabled"
+#define CS_ASPNETCORE_STDOUT_LOG_FILE                    L"stdoutLogFile"
+#define CS_ASPNETCORE_ENVIRONMENT_VARIABLES              L"environmentVariables"
+#define CS_ASPNETCORE_ENVIRONMENT_VARIABLE               L"environmentVariable"
+#define CS_ASPNETCORE_ENVIRONMENT_VARIABLE_NAME          L"name"
+#define CS_ASPNETCORE_ENVIRONMENT_VARIABLE_VALUE         L"value"
+#define CS_ASPNETCORE_PROCESSES_PER_APPLICATION          L"processesPerApplication"
+#define CS_ASPNETCORE_FORWARD_WINDOWS_AUTH_TOKEN         L"forwardWindowsAuthToken"
+#define CS_ASPNETCORE_DISABLE_START_UP_ERROR_PAGE        L"disableStartUpErrorPage"
+#define CS_ASPNETCORE_RECYCLE_ON_FILE_CHANGE             L"recycleOnFileChange"
+#define CS_ASPNETCORE_RECYCLE_ON_FILE_CHANGE_FILE        L"file"
+#define CS_ASPNETCORE_RECYCLE_ON_FILE_CHANGE_FILE_PATH   L"path"
+#define CS_ASPNETCORE_HOSTING_MODEL                      L"hostingModel"
+
+#define MAX_RAPID_FAILS_PER_MINUTE 100
+#define MILLISECONDS_IN_ONE_SECOND 1000
+#define MIN_PORT                   1025
+#define MAX_PORT                   48000
+
+#define TIMESPAN_IN_MILLISECONDS(x)  ((x)/((LONGLONG)(10000)))
+#define TIMESPAN_IN_SECONDS(x)       ((TIMESPAN_IN_MILLISECONDS(x))/((LONGLONG)(1000)))
+#define TIMESPAN_IN_MINUTES(x)       ((TIMESPAN_IN_SECONDS(x))/((LONGLONG)(60)))
+
+//#define HEX_TO_ASCII(c) ((CHAR)(((c) < 10) ? ((c) + '0') : ((c) + 'a' - 10)))
+
+#include "stdafx.h"
+
+enum APP_HOSTING_MODEL
+{
+    HOSTING_UNKNOWN = 0,
+    HOSTING_IN_PROCESS,
+    HOSTING_OUT_PROCESS
+};
+
+class ASPNETCORE_CONFIG : IHttpStoredContext
+{
+public:
+
+    virtual
+    ~ASPNETCORE_CONFIG();
+
+    VOID
+    CleanupStoredContext()
+    {
+        DereferenceConfiguration();
+    }
+
+    static
+    HRESULT
+    GetConfig(
+        _In_  IHttpServer             *pHttpServer,
+        _In_  HTTP_MODULE_ID           pModuleId,
+        _In_  IHttpContext            *pHttpContext,
+        _In_  HANDLE                   hEventLog,
+        _Out_ ASPNETCORE_CONFIG       **ppAspNetCoreConfig
+    );
+
+    ENVIRONMENT_VAR_HASH*
+    QueryEnvironmentVariables(
+        VOID
+    )
+    {
+        return m_pEnvironmentVariables;
+    }
+
+    DWORD
+    QueryRapidFailsPerMinute(
+        VOID
+    )
+    {
+        return m_dwRapidFailsPerMinute;
+    }
+
+    DWORD
+    QueryStartupTimeLimitInMS(
+        VOID
+    )
+    {
+        return m_dwStartupTimeLimitInMS;
+    }
+
+    DWORD
+    QueryShutdownTimeLimitInMS(
+        VOID
+    )
+    {
+        return m_dwShutdownTimeLimitInMS;
+    }
+
+    DWORD
+    QueryProcessesPerApplication(
+        VOID
+    )
+    {
+        return m_dwProcessesPerApplication;
+    }
+
+    DWORD
+    QueryRequestTimeoutInMS(
+        VOID
+    )
+    {
+        return m_dwRequestTimeoutInMS;
+    }
+
+    STRU*
+    QueryArguments(
+        VOID
+    )
+    {
+        return &m_struArguments;
+    }
+
+    STRU*
+    QueryApplicationPath(
+        VOID
+    )
+    {
+        return &m_struApplication;
+    }
+
+    STRU*
+    QueryApplicationPhysicalPath(
+        VOID
+    )
+    {
+        return &m_struApplicationPhysicalPath;
+    }
+
+    STRU*
+    QueryApplicationVirtualPath(
+        VOID
+    )
+    {
+        return &m_struApplicationVirtualPath;
+    }
+
+    STRU*
+    QueryProcessPath(
+            VOID
+    )
+    {
+        return &m_struProcessPath;
+    }
+
+    APP_HOSTING_MODEL
+    QueryHostingModel(
+        VOID
+    )
+    {
+        return m_hostingModel;
+    }
+
+    BOOL
+    QueryStdoutLogEnabled()
+    {
+        return m_fStdoutLogEnabled;
+    }
+
+    BOOL
+    QueryWebSocketEnabled()
+    {
+        return m_fWebSocketEnabled;
+    }
+
+    BOOL
+    QueryForwardWindowsAuthToken()
+    {
+        return m_fForwardWindowsAuthToken;
+    }
+
+    BOOL
+    QueryWindowsAuthEnabled()
+    {
+        return m_fWindowsAuthEnabled;
+    }
+
+    BOOL
+    QueryBasicAuthEnabled()
+    {
+        return m_fBasicAuthEnabled;
+    }
+
+    BOOL
+    QueryAnonymousAuthEnabled()
+    {
+        return m_fAnonymousAuthEnabled;
+    }
+
+    BOOL
+    QueryDisableStartUpErrorPage()
+    {
+        return m_fDisableStartUpErrorPage;
+    }
+
+    STRU*
+    QueryStdoutLogFile()
+    {
+        return &m_struStdoutLogFile;
+    }
+
+    STRU*
+    QueryConfigPath()
+    {
+        return &m_struConfigPath;
+    }
+
+    CONST
+    PCWSTR*
+    QueryHostFxrArguments(
+        VOID
+    )
+    {
+        return m_ppStrArguments;
+    }
+
+    CONST
+    DWORD
+    QueryHostFxrArgCount(
+        VOID
+    )
+    {
+        return m_dwArgc;
+    }
+
+    CONST
+    PCWSTR
+    QueryHostFxrFullPath(
+        VOID
+    )
+    {
+        return m_struHostFxrLocation.QueryStr();
+    }
+
+    HRESULT
+    SetHostFxrFullPath(
+        PCWSTR pStrHostFxrFullPath
+    )
+    {
+        return m_struHostFxrLocation.Copy(pStrHostFxrFullPath);
+    }
+
+    VOID
+    SetHostFxrArguments(
+        DWORD dwArgc,
+        PWSTR* ppStrArguments
+    )
+    {
+        if (m_ppStrArguments != NULL)
+        {
+            delete[] m_ppStrArguments;
+        }
+
+        m_dwArgc = dwArgc;
+        m_ppStrArguments = ppStrArguments;
+    }
+
+    VOID
+    ReferenceConfiguration(
+        VOID
+    ) const;
+
+    VOID
+    DereferenceConfiguration(
+        VOID
+    ) const;
+
+private:
+
+    //
+    // private constructor
+    //    
+    ASPNETCORE_CONFIG():
+        m_fStdoutLogEnabled( FALSE ),
+        m_pEnvironmentVariables( NULL ),
+        m_cRefs( 1 ),
+        m_hostingModel( HOSTING_UNKNOWN ),
+        m_ppStrArguments(NULL)
+    {
+    }
+
+    HRESULT
+    Populate(
+        IHttpServer  *pHttpServer,
+        IHttpContext *pHttpContext
+    );
+
+    mutable LONG           m_cRefs;
+
+    DWORD                  m_dwRequestTimeoutInMS;
+    DWORD                  m_dwStartupTimeLimitInMS;
+    DWORD                  m_dwShutdownTimeLimitInMS;
+    DWORD                  m_dwRapidFailsPerMinute;
+    DWORD                  m_dwProcessesPerApplication;
+    STRU                   m_struArguments;
+    STRU                   m_struProcessPath;
+    STRU                   m_struStdoutLogFile;
+    STRU                   m_struApplication;
+    STRU                   m_struApplicationPhysicalPath;
+    STRU                   m_struApplicationVirtualPath;
+    STRU                   m_struConfigPath;
+    BOOL                   m_fStdoutLogEnabled;
+    BOOL                   m_fForwardWindowsAuthToken;
+    BOOL                   m_fDisableStartUpErrorPage;
+    BOOL                   m_fWindowsAuthEnabled;
+    BOOL                   m_fBasicAuthEnabled;
+    BOOL                   m_fAnonymousAuthEnabled;
+    BOOL                   m_fWebSocketEnabled;
+    APP_HOSTING_MODEL      m_hostingModel;
+    ENVIRONMENT_VAR_HASH*  m_pEnvironmentVariables;
+    STRU                   m_struHostFxrLocation;
+    PWSTR*                m_ppStrArguments;
+    DWORD                  m_dwArgc;
+};
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/CommonLib/debugutil.h b/src/IISIntegration/src/AspNetCoreModuleV2/CommonLib/debugutil.h
new file mode 100644
index 0000000000000000000000000000000000000000..16fce88edd52b8892196a51cedb807cd6f121b92
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/CommonLib/debugutil.h
@@ -0,0 +1,81 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#pragma once
+#define ASPNETCORE_DEBUG_FLAG_INFO          0x00000001
+#define ASPNETCORE_DEBUG_FLAG_WARNING       0x00000002
+#define ASPNETCORE_DEBUG_FLAG_ERROR         0x00000004
+
+extern DWORD g_dwAspNetCoreDebugFlags;
+
+static
+BOOL
+IfDebug(
+    DWORD   dwFlag
+    )
+{
+    return ( dwFlag & g_dwAspNetCoreDebugFlags );
+}
+
+static
+VOID
+DebugPrint(
+    DWORD   dwFlag,
+    LPCSTR  szString
+    )
+{
+    STACK_STRA (strOutput, 256);
+    HRESULT  hr = S_OK;
+
+    if ( IfDebug( dwFlag ) )
+    {
+        hr = strOutput.SafeSnprintf( 
+            "[aspnetcore.dll] %s\r\n",
+            szString );
+
+        if (FAILED (hr))
+        {
+            goto Finished;
+        }
+
+        OutputDebugStringA( strOutput.QueryStr() );
+    }
+
+Finished:
+
+    return;
+}
+
+static
+VOID
+DebugPrintf(
+DWORD   dwFlag,
+LPCSTR  szFormat,
+...
+)
+{
+    STACK_STRA (strCooked,256);
+
+    va_list  args;
+    HRESULT hr = S_OK;
+
+    if ( IfDebug( dwFlag ) )
+    {
+        va_start( args, szFormat );
+
+        hr = strCooked.SafeVsnprintf(szFormat, args );
+
+        va_end( args );
+
+        if (FAILED (hr))
+        {
+            goto Finished;
+        }
+
+        DebugPrint( dwFlag, strCooked.QueryStr() );
+    }
+
+Finished:
+    return;
+}
+
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/CommonLib/environmentvariablehash.h b/src/IISIntegration/src/AspNetCoreModuleV2/CommonLib/environmentvariablehash.h
new file mode 100644
index 0000000000000000000000000000000000000000..8fa054f2a9a9496daa148689cff5583ade9fc8e0
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/CommonLib/environmentvariablehash.h
@@ -0,0 +1,131 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#pragma once
+
+#define HOSTING_STARTUP_ASSEMBLIES_ENV_STR          L"ASPNETCORE_HOSTINGSTARTUPASSEMBLIES"
+#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;"
+#define ASPNETCORE_IIS_AUTH_NONE                    L"none"
+
+//
+// The key used for hash-table lookups, consists of the port on which the http process is created.
+//
+
+class ENVIRONMENT_VAR_ENTRY
+{
+public:
+    ENVIRONMENT_VAR_ENTRY():
+        _cRefs(1)
+    {
+    }
+
+    HRESULT
+    Initialize(
+        PCWSTR      pszName,
+        PCWSTR      pszValue
+    )
+    {
+        HRESULT hr = S_OK;
+        if (FAILED(hr = _strName.Copy(pszName)) ||
+            FAILED(hr = _strValue.Copy(pszValue))) 
+        {
+        }
+        return hr;        
+    }
+
+    VOID 
+    Reference() const
+    {
+        InterlockedIncrement(&_cRefs);
+    }
+
+    VOID
+    Dereference() const
+    {
+        if (InterlockedDecrement(&_cRefs) == 0)
+        {
+            delete this;
+        }
+    }
+
+    PWSTR  const
+    QueryName()
+    {
+        return _strName.QueryStr();
+    }
+
+    PWSTR const
+    QueryValue()
+    {
+        return _strValue.QueryStr();
+    }
+
+private:
+    ~ENVIRONMENT_VAR_ENTRY()
+    {
+    }
+
+    STRU                _strName;
+    STRU                _strValue;
+    mutable LONG        _cRefs;
+};
+
+class ENVIRONMENT_VAR_HASH : public HASH_TABLE<ENVIRONMENT_VAR_ENTRY, PWSTR>
+{
+public:
+    ENVIRONMENT_VAR_HASH()
+    {
+    }
+
+    PWSTR
+    ExtractKey(
+        ENVIRONMENT_VAR_ENTRY *   pEntry
+    )
+    {
+        return pEntry->QueryName();
+    }
+
+    DWORD
+    CalcKeyHash(
+        PWSTR   pszName
+    )
+    {
+        return HashStringNoCase(pszName);
+    }
+
+    BOOL
+    EqualKeys(
+        PWSTR   pszName1,
+        PWSTR   pszName2
+    )
+    {
+        return (_wcsicmp(pszName1, pszName2) == 0);
+    }
+
+    VOID
+    ReferenceRecord(
+        ENVIRONMENT_VAR_ENTRY *   pEntry
+    )
+    {
+        pEntry->Reference();
+    }
+
+    VOID
+    DereferenceRecord(
+        ENVIRONMENT_VAR_ENTRY *   pEntry
+    )
+    {
+        pEntry->Dereference();
+    }
+
+
+private:
+    ENVIRONMENT_VAR_HASH(const ENVIRONMENT_VAR_HASH &);
+    void operator=(const ENVIRONMENT_VAR_HASH &);
+};
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/CommonLib/fx_ver.cxx b/src/IISIntegration/src/AspNetCoreModuleV2/CommonLib/fx_ver.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..7aeb0999c01816a9dde6dc7eef29ed6f0a80dbe7
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/CommonLib/fx_ver.cxx
@@ -0,0 +1,192 @@
+// Copyright (c) .NET Foundation and contributors. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+#include "stdafx.h"
+
+fx_ver_t::fx_ver_t(int major, int minor, int patch, const std::wstring& pre, const std::wstring& build)
+    : m_major(major)
+    , m_minor(minor)
+    , m_patch(patch)
+    , m_pre(pre)
+    , m_build(build)
+{
+}
+
+fx_ver_t::fx_ver_t(int major, int minor, int patch, const std::wstring& pre)
+    : fx_ver_t(major, minor, patch, pre, TEXT(""))
+{
+}
+
+fx_ver_t::fx_ver_t(int major, int minor, int patch)
+    : fx_ver_t(major, minor, patch, TEXT(""), TEXT(""))
+{
+}
+
+bool fx_ver_t::operator ==(const fx_ver_t& b) const
+{
+    return compare(*this, b) == 0;
+}
+
+bool fx_ver_t::operator !=(const fx_ver_t& b) const
+{
+    return !operator ==(b);
+}
+
+bool fx_ver_t::operator <(const fx_ver_t& b) const
+{
+    return compare(*this, b) < 0;
+}
+
+bool fx_ver_t::operator >(const fx_ver_t& b) const
+{
+    return compare(*this, b) > 0;
+}
+
+bool fx_ver_t::operator <=(const fx_ver_t& b) const
+{
+    return compare(*this, b) <= 0;
+}
+
+bool fx_ver_t::operator >=(const fx_ver_t& b) const
+{
+    return compare(*this, b) >= 0;
+}
+
+std::wstring fx_ver_t::as_str() const
+{
+    std::wstringstream stream;
+    stream << m_major << TEXT(".") << m_minor << TEXT(".") << m_patch;
+    if (!m_pre.empty())
+    {
+        stream << m_pre;
+    }
+    if (!m_build.empty())
+    {
+        stream << TEXT("+") << m_build;
+    }
+    return stream.str();
+}
+
+/* static */
+int fx_ver_t::compare(const fx_ver_t&a, const fx_ver_t& b)
+{
+    // compare(u.v.w-p+b, x.y.z-q+c)
+    if (a.m_major != b.m_major)
+    {
+        return (a.m_major > b.m_major) ? 1 : -1;
+    }
+
+    if (a.m_minor != b.m_minor)
+    {
+        return (a.m_minor > b.m_minor) ? 1 : -1;
+    }
+
+    if (a.m_patch != b.m_patch)
+    {
+        return (a.m_patch > b.m_patch) ? 1 : -1;
+    }
+
+    if (a.m_pre.empty() != b.m_pre.empty())
+    {
+        // Either a is empty or b is empty
+        return a.m_pre.empty() ? 1 : -1;
+    }
+
+    // Either both are empty or both are non-empty (may be equal)
+    int pre_cmp = a.m_pre.compare(b.m_pre);
+    if (pre_cmp != 0)
+    {
+        return pre_cmp;
+    }
+
+    return a.m_build.compare(b.m_build);
+}
+
+bool try_stou(const std::wstring& str, unsigned* num)
+{
+    if (str.empty())
+    {
+        return false;
+    }
+    if (str.find_first_not_of(TEXT("0123456789")) != std::wstring::npos)
+    {
+        return false;
+    }
+    *num = (unsigned)std::stoul(str);
+    return true;
+}
+
+bool parse_internal(const std::wstring& ver, fx_ver_t* fx_ver, bool parse_only_production)
+{
+    size_t maj_start = 0;
+    size_t maj_sep = ver.find(TEXT('.'));
+    if (maj_sep == std::wstring::npos)
+    {
+        return false;
+    }
+    unsigned major = 0;
+    if (!try_stou(ver.substr(maj_start, maj_sep), &major))
+    {
+        return false;
+    }
+
+    size_t min_start = maj_sep + 1;
+    size_t min_sep = ver.find(TEXT('.'), min_start);
+    if (min_sep == std::wstring::npos)
+    {
+        return false;
+    }
+
+    unsigned minor = 0;
+    if (!try_stou(ver.substr(min_start, min_sep - min_start), &minor))
+    {
+        return false;
+    }
+
+    unsigned patch = 0;
+    size_t pat_start = min_sep + 1;
+    size_t pat_sep = ver.find_first_not_of(TEXT("0123456789"), pat_start);
+    if (pat_sep == std::wstring::npos)
+    {
+        if (!try_stou(ver.substr(pat_start), &patch))
+        {
+            return false;
+        }
+
+        *fx_ver = fx_ver_t(major, minor, patch);
+        return true;
+    }
+
+    if (parse_only_production)
+    {
+        // This is a prerelease or has build suffix.
+        return false;
+    }
+
+    if (!try_stou(ver.substr(pat_start, pat_sep - pat_start), &patch))
+    {
+        return false;
+    }
+
+    size_t pre_start = pat_sep;
+    size_t pre_sep = ver.find(TEXT('+'), pre_start);
+    if (pre_sep == std::wstring::npos)
+    {
+        *fx_ver = fx_ver_t(major, minor, patch, ver.substr(pre_start));
+        return true;
+    }
+    else
+    {
+        size_t build_start = pre_sep + 1;
+        *fx_ver = fx_ver_t(major, minor, patch, ver.substr(pre_start, pre_sep - pre_start), ver.substr(build_start));
+        return true;
+    }
+}
+
+/* static */
+bool fx_ver_t::parse(const std::wstring& ver, fx_ver_t* fx_ver, bool parse_only_production)
+{
+    bool valid = parse_internal(ver, fx_ver, parse_only_production);
+    assert(!valid || fx_ver->as_str() == ver);
+    return valid;
+}
\ No newline at end of file
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/CommonLib/fx_ver.h b/src/IISIntegration/src/AspNetCoreModuleV2/CommonLib/fx_ver.h
new file mode 100644
index 0000000000000000000000000000000000000000..1626b2697cc0f100d260a028ae5db90f6ff5c4c4
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/CommonLib/fx_ver.h
@@ -0,0 +1,46 @@
+// Copyright (c) .NET Foundation and contributors. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+#pragma once
+
+// Note: This is not SemVer (esp., in comparing pre-release part, fx_ver_t does not
+// compare multiple dot separated identifiers individually.) ex: 1.0.0-beta.2 vs. 1.0.0-beta.11
+struct fx_ver_t
+{
+    fx_ver_t(int major, int minor, int patch);
+    fx_ver_t(int major, int minor, int patch, const std::wstring& pre);
+    fx_ver_t(int major, int minor, int patch, const std::wstring& pre, const std::wstring& build);
+
+    int get_major() const { return m_major; }
+    int get_minor() const { return m_minor; }
+    int get_patch() const { return m_patch; }
+
+    void set_major(int m) { m_major = m; }
+    void set_minor(int m) { m_minor = m; }
+    void set_patch(int p) { m_patch = p; }
+
+    bool is_prerelease() const { return !m_pre.empty(); }
+
+    std::wstring as_str() const;
+    std::wstring prerelease_glob() const;
+    std::wstring patch_glob() const;
+
+    bool operator ==(const fx_ver_t& b) const;
+    bool operator !=(const fx_ver_t& b) const;
+    bool operator <(const fx_ver_t& b) const;
+    bool operator >(const fx_ver_t& b) const;
+    bool operator <=(const fx_ver_t& b) const;
+    bool operator >=(const fx_ver_t& b) const;
+
+    static bool parse(const std::wstring& ver, fx_ver_t* fx_ver, bool parse_only_production = false);
+
+private:
+    int m_major;
+    int m_minor;
+    int m_patch;
+    std::wstring m_pre;
+    std::wstring m_build;
+
+    static int compare(const fx_ver_t&a, const fx_ver_t& b);
+};
+
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/CommonLib/hostfxr_utility.cpp b/src/IISIntegration/src/AspNetCoreModuleV2/CommonLib/hostfxr_utility.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..1ad02feba2abc324f3dcbd5a0fd13eca043cdf93
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/CommonLib/hostfxr_utility.cpp
@@ -0,0 +1,807 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#include "stdafx.h"
+
+HOSTFXR_UTILITY::HOSTFXR_UTILITY()
+{
+}
+
+HOSTFXR_UTILITY::~HOSTFXR_UTILITY()
+{
+}
+
+//
+// Runs a standalone appliction.
+// The folder structure looks like this:
+// Application/
+//   hostfxr.dll
+//   Application.exe
+//   Application.dll
+//   etc.
+// We get the full path to hostfxr.dll and Application.dll and run hostfxr_main,
+// passing in Application.dll.
+// Assuming we don't need Application.exe as the dll is the actual application.
+//
+HRESULT
+HOSTFXR_UTILITY::GetStandaloneHostfxrParameters(
+    PCWSTR              pwzExeAbsolutePath, // includes .exe file extension.
+    PCWSTR              pcwzApplicationPhysicalPath,
+    PCWSTR              pcwzArguments,
+    HANDLE              hEventLog,
+    _Inout_ STRU*       struHostFxrDllLocation,
+    _Out_ DWORD*        pdwArgCount,
+    _Out_ PWSTR**       ppwzArgv
+)
+{
+    HRESULT             hr = S_OK;
+    STRU                struDllPath;
+    STRU                struArguments;
+    STRU                struHostFxrPath;
+    STRU                struRuntimeConfigLocation;
+    DWORD               dwPosition;
+
+    // Obtain the app name from the processPath section.
+    if ( FAILED( hr = struDllPath.Copy( pwzExeAbsolutePath ) ) )
+    {
+        goto Finished;
+    }
+
+    dwPosition = struDllPath.LastIndexOf( L'.', 0 );
+    if ( dwPosition == -1 )
+    {
+        hr = E_FAIL;
+        goto Finished;
+    }
+
+    hr = UTILITY::ConvertPathToFullPath( L".\\hostfxr.dll", pcwzApplicationPhysicalPath, &struHostFxrPath );
+    if ( FAILED( hr ) )
+    {
+        goto Finished;
+    }
+
+	struDllPath.QueryStr()[dwPosition] = L'\0';
+	if (FAILED(hr = struDllPath.SyncWithBuffer()))
+	{
+		goto Finished;
+	}
+
+    if ( !UTILITY::CheckIfFileExists( struHostFxrPath.QueryStr() ) )
+    {
+        // Most likely a full framework app.
+        // Check that the runtime config file doesn't exist in the folder as another heuristic.
+        if (FAILED(hr = struRuntimeConfigLocation.Copy(struDllPath)) ||
+              FAILED(hr = struRuntimeConfigLocation.Append( L".runtimeconfig.json" )))
+        {
+            goto Finished;
+        }
+        if (!UTILITY::CheckIfFileExists(struRuntimeConfigLocation.QueryStr()))
+        {
+
+            hr = E_APPLICATION_ACTIVATION_EXEC_FAILURE;
+            UTILITY::LogEventF(hEventLog,
+                                EVENTLOG_ERROR_TYPE,
+                                ASPNETCORE_EVENT_INPROCESS_FULL_FRAMEWORK_APP,
+                                ASPNETCORE_EVENT_INPROCESS_FULL_FRAMEWORK_APP_MSG,
+                                pcwzApplicationPhysicalPath,
+                                hr);
+        }
+        else
+        {
+            // If a runtime config file does exist, report a file not found on the app.exe
+            hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
+	        UTILITY::LogEventF(hEventLog,
+		        EVENTLOG_ERROR_TYPE,
+		        ASPNETCORE_EVENT_APPLICATION_EXE_NOT_FOUND,
+		        ASPNETCORE_EVENT_APPLICATION_EXE_NOT_FOUND_MSG,
+	            pcwzApplicationPhysicalPath,
+	            hr);
+        }
+
+        goto Finished;
+    }
+
+    if (FAILED(hr = struHostFxrDllLocation->Copy(struHostFxrPath)))
+    {
+        goto Finished;
+    }
+
+
+    if (FAILED(hr = struDllPath.Append(L".dll")))
+    {
+        goto Finished;
+    }
+
+    if (!UTILITY::CheckIfFileExists(struDllPath.QueryStr()))
+    {
+        // Treat access issue as File not found
+        hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
+        goto Finished;
+    }
+
+    if (FAILED(hr = struArguments.Copy(struDllPath)) ||
+        FAILED(hr = struArguments.Append(L" ")) ||
+        FAILED(hr = struArguments.Append(pcwzArguments)))
+    {
+        goto Finished;
+    }
+
+    if (FAILED(hr = ParseHostfxrArguments(
+        struArguments.QueryStr(),
+        pwzExeAbsolutePath,
+        pcwzApplicationPhysicalPath,
+        hEventLog,
+        pdwArgCount,
+        ppwzArgv)))
+    {
+        goto Finished;
+    }
+
+Finished:
+
+    return hr;
+}
+
+HRESULT
+HOSTFXR_UTILITY::GetHostFxrParameters(
+    HANDLE              hEventLog,
+    PCWSTR              pcwzProcessPath,
+    PCWSTR              pcwzApplicationPhysicalPath,
+    PCWSTR              pcwzArguments,
+    _Inout_ STRU*		struHostFxrDllLocation,
+    _Out_ DWORD*		pdwArgCount,
+    _Out_ BSTR**		pbstrArgv
+)
+{
+    HRESULT                     hr = S_OK;
+    STRU                        struSystemPathVariable;
+    STRU                        struAbsolutePathToHostFxr;
+    STRU                        struAbsolutePathToDotnet;
+    STRU                        struEventMsg;
+    STACK_STRU(struExpandedProcessPath, MAX_PATH);
+    STACK_STRU(struExpandedArguments, MAX_PATH);
+
+    // Copy and Expand the processPath and Arguments.
+    if (FAILED(hr = struExpandedProcessPath.CopyAndExpandEnvironmentStrings(pcwzProcessPath))
+        || FAILED(hr = struExpandedArguments.CopyAndExpandEnvironmentStrings(pcwzArguments)))
+    {
+        goto Finished;
+    }
+
+    // Convert the process path an absolute path to our current application directory.
+    // If the path is already an absolute path, it will be unchanged.
+    hr = UTILITY::ConvertPathToFullPath(
+        struExpandedProcessPath.QueryStr(),
+        pcwzApplicationPhysicalPath,
+        &struAbsolutePathToDotnet
+    );
+
+    if (FAILED(hr))
+    {
+        goto Finished;
+    }
+
+    // Check if the absolute path is to dotnet or not.
+    if (struAbsolutePathToDotnet.EndsWith(L"dotnet.exe") || struAbsolutePathToDotnet.EndsWith(L"dotnet"))
+    {
+        //
+        // The processPath ends with dotnet.exe or dotnet
+        // like: C:\Program Files\dotnet\dotnet.exe, C:\Program Files\dotnet\dotnet, dotnet.exe, or dotnet.
+        // Get the absolute path to dotnet. If the path is already an absolute path, it will return that path
+        //
+        if (FAILED(hr = HOSTFXR_UTILITY::GetAbsolutePathToDotnet(&struAbsolutePathToDotnet))) // Make sure to append the dotnet.exe path correctly here (pass in regular path)?
+        {
+            goto Finished;
+        }
+
+        if (FAILED(hr = GetAbsolutePathToHostFxr(&struAbsolutePathToDotnet, hEventLog, &struAbsolutePathToHostFxr)))
+        {
+            goto Finished;
+        }
+
+        if (FAILED(hr = ParseHostfxrArguments(
+            struExpandedArguments.QueryStr(),
+            struAbsolutePathToDotnet.QueryStr(),
+            pcwzApplicationPhysicalPath,
+            hEventLog,
+            pdwArgCount,
+            pbstrArgv)))
+        {
+            goto Finished;
+        }
+
+        if (FAILED(hr = struHostFxrDllLocation->Copy(struAbsolutePathToHostFxr)))
+        {
+            goto Finished;
+        }
+    }
+    else
+    {
+        //
+        // The processPath is a path to the application executable
+        // like: C:\test\MyApp.Exe or MyApp.Exe
+        // Check if the file exists, and if it does, get the parameters for a standalone application
+        //
+        if (UTILITY::CheckIfFileExists(struAbsolutePathToDotnet.QueryStr()))
+        {
+            hr = GetStandaloneHostfxrParameters(
+                struAbsolutePathToDotnet.QueryStr(),
+                pcwzApplicationPhysicalPath,
+                struExpandedArguments.QueryStr(),
+                hEventLog,
+                struHostFxrDllLocation,
+                pdwArgCount,
+                pbstrArgv);
+        }
+        else
+        {
+            //
+            // If the processPath file does not exist and it doesn't include dotnet.exe or dotnet
+            // then it is an invalid argument.
+            //
+            hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);;
+            UTILITY::LogEventF(hEventLog,
+                EVENTLOG_ERROR_TYPE,
+                ASPNETCORE_EVENT_GENERAL_ERROR_MSG,
+                ASPNETCORE_EVENT_INVALID_PROCESS_PATH_MSG,
+                struExpandedProcessPath.QueryStr(),
+                hr);
+        }
+    }
+
+Finished:
+
+    return hr;
+}
+
+//
+// Forms the argument list in HOSTFXR_PARAMETERS.
+// Sets the ArgCount and Arguments.
+// Arg structure:
+// argv[0] = Path to exe activating hostfxr.
+// argv[1] = L"exec"
+// argv[2] = absolute path to dll.
+//
+HRESULT
+HOSTFXR_UTILITY::ParseHostfxrArguments(
+    PCWSTR              pwzArgumentsFromConfig,
+    PCWSTR              pwzExePath,
+    PCWSTR              pcwzApplicationPhysicalPath,
+    HANDLE              hEventLog,
+    _Out_ DWORD*        pdwArgCount,
+    _Out_ BSTR**        pbstrArgv
+)
+{
+    UNREFERENCED_PARAMETER( hEventLog ); // TODO use event log to set errors.
+
+	DBG_ASSERT(dwArgCount != NULL);
+	DBG_ASSERT(pwzArgv != NULL);
+
+    HRESULT     hr = S_OK;
+    INT         argc = 0;
+    BSTR*       argv = NULL;
+    LPWSTR*     pwzArgs = NULL;
+    STRU        struTempPath;
+    INT         intArgsProcessed = 0;
+
+    // If we call CommandLineToArgvW with an empty string, argc is 5 for some interesting reason.
+    // Protectively guard against this by check if the string is null or empty.
+    if (pwzArgumentsFromConfig == NULL || wcscmp(pwzArgumentsFromConfig, L"") == 0)
+    {
+        hr = E_INVALIDARG;
+        goto Finished;
+    }
+
+    pwzArgs = CommandLineToArgvW(pwzArgumentsFromConfig, &argc);
+
+    if (pwzArgs == NULL)
+    {
+        hr = HRESULT_FROM_WIN32(GetLastError());
+        goto Failure;
+    }
+
+    argv = new BSTR[argc + 1];
+    if (argv == NULL)
+    {
+        hr = E_OUTOFMEMORY;
+        goto Failure;
+    }
+
+    argv[0] = SysAllocString(pwzExePath);
+
+    if (argv[0] == NULL)
+    {
+        hr = E_OUTOFMEMORY;
+        goto Failure;
+    }
+
+    // Try to convert the application dll from a relative to an absolute path
+    // Don't record this failure as pwzArgs[0] may already be an absolute path to the dll.
+    for (intArgsProcessed = 0; intArgsProcessed < argc; intArgsProcessed++)
+    {
+        struTempPath.Copy(pwzArgs[intArgsProcessed]);
+        if (struTempPath.EndsWith(L".dll"))
+        {
+            if (SUCCEEDED(UTILITY::ConvertPathToFullPath(pwzArgs[intArgsProcessed], pcwzApplicationPhysicalPath, &struTempPath)))
+            {
+                argv[intArgsProcessed + 1] = SysAllocString(struTempPath.QueryStr());
+            }
+            else
+            {
+                argv[intArgsProcessed + 1] = SysAllocString(pwzArgs[intArgsProcessed]);
+            }
+            if (argv[intArgsProcessed + 1] == NULL)
+            {
+                hr = E_OUTOFMEMORY;
+                goto Failure;
+            }
+        }
+        else
+        {
+            argv[intArgsProcessed + 1] = SysAllocString(pwzArgs[intArgsProcessed]);
+            if (argv[intArgsProcessed + 1] == NULL)
+            {
+                hr = E_OUTOFMEMORY;
+                goto Failure;
+            }
+        }
+    }
+
+    *pbstrArgv = argv;
+    *pdwArgCount = argc + 1;
+
+    goto Finished;
+
+Failure:
+    if (argv != NULL)
+    {
+        // intArgsProcess - 1 here as if we fail to allocated the ith string
+        // we don't want to free it.
+        for (INT i = 0; i < intArgsProcessed - 1; i++)
+        {
+            SysFreeString(argv[i]);
+        }
+    }
+
+    delete[] argv;
+
+Finished:
+    if (pwzArgs != NULL)
+    {
+        LocalFree(pwzArgs);
+        DBG_ASSERT(pwzArgs == NULL);
+    }
+    return hr;
+}
+
+HRESULT
+HOSTFXR_UTILITY::GetAbsolutePathToDotnet(
+    _Inout_ STRU* pStruAbsolutePathToDotnet
+)
+{
+    HRESULT             hr = S_OK;
+
+    //
+    // If we are given an absolute path to dotnet.exe, we are done
+    //
+    if (UTILITY::CheckIfFileExists(pStruAbsolutePathToDotnet->QueryStr()))
+    {
+        goto Finished;
+    }
+
+    //
+    // If the path was C:\Program Files\dotnet\dotnet
+    // We need to try appending .exe and check if the file exists too.
+    //
+    if (FAILED(hr = pStruAbsolutePathToDotnet->Append(L".exe")))
+    {
+        goto Finished;
+    }
+
+    if (UTILITY::CheckIfFileExists(pStruAbsolutePathToDotnet->QueryStr()))
+    {
+        goto Finished;
+    }
+
+    // At this point, we are calling where.exe to find dotnet.
+    // If we encounter any failures, try getting dotnet.exe from the
+    // backup location.
+    if (!InvokeWhereToFindDotnet(pStruAbsolutePathToDotnet))
+    {
+        hr = GetAbsolutePathToDotnetFromProgramFiles(pStruAbsolutePathToDotnet);
+    }
+
+Finished:
+
+    return hr;
+}
+
+HRESULT
+HOSTFXR_UTILITY::GetAbsolutePathToHostFxr(
+    STRU* pStruAbsolutePathToDotnet,
+    HANDLE hEventLog,
+    STRU* pStruAbsolutePathToHostfxr
+)
+{
+    HRESULT                     hr = S_OK;
+    STRU                        struHostFxrPath;
+    STRU                        struHostFxrSearchExpression;
+    STRU                        struHighestDotnetVersion;
+    STRU                        struEventMsg;
+    std::vector<std::wstring>   vVersionFolders;
+    DWORD                       dwPosition = 0;
+
+    if (FAILED(hr = struHostFxrPath.Copy(pStruAbsolutePathToDotnet)))
+    {
+        goto Finished;
+    }
+
+    dwPosition = struHostFxrPath.LastIndexOf(L'\\', 0);
+    if (dwPosition == -1)
+    {
+        hr = E_FAIL;
+        goto Finished;
+    }
+
+    struHostFxrPath.QueryStr()[dwPosition] = L'\0';
+
+    if (FAILED(hr = struHostFxrPath.SyncWithBuffer()) ||
+        FAILED(hr = struHostFxrPath.Append(L"\\")))
+    {
+        goto Finished;
+    }
+
+    hr = struHostFxrPath.Append(L"host\\fxr");
+    if (FAILED(hr))
+    {
+        goto Finished;
+    }
+
+    if (!UTILITY::DirectoryExists(&struHostFxrPath))
+    {
+        hr = ERROR_BAD_ENVIRONMENT;
+        UTILITY::LogEventF(hEventLog,
+            EVENTLOG_ERROR_TYPE,
+            ASPNETCORE_EVENT_HOSTFXR_DIRECTORY_NOT_FOUND,
+            struEventMsg.QueryStr(),
+            ASPNETCORE_EVENT_HOSTFXR_DIRECTORY_NOT_FOUND_MSG,
+            struHostFxrPath.QueryStr(),
+            hr);
+        goto Finished;
+    }
+
+    // Find all folders under host\\fxr\\ for version numbers.
+    hr = struHostFxrSearchExpression.Copy(struHostFxrPath);
+    if (FAILED(hr))
+    {
+        goto Finished;
+    }
+
+    hr = struHostFxrSearchExpression.Append(L"\\*");
+    if (FAILED(hr))
+    {
+        goto Finished;
+    }
+
+    // As we use the logic from core-setup, we are opting to use std here.
+    UTILITY::FindDotNetFolders(struHostFxrSearchExpression.QueryStr(), &vVersionFolders);
+
+    if (vVersionFolders.size() == 0)
+    {
+        hr = HRESULT_FROM_WIN32(ERROR_BAD_ENVIRONMENT);
+        UTILITY::LogEventF(hEventLog,
+            EVENTLOG_ERROR_TYPE,
+            ASPNETCORE_EVENT_HOSTFXR_DIRECTORY_NOT_FOUND,
+            ASPNETCORE_EVENT_HOSTFXR_DIRECTORY_NOT_FOUND_MSG,
+            struHostFxrPath.QueryStr(),
+            hr);
+        goto Finished;
+    }
+
+    hr = UTILITY::FindHighestDotNetVersion(vVersionFolders, &struHighestDotnetVersion);
+    if (FAILED(hr))
+    {
+        goto Finished;
+    }
+
+    if (FAILED(hr = struHostFxrPath.Append(L"\\"))
+        || FAILED(hr = struHostFxrPath.Append(struHighestDotnetVersion.QueryStr()))
+        || FAILED(hr = struHostFxrPath.Append(L"\\hostfxr.dll")))
+    {
+        goto Finished;
+    }
+
+    if (!UTILITY::CheckIfFileExists(struHostFxrPath.QueryStr()))
+    {
+        // ASPNETCORE_EVENT_HOSTFXR_DLL_NOT_FOUND_MSG
+        hr = HRESULT_FROM_WIN32(ERROR_FILE_INVALID);
+        UTILITY::LogEventF(hEventLog,
+            EVENTLOG_ERROR_TYPE,
+            ASPNETCORE_EVENT_HOSTFXR_DLL_NOT_FOUND,
+            ASPNETCORE_EVENT_HOSTFXR_DLL_NOT_FOUND_MSG,
+            struHostFxrPath.QueryStr(),
+            hr);
+        goto Finished;
+    }
+
+    if (FAILED(hr = pStruAbsolutePathToHostfxr->Copy(struHostFxrPath)))
+    {
+        goto Finished;
+    }
+
+Finished:
+    return hr;
+}
+
+//
+// Tries to call where.exe to find the location of dotnet.exe.
+// Will check that the bitness of dotnet matches the current
+// worker process bitness.
+// Returns true if a valid dotnet was found, else false.
+//
+BOOL
+HOSTFXR_UTILITY::InvokeWhereToFindDotnet(
+    _Inout_ STRU* pStruAbsolutePathToDotnet
+)
+{
+    HRESULT             hr = S_OK;
+    // Arguments to call where.exe
+    STARTUPINFOW        startupInfo = { 0 };
+    PROCESS_INFORMATION processInformation = { 0 };
+    SECURITY_ATTRIBUTES securityAttributes;
+
+    CHAR                pzFileContents[READ_BUFFER_SIZE];
+    HANDLE              hStdOutReadPipe = INVALID_HANDLE_VALUE;
+    HANDLE              hStdOutWritePipe = INVALID_HANDLE_VALUE;
+    LPWSTR              pwzDotnetName = NULL;
+    DWORD               dwFilePointer;
+    BOOL                fIsWow64Process;
+    BOOL                fIsCurrentProcess64Bit;
+    DWORD               dwExitCode;
+    STRU                struDotnetSubstring;
+    STRU                struDotnetLocationsString;
+    DWORD               dwNumBytesRead;
+    DWORD               dwBinaryType;
+    INT                 index = 0;
+    INT                 prevIndex = 0;
+    BOOL                fProcessCreationResult = FALSE;
+    BOOL                fResult = FALSE;
+
+    // Set the security attributes for the read/write pipe
+    securityAttributes.nLength = sizeof(securityAttributes);
+    securityAttributes.lpSecurityDescriptor = NULL;
+    securityAttributes.bInheritHandle = TRUE;
+
+    // Reset the path to dotnet as we will be using whether the string is
+    // empty or not as state
+    pStruAbsolutePathToDotnet->Reset();
+
+    // Create a read/write pipe that will be used for reading the result of where.exe
+    if (!CreatePipe(&hStdOutReadPipe, &hStdOutWritePipe, &securityAttributes, 0))
+    {
+        hr = HRESULT_FROM_WIN32(GetLastError());
+        goto Finished;
+    }
+    if (!SetHandleInformation(hStdOutReadPipe, HANDLE_FLAG_INHERIT, 0))
+    {
+        hr = ERROR_FILE_INVALID;
+        goto Finished;
+    }
+
+    // Set the stdout and err pipe to the write pipes.
+    startupInfo.cb = sizeof(startupInfo);
+    startupInfo.dwFlags |= STARTF_USESTDHANDLES;
+    startupInfo.hStdOutput = hStdOutWritePipe;
+    startupInfo.hStdError = hStdOutWritePipe;
+
+    // CreateProcess requires a mutable string to be passed to commandline
+    // See https://blogs.msdn.microsoft.com/oldnewthing/20090601-00/?p=18083/
+    pwzDotnetName = SysAllocString(L"\"where.exe\" dotnet.exe");
+    if (pwzDotnetName == NULL)
+    {
+        goto Finished;
+    }
+
+    // Create a process to invoke where.exe
+    fProcessCreationResult = CreateProcessW(NULL,
+        pwzDotnetName,
+        NULL,
+        NULL,
+        TRUE,
+        CREATE_NO_WINDOW,
+        NULL,
+        NULL,
+        &startupInfo,
+        &processInformation
+    );
+
+    if (!fProcessCreationResult)
+    {
+        goto Finished;
+    }
+
+    // Wait for where.exe to return, waiting 2 seconds.
+    if (WaitForSingleObject(processInformation.hProcess, 2000) != WAIT_OBJECT_0)
+    {
+        // Timeout occured, terminate the where.exe process and return.
+        TerminateProcess(processInformation.hProcess, 2);
+        hr = HRESULT_FROM_WIN32(ERROR_TIMEOUT);
+        goto Finished;
+    }
+
+    //
+    // where.exe will return 0 on success, 1 if the file is not found
+    // and 2 if there was an error. Check if the exit code is 1 and set
+    // a new hr result saying it couldn't find dotnet.exe
+    //
+    if (!GetExitCodeProcess(processInformation.hProcess, &dwExitCode))
+    {
+        goto Finished;
+    }
+
+    //
+    // In this block, if anything fails, we will goto our fallback of
+    // looking in C:/Program Files/
+    //
+    if (dwExitCode != 0)
+    {
+        goto Finished;
+    }
+
+    // Where succeeded.
+    // Reset file pointer to the beginning of the file.
+    dwFilePointer = SetFilePointer(hStdOutReadPipe, 0, NULL, FILE_BEGIN);
+    if (dwFilePointer == INVALID_SET_FILE_POINTER)
+    {
+        goto Finished;
+    }
+
+    //
+    // As the call to where.exe succeeded (dotnet.exe was found), ReadFile should not hang.
+    // TODO consider putting ReadFile in a separate thread with a timeout to guarantee it doesn't block.
+    //
+    if (!ReadFile(hStdOutReadPipe, pzFileContents, READ_BUFFER_SIZE, &dwNumBytesRead, NULL))
+    {
+        goto Finished;
+    }
+
+    if (dwNumBytesRead >= READ_BUFFER_SIZE)
+    {
+        // This shouldn't ever be this large. We could continue to call ReadFile in a loop,
+        // however if someone had this many dotnet.exes on their machine.
+        goto Finished;
+    }
+
+    hr = HRESULT_FROM_WIN32(GetLastError());
+    if (FAILED(hr = struDotnetLocationsString.CopyA(pzFileContents, dwNumBytesRead)))
+    {
+        goto Finished;
+    }
+
+    // Check the bitness of the currently running process
+    // matches the dotnet.exe found.
+    if (!IsWow64Process(GetCurrentProcess(), &fIsWow64Process))
+    {
+        // Calling IsWow64Process failed
+        goto Finished;
+    }
+    if (fIsWow64Process)
+    {
+        // 32 bit mode
+        fIsCurrentProcess64Bit = FALSE;
+    }
+    else
+    {
+        // Check the SystemInfo to see if we are currently 32 or 64 bit.
+        SYSTEM_INFO systemInfo;
+        GetNativeSystemInfo(&systemInfo);
+        fIsCurrentProcess64Bit = systemInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64;
+    }
+
+    while (TRUE)
+    {
+        index = struDotnetLocationsString.IndexOf(L"\r\n", prevIndex);
+        if (index == -1)
+        {
+            break;
+        }
+        if (FAILED(hr = struDotnetSubstring.Copy(&struDotnetLocationsString.QueryStr()[prevIndex], index - prevIndex)))
+        {
+            goto Finished;
+        }
+        // \r\n is two wchars, so add 2 here.
+        prevIndex = index + 2;
+
+        if (GetBinaryTypeW(struDotnetSubstring.QueryStr(), &dwBinaryType) &&
+            fIsCurrentProcess64Bit == (dwBinaryType == SCS_64BIT_BINARY))
+        {
+            // The bitness of dotnet matched with the current worker process bitness.
+            if (FAILED(hr = pStruAbsolutePathToDotnet->Copy(struDotnetSubstring)))
+            {
+                goto Finished;
+            }
+            fResult = TRUE;
+            break;
+        }
+    }
+
+Finished:
+
+    if (hStdOutReadPipe != INVALID_HANDLE_VALUE)
+    {
+        CloseHandle(hStdOutReadPipe);
+    }
+    if (hStdOutWritePipe != INVALID_HANDLE_VALUE)
+    {
+        CloseHandle(hStdOutWritePipe);
+    }
+    if (processInformation.hProcess != INVALID_HANDLE_VALUE)
+    {
+        CloseHandle(processInformation.hProcess);
+    }
+    if (processInformation.hThread != INVALID_HANDLE_VALUE)
+    {
+        CloseHandle(processInformation.hThread);
+    }
+    if (pwzDotnetName != NULL)
+    {
+        SysFreeString(pwzDotnetName);
+    }
+
+    return fResult;
+}
+
+
+HRESULT
+HOSTFXR_UTILITY::GetAbsolutePathToDotnetFromProgramFiles(
+    _Inout_ STRU* pStruAbsolutePathToDotnet
+)
+{
+    HRESULT hr = S_OK;
+    BOOL fFound = FALSE;
+    DWORD dwNumBytesRead = 0;
+    DWORD dwPathSize = MAX_PATH;
+    STRU struDotnetSubstring;
+
+    while (!fFound)
+    {
+        if (FAILED(hr = struDotnetSubstring.Resize(dwPathSize)))
+        {
+            goto Finished;
+        }
+
+        dwNumBytesRead = GetEnvironmentVariable(L"ProgramFiles", struDotnetSubstring.QueryStr(), dwPathSize);
+        if (dwNumBytesRead == 0)
+        {
+            hr = HRESULT_FROM_WIN32(GetLastError());
+            goto Finished;
+        }
+        else if (dwNumBytesRead >= dwPathSize)
+        {
+            //
+            // The path to ProgramFiles should never be this long, but resize and try again.
+            dwPathSize *= 2 + 30; // for dotnet substring
+        }
+        else
+        {
+            if (FAILED(hr = struDotnetSubstring.SyncWithBuffer()) ||
+                FAILED(hr = struDotnetSubstring.Append(L"\\dotnet\\dotnet.exe")))
+            {
+                goto Finished;
+            }
+            if (!UTILITY::CheckIfFileExists(struDotnetSubstring.QueryStr()))
+            {
+                hr = HRESULT_FROM_WIN32(GetLastError());
+                goto Finished;
+            }
+            if (FAILED(hr = pStruAbsolutePathToDotnet->Copy(struDotnetSubstring)))
+            {
+                goto Finished;
+            }
+            fFound = TRUE;
+        }
+    }
+
+Finished:
+    return hr;
+}
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/CommonLib/hostfxr_utility.h b/src/IISIntegration/src/AspNetCoreModuleV2/CommonLib/hostfxr_utility.h
new file mode 100644
index 0000000000000000000000000000000000000000..e7703c5bfa30708e070b77d434765e96e6c2182a
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/CommonLib/hostfxr_utility.h
@@ -0,0 +1,78 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#pragma once
+
+typedef INT(*hostfxr_get_native_search_directories_fn) (CONST INT argc, CONST PCWSTR* argv, PWSTR buffer, DWORD buffer_size, DWORD* required_buffer_size);
+typedef INT(*hostfxr_main_fn) (CONST DWORD argc, CONST PCWSTR argv[]);
+
+#define READ_BUFFER_SIZE 4096
+
+class HOSTFXR_UTILITY
+{
+public:
+    HOSTFXR_UTILITY();
+    ~HOSTFXR_UTILITY();
+
+	static
+	HRESULT
+	GetHostFxrParameters(
+        HANDLE              hEventLog,
+        PCWSTR				pcwzProcessPath,
+        PCWSTR              pcwzApplicationPhysicalPath,
+        PCWSTR              pcwzArguments,
+        _Inout_ STRU*       pStruHostFxrDllLocation,
+        _Out_ DWORD*        pdwArgCount,
+        _Out_ BSTR**       ppwzArgv
+	);
+
+    static
+    HRESULT
+    GetStandaloneHostfxrParameters(
+        PCWSTR              pwzExeAbsolutePath, // includes .exe file extension.
+        PCWSTR				pcwzApplicationPhysicalPath,
+        PCWSTR              pcwzArguments,
+        HANDLE              hEventLog,
+        _Inout_ STRU*		pStruHostFxrDllLocation,
+        _Out_ DWORD*		pdwArgCount,
+        _Out_ BSTR**		ppwzArgv
+    );
+
+    static
+    HRESULT
+    ParseHostfxrArguments(
+        PCWSTR              pwzArgumentsFromConfig,
+        PCWSTR              pwzExePath, 
+        PCWSTR				pcwzApplicationPhysicalPath,
+        HANDLE              hEventLog,
+        _Out_ DWORD*        pdwArgCount,
+        _Out_ BSTR**        ppwzArgv
+    );
+
+    static
+    HRESULT
+    GetAbsolutePathToDotnet(
+        STRU*   pStruAbsolutePathToDotnet
+    );
+
+    static
+    HRESULT
+    GetAbsolutePathToHostFxr(
+        _In_ STRU* pStruAbsolutePathToDotnet,
+        _In_ HANDLE hEventLog,
+        _Out_ STRU* pStruAbsolutePathToHostfxr
+    );
+
+    static
+    BOOL
+    InvokeWhereToFindDotnet(
+        _Inout_ STRU* pStruAbsolutePathToDotnet
+    );
+
+    static
+    HRESULT
+    GetAbsolutePathToDotnetFromProgramFiles(
+        _Inout_ STRU* pStruAbsolutePathToDotnet
+    );
+};
+
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/CommonLib/requesthandler.cxx b/src/IISIntegration/src/AspNetCoreModuleV2/CommonLib/requesthandler.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..bcf1887d354365b6c4789d33b3ca96d4887f303f
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/CommonLib/requesthandler.cxx
@@ -0,0 +1,44 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#include "stdafx.h"
+
+REQUEST_HANDLER::REQUEST_HANDLER(
+    _In_ IHttpContext *pW3Context,
+    _In_ HTTP_MODULE_ID  *pModuleId,
+    _In_ APPLICATION  *pApplication)
+    : m_cRefs(1)
+{
+    m_pW3Context = pW3Context;
+    m_pApplication = pApplication;
+    m_pModuleId = *pModuleId;
+}
+
+
+REQUEST_HANDLER::~REQUEST_HANDLER()
+{
+}
+
+VOID
+REQUEST_HANDLER::ReferenceRequestHandler(
+    VOID
+) const
+{
+    InterlockedIncrement(&m_cRefs);
+}
+
+
+VOID
+REQUEST_HANDLER::DereferenceRequestHandler(
+    VOID
+) const
+{
+    DBG_ASSERT(m_cRefs != 0);
+
+    LONG cRefs = 0;
+    if ((cRefs = InterlockedDecrement(&m_cRefs)) == 0)
+    {
+        delete this;
+    }
+
+}
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/CommonLib/requesthandler.h b/src/IISIntegration/src/AspNetCoreModuleV2/CommonLib/requesthandler.h
new file mode 100644
index 0000000000000000000000000000000000000000..28f4fb725eec5a3494a4665475568290c4eaacd5
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/CommonLib/requesthandler.h
@@ -0,0 +1,59 @@
+// 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 "stdafx.h"
+#include "application.h"
+
+//
+// Abstract class
+//
+class REQUEST_HANDLER
+{
+public:
+    REQUEST_HANDLER(
+        _In_ IHttpContext *pW3Context,
+        _In_ HTTP_MODULE_ID  *pModuleId,
+        _In_ APPLICATION  *pApplication
+    );
+
+    virtual
+    REQUEST_NOTIFICATION_STATUS
+    OnExecuteRequestHandler() = 0;
+
+    virtual
+    REQUEST_NOTIFICATION_STATUS
+    OnAsyncCompletion(
+        DWORD      cbCompletion,
+        HRESULT    hrCompletionStatus
+    ) = 0;
+
+    virtual
+    VOID
+    TerminateRequest(
+        bool    fClientInitiated
+    ) = 0;
+
+    virtual
+    ~REQUEST_HANDLER(
+        VOID
+    );
+
+    VOID
+    ReferenceRequestHandler(
+        VOID
+    ) const;
+
+    virtual
+    VOID
+    DereferenceRequestHandler(
+        VOID
+    ) const;
+
+protected:
+    mutable LONG    m_cRefs;
+    IHttpContext*   m_pW3Context;
+    APPLICATION*    m_pApplication;
+    HTTP_MODULE_ID   m_pModuleId;
+};
\ No newline at end of file
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/CommonLib/resources.h b/src/IISIntegration/src/AspNetCoreModuleV2/CommonLib/resources.h
new file mode 100644
index 0000000000000000000000000000000000000000..140a573f3f5f46fcae0570026e913344353cd9ed
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/CommonLib/resources.h
@@ -0,0 +1,47 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#pragma once
+
+#define IDS_INVALID_PROPERTY        1000
+#define IDS_SERVER_ERROR            1001
+
+#define ASPNETCORE_EVENT_PROVIDER L"IIS AspNetCore Module"
+#define ASPNETCORE_IISEXPRESS_EVENT_PROVIDER L"IIS Express AspNetCore Module"
+
+#define ASPNETCORE_EVENT_MSG_BUFFER_SIZE 256
+#define ASPNETCORE_EVENT_PROCESS_START_SUCCESS_MSG           L"Application '%s' started process '%d' successfully and process '%d' is listening on port '%d'."
+#define ASPNETCORE_EVENT_RAPID_FAIL_COUNT_EXCEEDED_MSG       L"Maximum rapid fail count per minute of '%d' exceeded."
+#define ASPNETCORE_EVENT_PROCESS_START_ERROR_MSG             L"Application '%s' with physical root '%s' failed to start process with commandline '%s' at stage '%s', ErrorCode = '0x%x', assigned port %d, retryCounter '%d'."
+#define ASPNETCORE_EVENT_PROCESS_START_FAILURE_MSG           L"Application '%s' with physical root '%s' failed to start process with commandline '%s' with multiple retries. The last try of listening port is '%d'. See pervious warnings for details."
+#define ASPNETCORE_EVENT_PROCESS_START_STATUS_ERROR_MSG      L"Application '%s' with physical root '%s' failed to start process with commandline '%s' , ErrorCode = '0x%x', processId '%d', processStatus '%d'."
+#define ASPNETCORE_EVENT_PROCESS_START_PORTSETUP_ERROR_MSG   L"Application '%s' with physical root '%s' failed to choose listen port '%d' given port rang '%d - %d', EorrorCode = '0x%x'. If environment variable 'ASPNETCORE_PORT' was set, try removing it such that a random port is selected instead."
+#define ASPNETCORE_EVENT_PROCESS_START_WRONGPORT_ERROR_MSG   L"Application '%s' with physical root '%s' created process with commandline '%s' but failed to listen on the given port '%d'"
+#define ASPNETCORE_EVENT_PROCESS_START_NOTREADY_ERROR_MSG    L"Application '%s' with physical root '%s' created process with commandline '%s' but either crashed or did not respond or did not listen on the given port '%d', ErrorCode = '0x%x'"
+#define ASPNETCORE_EVENT_PROCESS_SHUTDOWN_MSG                L"Application '%s' with physical root '%s' shut down process with Id '%d' listening on port '%d'"
+#define ASPNETCORE_EVENT_INVALID_STDOUT_LOG_FILE_MSG         L"Warning: Could not create stdoutLogFile %s, ErrorCode = '0x%x'."
+#define ASPNETCORE_EVENT_GRACEFUL_SHUTDOWN_FAILURE_MSG       L"Failed to gracefully shutdown process '%d'."
+#define ASPNETCORE_EVENT_SENT_SHUTDOWN_HTTP_REQUEST_MSG      L"Sent shutdown HTTP message to process '%d' and received http status '%d'."
+#define ASPNETCORE_EVENT_APP_SHUTDOWN_FAILURE_MSG            L"Failed to gracefully shutdown application '%s'."
+#define ASPNETCORE_EVENT_LOAD_CLR_FALIURE_MSG                L"Application '%s' with physical root '%s' failed to load clr and managed application, ErrorCode = '0x%x."
+#define ASPNETCORE_EVENT_DUPLICATED_INPROCESS_APP_MSG        L"Only one inprocess application is allowed per IIS application pool. Please assign the application '%s' to a different IIS application pool."
+#define ASPNETCORE_EVENT_MIXED_HOSTING_MODEL_ERROR_MSG       L"Mixed hosting model is not supported. Application '%s' configured with different hostingModel value '%d' other than the one of running application(s)."
+#define ASPNETCORE_EVENT_ADD_APPLICATION_ERROR_MSG           L"Failed to start application '%s', ErrorCode '0x%x'."
+#define ASPNETCORE_EVENT_INPROCESS_THREAD_EXIT_STDERR_MSG    L"Application '%s' with physical root '%s' hit unexpected managed background thread exit, ErrorCode = '0x%x. First 4KB characters of captured stderr logs on startup:\r\n%s"
+#define ASPNETCORE_EVENT_INPROCESS_THREAD_EXIT_STDOUT_MSG    L"Application '%s' with physical root '%s' hit unexpected managed background thread exit, ErrorCode = '0x%x. Last 4KB characters of captured stdout and stderr logs:\r\n%s"
+#define ASPNETCORE_EVENT_INPROCESS_THREAD_EXIT_MSG           L"Application '%s' with physical root '%s' hit unexpected managed background thread exit, ErrorCode = '0x%x. Please check the stderr logs for more information."
+#define ASPNETCORE_EVENT_APP_IN_SHUTDOWN_MSG                 L"Application shutting down."
+#define ASPNETCORE_EVENT_RECYCLE_APPOFFLINE_MSG              L"Application '%s' was recycled after detecting the app_offline file."
+#define ASPNETCORE_EVENT_RECYCLE_APPOFFLINE_REMOVED_MSG      L"App_offline.htm has been removed from the application. Application will be recycled."
+#define ASPNETCORE_EVENT_RECYCLE_CONFIGURATION_MSG           L"Application '%s' was recycled due to configuration change"
+#define ASPNETCORE_EVENT_RECYCLE_FAILURE_CONFIGURATION_MSG   L"Failed to recycle application due to a configuration change at '%s'. Recycling worker process."
+#define ASPNETCORE_EVENT_MODULE_DISABLED_MSG                 L"AspNetCore Module is disabled"
+#define ASPNETCORE_EVENT_INPROCESS_FULL_FRAMEWORK_APP_MSG    L"Application '%s' was compiled for .NET Framework. Please compile for .NET core to run the inprocess application or change the process mode to out of process. ErrorCode = '0x%x'."
+#define ASPNETCORE_EVENT_PORTABLE_APP_DOTNET_MISSING_MSG     L"Could not find dotnet.exe on the system PATH environment variable for portable application '%s'. Check that a valid path to dotnet is on the PATH and the bitness of dotnet matches the bitness of the IIS worker process. ErrorCode = '0x%x'."
+#define ASPNETCORE_EVENT_HOSTFXR_DIRECTORY_NOT_FOUND_MSG     L"Could not find the hostfxr directory '%s' in the dotnet directory. ErrorCode = '0x%x'."
+#define ASPNETCORE_EVENT_HOSTFXR_DLL_NOT_FOUND_MSG           L"Could not find hostfxr.dll in '%s'. ErrorCode = '0x%x'."
+#define ASPNETCORE_EVENT_APPLICATION_EXE_NOT_FOUND_MSG       L"Could not find application executable in '%s'. ErrorCode = '0x%x'."
+#define ASPNETCORE_EVENT_INPROCESS_THREAD_EXCEPTION_MSG      L"Application '%s' with physical root '%s' hit unexpected managed exception, ErrorCode = '0x%x. Please check the stderr logs for more information."
+#define ASPNETCORE_EVENT_INVALID_PROCESS_PATH_MSG            L"Invalid or unknown processPath provided in web.config: processPath = %s, ErrorCode = '0x%x'."
+#define ASPNETCORE_EVENT_INPROCESS_RH_MISSING_MSG            L"Could not find the aspnetcorerh.dll for in-process application. Please confirm the Microsoft.AspNetCore.Server.IIS package is referenced in your application."
+#define ASPNETCORE_EVENT_OUT_OF_PROCESS_RH_MISSING_MSG       L"Could not find the aspnetcorerh.dll for out-of-process application. Please confirm the aspnetcorerh.dll is installed in installed globally for IIS or IISExpress."
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/CommonLib/stdafx.cpp b/src/IISIntegration/src/AspNetCoreModuleV2/CommonLib/stdafx.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..0351feb240df1563f54ee259819f693c1e68f435
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/CommonLib/stdafx.cpp
@@ -0,0 +1,4 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#include "stdafx.h"
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/CommonLib/stdafx.h b/src/IISIntegration/src/AspNetCoreModuleV2/CommonLib/stdafx.h
new file mode 100644
index 0000000000000000000000000000000000000000..69ad058f1f653b8aad1ebf5ff5507b3938e6c5cd
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/CommonLib/stdafx.h
@@ -0,0 +1,34 @@
+// 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 "targetver.h"
+
+#define WIN32_LEAN_AND_MEAN             // Exclude rarely-used stuff from Windows headers
+
+#include <Windows.h>
+#include <httpserv.h>
+#include <wchar.h>
+#include <vector>
+#include <shellapi.h>
+#include <sstream>
+#include "Shlwapi.h"
+#include "..\IISLib\hashtable.h"
+#include "..\IISLib\stringu.h"
+#include "..\IISLib\stringa.h"
+#include "..\IISLib\multisz.h"
+#include "..\IISLib\dbgutil.h"
+#include "..\IISLib\ahutil.h"
+#include "..\IISLib\hashfn.h"
+#include "SRWLockWrapper.h"
+#include "environmentvariablehash.h"
+#include "utility.h"
+#include "aspnetcoreconfig.h"
+#include "application.h"
+#include "requesthandler.h"
+#include "fx_ver.h"
+#include "hostfxr_utility.h"
+#include "resources.h"
+#include "aspnetcore_msg.h"
+
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/CommonLib/targetver.h b/src/IISIntegration/src/AspNetCoreModuleV2/CommonLib/targetver.h
new file mode 100644
index 0000000000000000000000000000000000000000..5b1f29cad0ce0d0ec02ec5e0f2fabb0f04763045
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/CommonLib/targetver.h
@@ -0,0 +1,8 @@
+#pragma once
+
+// Including SDKDDKVer.h defines the highest available Windows platform.
+
+// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and
+// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h.
+
+#include <SDKDDKVer.h>
\ No newline at end of file
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/CommonLib/utility.cxx b/src/IISIntegration/src/AspNetCoreModuleV2/CommonLib/utility.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..cb762f21bc7bb4d1e7deabb6a2b271d926365fec
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/CommonLib/utility.cxx
@@ -0,0 +1,656 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#include"stdafx.h"
+
+// static
+HRESULT
+UTILITY::SplitUrl(
+    PCWSTR pszDestinationUrl,
+    BOOL *pfSecure,
+    STRU *pstrDestination,
+    STRU *pstrUrl
+)
+/*++
+
+Routine Description:
+
+    Split the URL specified for forwarding into its specific components
+    The format of the URL looks like
+    http[s]://destination[:port]/path
+    when port is omitted, the default port for that specific protocol is used
+    when host is omitted, it gets the same value as the destination
+
+Arguments:
+
+    pszDestinationUrl - the url to be split up
+    pfSecure - SSL to be used in forwarding?
+    pstrDestination - destination
+    pDestinationPort - port
+    pstrUrl - URL
+
+Return Value:
+
+    HRESULT
+
+--*/
+{
+    HRESULT hr;
+
+    //
+    // First determine if the target is secure
+    //
+    if (_wcsnicmp(pszDestinationUrl, L"http://", 7) == 0)
+    {
+        *pfSecure = FALSE;
+        pszDestinationUrl += 7;
+    }
+    else if (_wcsnicmp(pszDestinationUrl, L"https://", 8) == 0)
+    {
+        *pfSecure = TRUE;
+        pszDestinationUrl += 8;
+    }
+    else
+    {
+        return HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
+    }
+
+    if (*pszDestinationUrl == L'\0')
+    {
+        return HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
+    }
+
+    //
+    // Find the 3rd slash corresponding to the url
+    //
+    LPCWSTR pszSlash = wcschr(pszDestinationUrl, L'/');
+    if (pszSlash == NULL)
+    {
+        if (FAILED(hr = pstrUrl->Copy(L"/", 1)) ||
+            FAILED(hr = pstrDestination->Copy(pszDestinationUrl)))
+        {
+            return hr;
+        }
+    }
+    else
+    {
+        if (FAILED(hr = pstrUrl->Copy(pszSlash)) ||
+            FAILED(hr = pstrDestination->Copy(pszDestinationUrl,
+                            (DWORD)(pszSlash - pszDestinationUrl))))
+        {
+            return hr;
+        }
+    }
+
+    return S_OK;
+}
+
+// Change a hexadecimal digit to its numerical equivalent
+#define TOHEX( ch )                                     \
+    ((ch) > L'9' ?                                      \
+        (ch) >= L'a' ?                                  \
+            (ch) - L'a' + 10 :                          \
+            (ch) - L'A' + 10                            \
+        : (ch) - L'0')
+
+// static
+HRESULT
+UTILITY::UnEscapeUrl(
+    PCWSTR      pszUrl,
+    DWORD       cchUrl,
+    bool        fCopyQuery,
+    STRA *      pstrResult
+)
+{
+    HRESULT hr;
+    CHAR pch[2];
+    pch[1] = '\0';
+    DWORD cchStart = 0;
+    DWORD index = 0;
+
+    while (index < cchUrl &&
+           (fCopyQuery || pszUrl[index] != L'?'))
+    {
+        switch (pszUrl[index])
+        {
+        case L'%':
+            if (iswxdigit(pszUrl[index+1]) && iswxdigit(pszUrl[index+2]))
+            {
+                if (index > cchStart &&
+                    FAILED(hr = pstrResult->AppendW(pszUrl + cchStart,
+                                                    index - cchStart)))
+                {
+                    return hr;
+                }
+                cchStart = index+3;
+
+                pch[0] = static_cast<CHAR>(TOHEX(pszUrl[index+1]) * 16 +
+                                TOHEX(pszUrl[index+2]));
+                if (FAILED(hr = pstrResult->Append(pch, 1)))
+                {
+                    return hr;
+                }
+                index += 3;
+                break;
+            }
+
+            __fallthrough;
+        default:
+            index++;
+        }
+    }
+
+    if (index > cchStart)
+    {
+        return pstrResult->AppendW(pszUrl + cchStart,
+                                   index - cchStart);
+    }
+
+    return S_OK;
+}
+
+// static
+HRESULT
+UTILITY::UnEscapeUrl(
+    PCWSTR      pszUrl,
+    DWORD       cchUrl,
+    STRU *      pstrResult
+)
+{
+    HRESULT hr;
+    WCHAR pch[2];
+    pch[1] = L'\0';
+    DWORD cchStart = 0;
+    DWORD index = 0;
+    bool fInQuery = FALSE;
+
+    while (index < cchUrl)
+    {
+        switch (pszUrl[index])
+        {
+        case L'%':
+            if (iswxdigit(pszUrl[index+1]) && iswxdigit(pszUrl[index+2]))
+            {
+                if (index > cchStart &&
+                    FAILED(hr = pstrResult->Append(pszUrl + cchStart,
+                                                   index - cchStart)))
+                {
+                    return hr;
+                }
+                cchStart = index+3;
+
+                pch[0] = static_cast<WCHAR>(TOHEX(pszUrl[index+1]) * 16 +
+                                 TOHEX(pszUrl[index+2]));
+                if (FAILED(hr = pstrResult->Append(pch, 1)))
+                {
+                    return hr;
+                }
+                index += 3;
+                if (pch[0] == L'?')
+                {
+                    fInQuery = TRUE;
+                }
+                break;
+            }
+
+            index++;
+            break;
+
+        case L'/':
+            if (fInQuery)
+            {
+                if (index > cchStart &&
+                    FAILED(hr = pstrResult->Append(pszUrl + cchStart,
+                                                   index - cchStart)))
+                {
+                    return hr;
+                }
+                cchStart = index+1;
+
+                if (FAILED(hr = pstrResult->Append(L"\\", 1)))
+                {
+                    return hr;
+                }
+                index += 1;
+                break;
+            }
+
+            __fallthrough;
+        default:
+            index++;
+        }
+    }
+
+    if (index > cchStart)
+    {
+        return pstrResult->Append(pszUrl + cchStart,
+                                  index - cchStart);
+    }
+
+    return S_OK;
+}
+
+HRESULT
+UTILITY::EscapeAbsPath(
+    IHttpRequest * pRequest,
+    STRU * strEscapedUrl
+)
+{
+    HRESULT hr = S_OK;
+    STRU    strAbsPath;
+    LPCWSTR pszAbsPath = NULL;
+    LPCWSTR pszFindStr = NULL;
+
+    hr = strAbsPath.Copy( pRequest->GetRawHttpRequest()->CookedUrl.pAbsPath,
+        pRequest->GetRawHttpRequest()->CookedUrl.AbsPathLength / sizeof(WCHAR) );
+    if(FAILED(hr))
+    {
+        goto Finished;
+    }
+
+    pszAbsPath = strAbsPath.QueryStr();
+    pszFindStr = wcschr(pszAbsPath, L'?');
+
+    while(pszFindStr != NULL)
+    {
+        strEscapedUrl->Append( pszAbsPath, pszFindStr - pszAbsPath);
+        strEscapedUrl->Append(L"%3F");
+        pszAbsPath = pszFindStr + 1;
+        pszFindStr = wcschr(pszAbsPath, L'?');
+    }
+
+    strEscapedUrl->Append(pszAbsPath);
+    strEscapedUrl->Append(pRequest->GetRawHttpRequest()->CookedUrl.pQueryString,
+                          pRequest->GetRawHttpRequest()->CookedUrl.QueryStringLength / sizeof(WCHAR));
+
+Finished:
+    return hr;
+}
+
+// static
+bool
+UTILITY::IsValidAttributeNameChar(
+    WCHAR ch
+)
+{
+    //
+    // Values based on ASP.NET rendering for cookie names. RFC 2965 is not clear
+    // what the non-special characters are.
+    //
+    return ch == L'\t' || (ch > 31 && ch < 127);
+}
+
+// static
+bool
+UTILITY::FindInMultiString(
+    PCWSTR      pszMultiString,
+    PCWSTR      pszStringToFind
+)
+{
+    while (*pszMultiString != L'\0')
+    {
+        if (wcscmp(pszMultiString, pszStringToFind) == 0)
+        {
+            return TRUE;
+        }
+        pszMultiString += wcslen(pszMultiString) + 1;
+    }
+
+    return FALSE;
+}
+
+// static
+bool
+UTILITY::IsValidQueryStringName(
+    PCWSTR  pszName
+)
+{
+    while (*pszName != L'\0')
+    {
+        WCHAR c = *pszName;
+        if (c != L'-' && c != L'_' && c != L'+' &&
+            c != L'.' && c != L'*' && c != L'$' && c != L'%' && c != L',' &&
+            !iswalnum(c))
+        {
+            return FALSE;
+        }
+        pszName++;
+    }
+
+    return TRUE;
+}
+
+// static
+bool
+UTILITY::IsValidHeaderName(
+    PCWSTR  pszName
+)
+{
+    while (*pszName != L'\0')
+    {
+        WCHAR c = *pszName;
+        if (c != L'-' && c != L'_' && c != L'+' &&
+            c != L'.' && c != L'*' && c != L'$' && c != L'%'
+            && !iswalnum(c))
+        {
+            return FALSE;
+        }
+        pszName++;
+    }
+
+    return TRUE;
+}
+
+HRESULT
+UTILITY::IsPathUnc(
+    __in  LPCWSTR       pszPath,
+    __out BOOL *        pfIsUnc
+)
+{
+    HRESULT hr = S_OK;
+    STRU strTempPath;
+
+    if ( pszPath == NULL || pfIsUnc == NULL )
+    {
+        hr = E_INVALIDARG;
+        goto Finished;
+    }
+
+    hr = MakePathCanonicalizationProof( (LPWSTR) pszPath, &strTempPath );
+    if ( FAILED(hr) )
+    {
+        goto Finished;
+    }
+
+    //
+    // MakePathCanonicalizationProof will map \\?\UNC, \\.\UNC and \\ to \\?\UNC
+    //
+    (*pfIsUnc) = ( _wcsnicmp( strTempPath.QueryStr(), L"\\\\?\\UNC\\", 8 /* sizeof \\?\UNC\ */) == 0 );
+
+Finished:
+
+    return hr;
+}
+
+HRESULT
+UTILITY::ConvertPathToFullPath(
+    _In_  LPCWSTR   pszPath,
+    _In_  LPCWSTR   pszRootPath,
+    _Out_ STRU*     pStruFullPath
+)
+{
+    HRESULT hr = S_OK;
+    STRU strFileFullPath;
+    LPWSTR pszFullPath = NULL;
+
+    // if relative path, prefix with root path and then convert to absolute path.
+    if ( PathIsRelative(pszPath) )
+    {
+        hr = strFileFullPath.Copy(pszRootPath);
+        if(FAILED(hr))
+        {
+            goto Finished;
+        }
+
+        if(!strFileFullPath.EndsWith(L"\\"))
+        {
+            hr = strFileFullPath.Append(L"\\");
+            if(FAILED(hr))
+            {
+                goto Finished;
+            }
+        }
+    }
+
+    hr = strFileFullPath.Append( pszPath );
+    if (FAILED(hr))
+    {
+        goto Finished;
+    }
+
+    pszFullPath = new WCHAR[ strFileFullPath.QueryCCH() + 1];
+    if ( pszFullPath == NULL )
+    {
+        hr = E_OUTOFMEMORY;
+        goto Finished;
+    }
+
+    if(_wfullpath( pszFullPath,
+                   strFileFullPath.QueryStr(),
+                   strFileFullPath.QueryCCH() + 1 ) == NULL )
+    {
+        hr = HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
+        goto Finished;
+    }
+
+    // convert to canonical path
+    hr = MakePathCanonicalizationProof( pszFullPath, pStruFullPath );
+    if (FAILED(hr))
+    {
+        goto Finished;
+    }
+
+Finished:
+
+    if ( pszFullPath != NULL )
+    {
+        delete[] pszFullPath;
+        pszFullPath = NULL;
+    }
+
+    return hr;
+}
+
+HRESULT
+UTILITY::EnsureDirectoryPathExist(
+    _In_  LPCWSTR pszPath
+)
+{
+    HRESULT hr = S_OK;
+    STRU    struPath;
+    DWORD   dwPosition = 0;
+    BOOL    fDone = FALSE;
+    BOOL    fUnc = FALSE;
+
+    struPath.Copy(pszPath);
+    hr = IsPathUnc(pszPath, &fUnc);
+    if (FAILED(hr))
+    {
+        goto Finished;
+    }
+    if (fUnc)
+    {
+        // "\\?\UNC\"
+        dwPosition = 8;
+    }
+    else if (struPath.IndexOf(L'?', 0) != -1)
+    {
+        // sceanrio "\\?\"
+        dwPosition = 4;
+    }
+    while (!fDone)
+    {
+        dwPosition = struPath.IndexOf(L'\\', dwPosition + 1);
+        if (dwPosition == -1)
+        {
+            // not found '/'
+            fDone = TRUE;
+            goto Finished;
+        }
+        else if (dwPosition ==0)
+        {
+            hr = ERROR_INTERNAL_ERROR;
+            goto Finished;
+        }
+        else if (struPath.QueryStr()[dwPosition-1] == L':')
+        {
+            //  skip volume case
+            continue;
+        }
+        else
+        {
+            struPath.QueryStr()[dwPosition] = L'\0';
+        }
+
+        if (!CreateDirectory(struPath.QueryStr(), NULL) &&
+            ERROR_ALREADY_EXISTS != GetLastError())
+        {
+            hr = HRESULT_FROM_WIN32(GetLastError());
+            fDone = TRUE;
+            goto Finished;
+        }
+        struPath.QueryStr()[dwPosition] = L'\\';
+    }
+
+Finished:
+    return hr;
+}
+
+HRESULT
+UTILITY::FindHighestDotNetVersion(
+    _In_ std::vector<std::wstring> vFolders,
+    _Out_ STRU *pstrResult
+)
+{
+    HRESULT hr = S_OK;
+    fx_ver_t max_ver(-1, -1, -1);
+    for (const auto& dir : vFolders)
+    {
+        fx_ver_t fx_ver(-1, -1, -1);
+        if (fx_ver_t::parse(dir, &fx_ver, false))
+        {
+            // TODO using max instead of std::max works
+            max_ver = max(max_ver, fx_ver);
+        }
+    }
+
+    hr = pstrResult->Copy(max_ver.as_str().c_str());
+
+    // we check FAILED(hr) outside of function
+    return hr;
+}
+
+BOOL
+UTILITY::DirectoryExists(
+    _In_ STRU *pstrPath
+)
+{
+    WIN32_FILE_ATTRIBUTE_DATA data;
+
+    if (pstrPath->IsEmpty())
+    {
+        return false;
+    }
+
+    return GetFileAttributesExW(pstrPath->QueryStr(), GetFileExInfoStandard, &data);
+}
+
+VOID
+UTILITY::FindDotNetFolders(
+    _In_ PCWSTR pszPath,
+    _Out_ std::vector<std::wstring> *pvFolders
+)
+{
+    HANDLE handle = NULL;
+    WIN32_FIND_DATAW data = { 0 };
+
+    handle = FindFirstFileExW(pszPath, FindExInfoStandard, &data, FindExSearchNameMatch, NULL, 0);
+    if (handle == INVALID_HANDLE_VALUE)
+    {
+        return;
+    }
+
+    do
+    {
+        std::wstring folder(data.cFileName);
+        pvFolders->push_back(folder);
+    } while (FindNextFileW(handle, &data));
+
+    FindClose(handle);
+}
+
+BOOL
+UTILITY::CheckIfFileExists(
+    _In_ PCWSTR pszFilePath
+)
+{
+    HANDLE              hFileHandle = INVALID_HANDLE_VALUE;
+    SECURITY_ATTRIBUTES saAttr;
+    BOOL                fFileExists = FALSE;
+
+    saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
+    saAttr.bInheritHandle = TRUE;
+    saAttr.lpSecurityDescriptor = NULL;
+
+    hFileHandle = CreateFile(pszFilePath,
+        GENERIC_READ,
+        FILE_SHARE_READ,
+        &saAttr,
+        OPEN_EXISTING,
+        FILE_ATTRIBUTE_NORMAL,
+        NULL);
+
+    fFileExists = hFileHandle != INVALID_HANDLE_VALUE || GetLastError() == ERROR_SHARING_VIOLATION;
+
+    if (fFileExists)
+    {
+        CloseHandle(hFileHandle);
+    }
+
+    return fFileExists;
+}
+
+VOID
+UTILITY::LogEvent(
+    _In_ HANDLE  hEventLog,
+    _In_ WORD    dwEventInfoType,
+    _In_ DWORD   dwEventId,
+    _In_ LPCWSTR pstrMsg
+)
+{
+    if (hEventLog != NULL)
+    {
+        ReportEventW(hEventLog,
+            dwEventInfoType,
+            0,        // wCategory
+            dwEventId,
+            NULL,     // lpUserSid
+            1,        // wNumStrings
+            0,        // dwDataSize,
+            &pstrMsg,
+            NULL      // lpRawData
+        );
+    }
+
+    if (dwEventInfoType == EVENTLOG_ERROR_TYPE)
+    {
+        fwprintf(stderr, L"ERROR: %s\n", pstrMsg);
+    }
+}
+
+VOID
+UTILITY::LogEventF(
+    _In_ HANDLE  hEventLog,
+    _In_ WORD    dwEventInfoType,
+    _In_ DWORD   dwEventId,
+    _In_ LPCWSTR pstrMsg,
+    ...
+)
+{
+    va_list argsList;
+    va_start(argsList, pstrMsg);
+
+    STACK_STRU ( strEventMsg, 256 );
+
+    if (SUCCEEDED(strEventMsg.SafeVsnwprintf(
+        pstrMsg,
+        argsList)))
+    {
+        UTILITY::LogEvent(hEventLog,
+            dwEventInfoType,
+            dwEventId,
+            strEventMsg.QueryStr());
+    }
+
+    va_end( argsList );
+}
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/CommonLib/utility.h b/src/IISIntegration/src/AspNetCoreModuleV2/CommonLib/utility.h
new file mode 100644
index 0000000000000000000000000000000000000000..830c2a061323152bd0c15d12c46e8b2df07f842e
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/CommonLib/utility.h
@@ -0,0 +1,137 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#pragma once
+
+class UTILITY
+{
+public:
+
+    static
+    HRESULT
+    SplitUrl(
+        PCWSTR pszDestinationUrl,
+        BOOL *pfSecure,
+        STRU *pstrDestination,
+        STRU *pstrUrl
+    );
+
+    static
+    HRESULT
+    UnEscapeUrl(
+        PCWSTR      pszUrl,
+        DWORD       cchUrl,
+        bool        fCopyQuery,
+        STRA *      pstrResult
+    );
+
+    static
+    HRESULT
+    UnEscapeUrl(
+        PCWSTR      pszUrl,
+        DWORD       cchUrl,
+        STRU *      pstrResult
+    );
+
+    static HRESULT
+    EscapeAbsPath(
+        IHttpRequest * pRequest,
+        STRU * strEscapedUrl
+    );
+
+    static
+    bool
+    IsValidAttributeNameChar(
+        WCHAR ch
+    );
+
+    static
+    bool
+    IsValidQueryStringName(
+        PCWSTR  pszName
+    );
+
+    static
+    bool
+    IsValidHeaderName(
+        PCWSTR  pszName
+    );
+
+    static
+    bool
+    FindInMultiString(
+        PCWSTR      pszMultiString,
+        PCWSTR      pszStringToFind
+    );
+
+    static
+    HRESULT
+    IsPathUnc(
+        __in  LPCWSTR       pszPath,
+        __out BOOL *        pfIsUnc
+    );
+
+    static
+    HRESULT
+    ConvertPathToFullPath(
+        _In_  LPCWSTR   pszPath,
+        _In_  LPCWSTR   pszRootPath,
+        _Out_ STRU*     pStrFullPath
+    );
+
+    static
+    HRESULT
+    EnsureDirectoryPathExist(
+        _In_  LPCWSTR pszPath
+    );
+
+    static
+    BOOL
+    DirectoryExists(
+        _In_ STRU *pstrPath
+    );
+
+    static
+    VOID
+    FindDotNetFolders(
+        _In_ PCWSTR pszPath,
+        _Out_ std::vector<std::wstring> *pvFolders
+    );
+
+    static
+    HRESULT
+    FindHighestDotNetVersion(
+        _In_ std::vector<std::wstring> vFolders,
+        _Out_ STRU *pstrResult
+    );
+
+    static
+    BOOL
+    CheckIfFileExists(
+        PCWSTR pszFilePath
+    );
+
+    static
+    VOID
+    LogEvent(
+        _In_ HANDLE  hEventLog,
+        _In_ WORD    dwEventInfoType,
+        _In_ DWORD   dwEventId,
+        _In_ LPCWSTR pstrMsg
+    );
+
+    static
+    VOID
+    LogEventF(
+        _In_ HANDLE  hEventLog,
+        _In_ WORD    dwEventInfoType,
+        _In_ DWORD   dwEventId,
+        __in PCWSTR  pstrMsg,
+        ...
+    );
+
+private:
+
+    UTILITY() {}
+    ~UTILITY() {}
+};
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/IISLib/IISLib.vcxproj b/src/IISIntegration/src/AspNetCoreModuleV2/IISLib/IISLib.vcxproj
new file mode 100644
index 0000000000000000000000000000000000000000..7c0cca66266edaa286dd7d0cffec85a3d232f75d
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/IISLib/IISLib.vcxproj
@@ -0,0 +1,201 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|Win32">
+      <Configuration>Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Debug|x64">
+      <Configuration>Debug</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|x64">
+      <Configuration>Release</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{09D9D1D6-2951-4E14-BC35-76A23CF9391A}</ProjectGuid>
+    <Keyword>Win32Proj</Keyword>
+    <RootNamespace>IISLib</RootNamespace>
+    <ProjectName>IISLib</ProjectName>
+    <WindowsTargetPlatformVersion>10.0.15063.0</WindowsTargetPlatformVersion>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+    <ConfigurationType>StaticLibrary</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <PlatformToolset>v141</PlatformToolset>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+    <ConfigurationType>StaticLibrary</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <PlatformToolset>v141</PlatformToolset>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+    <ConfigurationType>StaticLibrary</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <PlatformToolset>v141</PlatformToolset>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+    <ConfigurationType>StaticLibrary</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <PlatformToolset>v141</PlatformToolset>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <OutDir>$(MSBuildProjectDirectory)\bin\$(Configuration)\$(Platform)\</OutDir>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <OutDir>$(MSBuildProjectDirectory)\bin\$(Configuration)\$(Platform)\</OutDir>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <OutDir>$(MSBuildProjectDirectory)\bin\$(Configuration)\$(Platform)\</OutDir>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <OutDir>$(MSBuildProjectDirectory)\bin\$(Configuration)\$(Platform)\</OutDir>
+  </PropertyGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>
+      </PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <SDLCheck>true</SDLCheck>
+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+      <ShowIncludes>false</ShowIncludes>
+      <TreatWarningAsError>true</TreatWarningAsError>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <ClCompile>
+      <PrecompiledHeader>
+      </PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <SDLCheck>true</SDLCheck>
+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+      <ShowIncludes>false</ShowIncludes>
+      <TreatWarningAsError>true</TreatWarningAsError>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <PrecompiledHeader>
+      </PrecompiledHeader>
+      <Optimization>MaxSpeed</Optimization>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+      <ShowIncludes>false</ShowIncludes>
+      <TreatWarningAsError>true</TreatWarningAsError>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <PrecompiledHeader>
+      </PrecompiledHeader>
+      <Optimization>MaxSpeed</Optimization>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+      <ShowIncludes>false</ShowIncludes>
+      <TreatWarningAsError>true</TreatWarningAsError>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemGroup>
+    <ClInclude Include="acache.h" />
+    <ClInclude Include="ahutil.h" />
+    <ClInclude Include="base64.h" />
+    <ClInclude Include="buffer.h" />
+    <ClInclude Include="datetime.h" />
+    <ClInclude Include="dbgutil.h" />
+    <ClInclude Include="hashfn.h" />
+    <ClInclude Include="hashtable.h" />
+    <ClInclude Include="listentry.h" />
+    <ClInclude Include="macros.h" />
+    <ClInclude Include="multisz.h" />
+    <ClInclude Include="multisza.h" />
+    <ClInclude Include="ntassert.h" />
+    <ClInclude Include="percpu.h" />
+    <ClInclude Include="precomp.h" />
+    <ClInclude Include="prime.h" />
+    <ClInclude Include="pudebug.h" />
+    <ClInclude Include="reftrace.h" />
+    <ClInclude Include="rwlock.h" />
+    <ClInclude Include="stringa.h" />
+    <ClInclude Include="stringu.h" />
+    <ClInclude Include="tracelog.h" />
+    <ClInclude Include="treehash.h" />
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="acache.cxx" />
+    <ClCompile Include="ahutil.cpp" />
+    <ClCompile Include="base64.cpp" />
+    <ClCompile Include="multisz.cpp" />
+    <ClCompile Include="multisza.cpp" />
+    <ClCompile Include="reftrace.c" />
+    <ClCompile Include="stringa.cpp" />
+    <ClCompile Include="stringu.cpp" />
+    <ClCompile Include="tracelog.c" />
+    <ClCompile Include="util.cxx" />
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  </ImportGroup>
+</Project>
\ No newline at end of file
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/IISLib/acache.cxx b/src/IISIntegration/src/AspNetCoreModuleV2/IISLib/acache.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..d68813edbc929d410559ec5ec949ea2953f367c2
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/IISLib/acache.cxx
@@ -0,0 +1,443 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#include "precomp.h"
+
+LONG    ALLOC_CACHE_HANDLER::sm_nFillPattern = 0xACA50000;
+HANDLE  ALLOC_CACHE_HANDLER::sm_hHeap;
+
+//
+// This class is used to implement the free list.  We cast the free'd
+// memory block to a FREE_LIST_HEADER*.  The signature is used to guard against
+// double deletion.  We also fill memory with a pattern.
+//
+class FREE_LIST_HEADER
+{
+public:
+    SLIST_ENTRY     ListEntry;
+    DWORD           dwSignature;
+
+    enum
+    {
+        FREE_SIGNATURE = (('A') | ('C' << 8) | ('a' << 16) | (('$' << 24) | 0x80)),
+    };
+};
+
+ALLOC_CACHE_HANDLER::ALLOC_CACHE_HANDLER(
+    VOID
+) : m_nThreshold(0),
+    m_cbSize(0),
+    m_pFreeLists(NULL),
+    m_nTotal(0)
+{
+}
+
+ALLOC_CACHE_HANDLER::~ALLOC_CACHE_HANDLER(
+    VOID
+)
+{
+    if (m_pFreeLists != NULL)
+    {
+        CleanupLookaside();
+        m_pFreeLists->Dispose();
+        m_pFreeLists = NULL;
+    }
+}
+
+HRESULT
+ALLOC_CACHE_HANDLER::Initialize(
+    DWORD       cbSize,
+    LONG        nThreshold
+)
+{
+    HRESULT hr = S_OK;
+
+    m_nThreshold = nThreshold;
+    if ( m_nThreshold > 0xffff)
+    {
+        //
+        // This will be compared against QueryDepthSList return value (USHORT).
+        //
+        m_nThreshold = 0xffff;
+    }
+
+    if ( IsPageheapEnabled() )
+    {
+        //
+        // Disable acache.
+        //
+        m_nThreshold = 0;
+    }
+
+    //
+    // Make sure the block is big enough to hold a FREE_LIST_HEADER.
+    //
+    m_cbSize = cbSize;
+    m_cbSize = max(m_cbSize, sizeof(FREE_LIST_HEADER));
+    
+    //
+    // Round up the block size to a multiple of the size of a LONG (for
+    // the fill pattern in Free()).
+    //
+    m_cbSize = (m_cbSize + sizeof(LONG) - 1) & ~(sizeof(LONG) - 1);
+
+#if defined(_MSC_VER) && _MSC_VER >= 1600 // VC10
+    auto Init = [] (SLIST_HEADER* pHead)
+    {
+        InitializeSListHead(pHead);
+    };
+#else
+    class Functor
+    {
+    public:
+        void operator()(SLIST_HEADER* pHead)
+        {
+            InitializeSListHead(pHead);
+        }
+    } Init;
+#endif
+    
+    hr = PER_CPU<SLIST_HEADER>::Create(Init,
+                                       &m_pFreeLists );
+    if (FAILED(hr))
+    {
+        goto Finished;
+    }
+
+    m_nFillPattern = InterlockedIncrement(&sm_nFillPattern);
+
+Finished:
+
+    return hr;
+}
+
+// static
+HRESULT
+ALLOC_CACHE_HANDLER::StaticInitialize(
+    VOID
+)
+{
+    //
+    // Since the memory allocated is fixed size,
+    // a heap is not really needed, allocations can be done
+    // using VirtualAllocEx[Numa]. For now use Windows Heap.
+    //
+    // Be aware that creating one private heap consumes more
+    // virtual address space for the worker process.
+    //
+    sm_hHeap = GetProcessHeap();
+    return S_OK;
+}
+
+
+// static
+VOID
+ALLOC_CACHE_HANDLER::StaticTerminate(
+    VOID
+)
+{
+    sm_hHeap = NULL;
+}
+
+VOID
+ALLOC_CACHE_HANDLER::CleanupLookaside(
+    VOID
+)
+/*++
+  Description:
+    This function cleans up the lookaside list by removing storage space.
+
+  Arguments:
+    None.
+
+  Returns:
+     None
+--*/
+{
+    //
+    // Free up all the entries in the list.
+    // Don't use InterlockedFlushSList, in order to work
+    // memory must be 16 bytes aligned and currently it is 64.
+    //
+
+#if defined(_MSC_VER) && _MSC_VER >= 1600 // VC10
+    auto Predicate = [=] (SLIST_HEADER * pListHeader)
+    {
+        PSLIST_ENTRY pl;
+        LONG NodesToDelete = QueryDepthSList( pListHeader );
+
+        pl = InterlockedPopEntrySList( pListHeader );
+        while ( pl != NULL && --NodesToDelete >= 0 )
+        {
+            InterlockedDecrement( &m_nTotal);
+
+            ::HeapFree( sm_hHeap, 0, pl );
+
+            pl = InterlockedPopEntrySList(pListHeader);
+        }
+    };
+#else
+    class Functor
+    {
+    public:
+        explicit Functor(ALLOC_CACHE_HANDLER * pThis) : _pThis(pThis)
+        {
+        }
+        void operator()(SLIST_HEADER * pListHeader)
+        {
+            PSLIST_ENTRY pl;
+            LONG NodesToDelete = QueryDepthSList( pListHeader );
+
+            pl = InterlockedPopEntrySList( pListHeader );
+            while ( pl != NULL && --NodesToDelete >= 0 )
+            {
+                InterlockedDecrement( &_pThis->m_nTotal);
+
+                ::HeapFree( sm_hHeap, 0, pl );
+
+                pl = InterlockedPopEntrySList(pListHeader);
+            }
+        }
+    private:
+        ALLOC_CACHE_HANDLER * _pThis;
+    } Predicate(this);
+#endif
+
+    m_pFreeLists ->ForEach(Predicate);
+}
+
+LPVOID
+ALLOC_CACHE_HANDLER::Alloc(
+    VOID
+)
+{
+    LPVOID pMemory = NULL;
+
+    if ( m_nThreshold > 0 )
+    {
+        SLIST_HEADER * pListHeader = m_pFreeLists ->GetLocal();
+        pMemory = (LPVOID) InterlockedPopEntrySList(pListHeader);  // get the real object
+
+        if (pMemory != NULL)
+        {
+            FREE_LIST_HEADER* pfl = (FREE_LIST_HEADER*) pMemory;
+            //
+            // If the signature is wrong then somebody's been scribbling
+            // on memory that they've freed.
+            //
+            DBG_ASSERT(pfl->dwSignature == FREE_LIST_HEADER::FREE_SIGNATURE);
+        }
+    }
+
+    if ( pMemory == NULL )
+    {
+        //
+        // No free entry. Need to alloc a new object.
+        //
+        pMemory = (LPVOID) ::HeapAlloc( sm_hHeap,
+                                        0,
+                                        m_cbSize );
+
+        if ( pMemory != NULL )
+        {
+            //
+            // Update counters.
+            //
+            m_nTotal++;
+        }
+    }
+
+    if ( pMemory == NULL )
+    {
+        SetLastError( ERROR_NOT_ENOUGH_MEMORY );
+    }
+    else
+    {
+        FREE_LIST_HEADER* pfl = (FREE_LIST_HEADER*) pMemory;
+        pfl->dwSignature = 0; // clear; just in case caller never overwrites
+    }
+
+    return pMemory;
+}
+
+VOID
+ALLOC_CACHE_HANDLER::Free(
+    __in LPVOID pMemory
+)
+{
+    //
+    // Assume that this is allocated using the Alloc() function.
+    //
+    DBG_ASSERT(NULL != pMemory);
+
+    //
+    // Use a signature to check against double deletions.
+    //
+    FREE_LIST_HEADER* pfl = (FREE_LIST_HEADER*) pMemory;
+    DBG_ASSERT(pfl->dwSignature != FREE_LIST_HEADER::FREE_SIGNATURE);
+
+    //
+    // Start filling the space beyond the portion overlaid by the initial
+    // FREE_LIST_HEADER.  Fill at most 6 DWORDS.
+    //
+    LONG* pl = (LONG*) (pfl+1);
+
+    for (LONG cb = (LONG)min(6 * sizeof(LONG),m_cbSize) - sizeof(FREE_LIST_HEADER);
+         cb > 0;
+         cb -= sizeof(LONG))
+    {
+        *pl++ = m_nFillPattern;
+    }
+
+    //
+    // Now, set the signature.
+    //
+    pfl->dwSignature = FREE_LIST_HEADER::FREE_SIGNATURE;
+
+    //
+    // Store the items in the alloc cache.
+    //
+    SLIST_HEADER * pListHeader = m_pFreeLists ->GetLocal();
+
+    if ( QueryDepthSList(pListHeader) >= m_nThreshold )
+    {
+        //
+        // Threshold for free entries is exceeded. Free the object to
+        // process pool.
+        //
+        ::HeapFree( sm_hHeap, 0, pMemory );
+    }
+    else
+    {
+        //
+        // Store the given pointer in the single linear list
+        //
+        InterlockedPushEntrySList(pListHeader, &pfl->ListEntry);
+    }
+}
+
+DWORD
+ALLOC_CACHE_HANDLER::QueryDepthForAllSLists(
+    VOID
+)
+/*++
+
+Description:
+    
+    Aggregates the total count of elements in all lists.
+    
+Arguments:
+    
+    None.
+
+Return Value:
+
+    Total count (snapshot).
+
+--*/
+{
+    DWORD Count = 0;
+
+    if (m_pFreeLists  != NULL)
+    {
+#if defined(_MSC_VER) && _MSC_VER >= 1600 // VC10
+        auto Predicate = [&Count] (SLIST_HEADER * pListHeader)
+        {
+            Count += QueryDepthSList(pListHeader);
+        };
+#else
+        class Functor
+        {
+        public:
+            explicit Functor(DWORD& Count) : _Count(Count)
+            {
+            }
+            void operator()(SLIST_HEADER * pListHeader)
+            {
+                _Count += QueryDepthSList(pListHeader);
+            }
+        private:
+            DWORD& _Count;
+        } Predicate(Count);
+#endif
+        //
+        // [&Count] means that the method can modify local variable Count.
+        //
+        m_pFreeLists ->ForEach(Predicate);
+    }
+
+    return Count;
+}
+
+// static
+BOOL
+ALLOC_CACHE_HANDLER::IsPageheapEnabled(
+    VOID
+)
+{
+    BOOL        fRet = FALSE;
+    BOOL        fLockedHeap = FALSE;
+    HMODULE     hModule = NULL;
+    HANDLE      hHeap = NULL;
+    PROCESS_HEAP_ENTRY heapEntry = {0};
+
+    //
+    // If verifier.dll is loaded - we are running under app verifier == pageheap is enabled
+    //
+    hModule = GetModuleHandle( L"verifier.dll" );
+    if ( hModule != NULL )
+    {
+        hModule = NULL;
+        fRet = TRUE;
+        goto Finished;
+    }
+
+    //
+    // Create a heap for calling heapwalk 
+    // otherwise HeapWalk turns off lookasides for a useful heap
+    //
+    hHeap = ::HeapCreate( 0, 0, 0 );
+    if ( hHeap == NULL )
+    {
+        fRet = FALSE;
+        goto Finished;
+    }
+    
+    fRet = ::HeapLock( hHeap );
+    if ( !fRet )
+    {
+        goto Finished;
+    }
+    fLockedHeap = TRUE;
+
+    //
+    // If HeapWalk is unsupported -> then running page heap
+    //
+    fRet = ::HeapWalk( hHeap, &heapEntry );
+    if ( !fRet )
+    {
+        if ( GetLastError() == ERROR_INVALID_FUNCTION )
+        {
+            fRet = TRUE;
+            goto Finished;
+        }
+    }
+
+    fRet = FALSE;
+
+Finished:
+
+    if ( fLockedHeap )
+    {
+        fLockedHeap = FALSE;
+        DBG_REQUIRE( ::HeapUnlock( hHeap ) );
+    }
+
+    if ( hHeap )
+    {
+        DBG_REQUIRE( ::HeapDestroy( hHeap ) );
+        hHeap = NULL;
+    }
+
+    return fRet;
+}
\ No newline at end of file
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/IISLib/acache.h b/src/IISIntegration/src/AspNetCoreModuleV2/IISLib/acache.h
new file mode 100644
index 0000000000000000000000000000000000000000..048df2b507d63b8194f42cd4cfbe5e948c4082f8
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/IISLib/acache.h
@@ -0,0 +1,115 @@
+// 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 "percpu.h"
+
+class ALLOC_CACHE_HANDLER
+{
+public:
+
+    ALLOC_CACHE_HANDLER(
+        VOID
+    );
+
+    ~ALLOC_CACHE_HANDLER(
+        VOID
+    );
+
+    HRESULT
+    Initialize(
+        DWORD       cbSize,
+        LONG        nThreshold
+    );
+
+    LPVOID
+    Alloc(
+        VOID
+    );
+
+    VOID
+    Free(
+        __in LPVOID pMemory
+    );
+
+
+private:
+
+    VOID
+    CleanupLookaside(
+        VOID
+    );
+
+    DWORD
+    QueryDepthForAllSLists(
+        VOID
+    );
+
+    LONG                    m_nThreshold;
+    DWORD                   m_cbSize;
+
+    PER_CPU<SLIST_HEADER> * m_pFreeLists;
+
+    //
+    // Total heap allocations done over the lifetime.
+    // Note that this is not interlocked, it is just a hint for debugging.
+    //
+    volatile LONG           m_nTotal;
+
+    LONG                    m_nFillPattern;
+
+public:
+
+    static
+    HRESULT
+    StaticInitialize(
+        VOID
+    );
+    
+    static
+    VOID
+    StaticTerminate(
+        VOID
+    );
+
+    static
+    BOOL
+    IsPageheapEnabled();
+
+private:
+
+    static LONG             sm_nFillPattern;
+    static HANDLE           sm_hHeap;
+};
+
+
+// You can use ALLOC_CACHE_HANDLER as a per-class allocator
+// in your C++ classes.  Add the following to your class definition:
+//
+//  protected:
+//      static ALLOC_CACHE_HANDLER* sm_palloc;
+//  public:
+//      static void*  operator new(size_t s)
+//      {
+//        IRTLASSERT(s == sizeof(C));
+//        IRTLASSERT(sm_palloc != NULL);
+//        return sm_palloc->Alloc();
+//      }
+//      static void   operator delete(void* pv)
+//      {
+//        IRTLASSERT(pv != NULL);
+//        if (sm_palloc != NULL)
+//            sm_palloc->Free(pv);
+//      }
+//
+// Obviously, you must initialize sm_palloc before you can allocate
+// any objects of this class.
+//
+// Note that if you derive a class from this base class, the derived class
+// must also provide its own operator new and operator delete.  If not, the
+// base class's allocator will be called, but the size of the derived
+// object will almost certainly be larger than that of the base object.
+// Furthermore, the allocator will not be used for arrays of objects
+// (override operator new[] and operator delete[]), but this is a
+// harder problem since the allocator works with one fixed size.
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/IISLib/ahutil.cpp b/src/IISIntegration/src/AspNetCoreModuleV2/IISLib/ahutil.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..dae2027f335661f762a808d08f23c596235f8579
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/IISLib/ahutil.cpp
@@ -0,0 +1,1671 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#include "precomp.h"
+
+HRESULT
+SetElementProperty(
+    IN          IAppHostElement *   pElement,
+    IN          CONST WCHAR *       szPropName,
+    IN          CONST VARIANT *     varPropValue
+    )
+{
+    HRESULT hr = NOERROR;
+
+    CComPtr<IAppHostProperty>   pPropElement;
+
+    BSTR bstrPropName = SysAllocString( szPropName );
+
+    if( !bstrPropName )
+    {
+        hr = E_OUTOFMEMORY;
+        DBGERROR_HR( hr );
+        goto exit;
+    }
+
+    hr = pElement->GetPropertyByName( bstrPropName,
+                                      &pPropElement );
+    if( FAILED(hr) )
+    {
+        DBGERROR_HR( hr );
+        goto exit;
+    }
+
+    hr = pPropElement->put_Value( *varPropValue );
+    if( FAILED(hr) )
+    {
+        DBGERROR_HR( hr );
+        goto exit;
+    }
+
+exit:
+
+    if( bstrPropName )
+    {
+        SysFreeString( bstrPropName );
+        bstrPropName = NULL;
+    }
+
+    return hr;
+}
+
+HRESULT
+SetElementStringProperty(
+    IN          IAppHostElement *   pElement,
+    IN          CONST WCHAR *       szPropName,
+    IN          CONST WCHAR *       szPropValue
+    )
+{
+    HRESULT hr;
+    VARIANT varPropValue;
+    VariantInit(&varPropValue);
+
+    hr = VariantAssign(&varPropValue, szPropValue);
+
+    if (FAILED(hr))
+    {
+        DBGERROR_HR(hr);
+        goto exit;
+    }
+
+    hr = SetElementProperty(pElement, szPropName, &varPropValue);
+
+    if (FAILED(hr))
+    {
+        DBGERROR_HR(hr);
+        goto exit;
+    }
+
+exit:
+
+    VariantClear(&varPropValue);
+    return hr;
+}
+
+HRESULT
+GetElementStringProperty(
+    IN          IAppHostElement *   pElement,
+    IN          CONST WCHAR *       szPropName,
+    OUT         BSTR *              pbstrPropValue
+    )
+{
+    HRESULT hr = S_OK;
+    BSTR bstrPropName = SysAllocString( szPropName );
+    IAppHostProperty* pProperty = NULL;
+
+    *pbstrPropValue = NULL;
+
+    if (!bstrPropName)
+    {
+        hr = E_OUTOFMEMORY;
+        DBGERROR_HR( hr );
+        goto exit;
+    }
+
+    hr = pElement->GetPropertyByName( bstrPropName, &pProperty );
+    if (FAILED(hr))
+    {
+        DBGERROR_HR( hr );
+        goto exit;
+    }
+
+    hr = pProperty->get_StringValue( pbstrPropValue );
+    if (FAILED(hr))
+    {
+        DBGERROR_HR( hr );
+        goto exit;
+    }
+
+exit:
+
+    if (pProperty)
+    {
+        pProperty->Release();
+    }
+
+    if (bstrPropName)
+    {
+        SysFreeString( bstrPropName );
+    }
+
+    return hr;
+}
+
+
+HRESULT
+GetElementStringProperty(
+    IN          IAppHostElement *   pElement,
+    IN          CONST WCHAR *       szPropName,
+    OUT         STRU *              pstrPropValue
+    )
+{
+    HRESULT hr = S_OK;
+    BSTR bstrPropName = SysAllocString( szPropName );
+    IAppHostProperty* pProperty = NULL;
+    BSTR bstrPropValue = NULL;
+
+    if (!bstrPropName)
+    {
+        hr = E_OUTOFMEMORY;
+        DBGERROR_HR( hr );
+        goto exit;
+    }
+
+    hr = pElement->GetPropertyByName( bstrPropName, &pProperty );
+    if (FAILED(hr))
+    {
+        DBGERROR_HR( hr );
+        goto exit;
+    }
+
+    hr = pProperty->get_StringValue( &bstrPropValue );
+    if (FAILED(hr))
+    {
+        DBGERROR_HR( hr );
+        goto exit;
+    }
+
+    hr = pstrPropValue->Copy(bstrPropValue);
+    if (FAILED(hr))
+    {
+        DBGERROR_HR( hr );
+        goto exit;
+    }
+
+exit:
+
+    if (pProperty)
+    {
+        pProperty->Release();
+    }
+
+    if (bstrPropValue)
+    {
+        SysFreeString( bstrPropValue );
+    }
+
+    if (bstrPropName)
+    {
+        SysFreeString( bstrPropName );
+    }
+
+    return hr;
+}
+
+HRESULT
+GetElementChildByName(
+    IN IAppHostElement *    pElement,
+    IN LPCWSTR              pszElementName,
+    OUT IAppHostElement **  ppChildElement
+)
+{
+    BSTR bstrElementName = SysAllocString(pszElementName);
+    if (bstrElementName == NULL)
+    {
+        return E_OUTOFMEMORY;
+    }
+    HRESULT hr = pElement->GetElementByName(bstrElementName,
+                                            ppChildElement);
+    SysFreeString(bstrElementName);
+    return hr;
+}
+
+HRESULT
+GetElementBoolProperty(
+    IN IAppHostElement * pElement,
+    IN LPCWSTR           pszPropertyName,
+    OUT bool *           pBool
+)
+{
+    BOOL fValue;
+    HRESULT hr = GetElementBoolProperty(pElement,
+                                        pszPropertyName,
+                                        &fValue);
+    if (SUCCEEDED(hr))
+    {
+        *pBool = !!fValue;
+    }
+    return hr;
+}
+
+HRESULT
+GetElementBoolProperty(
+    IN IAppHostElement * pElement,
+    IN LPCWSTR           pszPropertyName,
+    OUT BOOL *           pBool
+)
+{
+    HRESULT hr = S_OK;
+    BSTR    bstrPropertyName = NULL;
+    IAppHostProperty * pProperty = NULL;
+    VARIANT            varValue;
+
+    VariantInit( &varValue );
+
+    bstrPropertyName = SysAllocString( pszPropertyName );
+    if ( bstrPropertyName == NULL )
+    {
+        hr = E_OUTOFMEMORY;
+        DBGERROR_HR(hr);
+        goto exit;
+    }
+
+    // Now ask for the property and if it succeeds it is returned directly back.
+    hr = pElement->GetPropertyByName( bstrPropertyName, &pProperty );
+    if ( FAILED ( hr ) )
+    {
+       goto exit;
+    }
+
+    // Now let's get the property and then extract it from the Variant.
+    hr = pProperty->get_Value( &varValue );
+    if ( FAILED ( hr ) )
+    {
+         goto exit;
+    }
+
+    hr = VariantChangeType( &varValue, &varValue, 0, VT_BOOL );
+    if ( FAILED ( hr ) )
+    {
+         goto exit;
+    }
+
+    // extract the value
+    *pBool = ( V_BOOL( &varValue ) == VARIANT_TRUE );
+
+exit:
+
+    VariantClear( &varValue );
+
+    if ( bstrPropertyName != NULL )
+    {
+        SysFreeString( bstrPropertyName );
+        bstrPropertyName = NULL;
+    }
+
+    if ( pProperty != NULL )
+    {
+        pProperty->Release();
+        pProperty = NULL;
+    }
+
+    return hr;
+
+}
+
+HRESULT
+GetElementDWORDProperty(
+    IN  IAppHostElement * pSitesCollectionEntry,
+    IN  LPCWSTR           pwszName,
+    OUT DWORD *           pdwValue
+)
+{
+    HRESULT            hr = S_OK;
+    IAppHostProperty * pProperty = NULL;
+    BSTR               bstrName = NULL;
+    VARIANT            varValue;
+
+    VariantInit( &varValue );
+
+    bstrName = SysAllocString( pwszName );
+    if ( bstrName == NULL )
+    {
+        hr = E_OUTOFMEMORY;
+        DBGERROR_HR(hr);
+        goto error;
+    }
+
+    hr = pSitesCollectionEntry->GetPropertyByName( bstrName,
+                                                   &pProperty );
+    if ( FAILED ( hr ) )
+    {
+        goto error;
+    }
+
+    hr = pProperty->get_Value( &varValue );
+    if ( FAILED ( hr ) )
+    {
+         goto error;
+    }
+
+    hr = VariantChangeType( &varValue, &varValue, 0, VT_UI4 );
+    if ( FAILED ( hr ) )
+    {
+         goto error;
+    }
+
+    // extract the value
+    *pdwValue = varValue.ulVal;
+
+error:
+
+    VariantClear( &varValue );
+
+    if ( pProperty != NULL )
+    {
+        pProperty->Release();
+        pProperty = NULL;
+    }
+
+    if ( bstrName != NULL )
+    {
+        SysFreeString( bstrName );
+        bstrName = NULL;
+    }
+
+    return hr;
+}
+
+HRESULT
+GetElementLONGLONGProperty(
+    IN  IAppHostElement * pSitesCollectionEntry,
+    IN  LPCWSTR           pwszName,
+    OUT LONGLONG *        pllValue
+)
+{
+    HRESULT            hr = S_OK;
+    IAppHostProperty * pProperty = NULL;
+    BSTR               bstrName = NULL;
+    VARIANT            varValue;
+
+    VariantInit( &varValue );
+
+    bstrName = SysAllocString( pwszName );
+    if ( bstrName == NULL )
+    {
+        hr = E_OUTOFMEMORY;
+        DBGERROR_HR(hr);
+        goto error;
+    }
+
+    hr = pSitesCollectionEntry->GetPropertyByName( bstrName,
+                                                   &pProperty );
+    if ( FAILED ( hr ) )
+    {
+        goto error;
+    }
+
+    hr = pProperty->get_Value( &varValue );
+    if ( FAILED ( hr ) )
+    {
+         goto error;
+    }
+
+    hr = VariantChangeType( &varValue, &varValue, 0, VT_I8 );
+    if ( FAILED ( hr ) )
+    {
+         goto error;
+    }
+
+    // extract the value
+    *pllValue = varValue.ulVal;
+
+error:
+
+    VariantClear( &varValue );
+
+    if ( pProperty != NULL )
+    {
+        pProperty->Release();
+        pProperty = NULL;
+    }
+
+    if ( bstrName != NULL )
+    {
+        SysFreeString( bstrName );
+        bstrName = NULL;
+    }
+
+    return hr;
+}
+
+HRESULT
+GetElementRawTimeSpanProperty(
+    IN IAppHostElement * pElement,
+    IN LPCWSTR           pszPropertyName,
+    OUT ULONGLONG *      pulonglong
+)
+{
+    HRESULT hr = S_OK;
+    BSTR    bstrPropertyName = NULL;
+    IAppHostProperty * pProperty = NULL;
+    VARIANT            varValue;
+
+    VariantInit( &varValue );
+
+    bstrPropertyName = SysAllocString( pszPropertyName );
+    if ( bstrPropertyName == NULL )
+    {
+        hr = HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
+        goto Finished;
+    }
+
+    // Now ask for the property and if it succeeds it is returned directly back
+    hr = pElement->GetPropertyByName( bstrPropertyName, &pProperty );
+    if ( FAILED ( hr ) )
+    {
+       goto Finished;
+    }
+
+    // Now let's get the property and then extract it from the Variant.
+    hr = pProperty->get_Value( &varValue );
+    if ( FAILED ( hr ) )
+    {
+         goto Finished;
+    }
+
+    hr = VariantChangeType( &varValue, &varValue, 0, VT_UI8 );
+    if ( FAILED ( hr ) )
+    {
+         goto Finished;
+    }
+
+    // extract the value
+    *pulonglong = varValue.ullVal;
+
+
+Finished:
+
+    VariantClear( &varValue );
+
+    if ( bstrPropertyName != NULL )
+    {
+        SysFreeString( bstrPropertyName );
+        bstrPropertyName = NULL;
+    }
+
+    if ( pProperty != NULL )
+    {
+        pProperty->Release();
+        pProperty = NULL;
+    }
+
+    return hr;
+
+} // end of Config_GetRawTimeSpanProperty
+
+HRESULT
+DeleteElementFromCollection(
+    IAppHostElementCollection           *pCollection,
+    CONST WCHAR *                       szKeyName,
+    CONST WCHAR *                       szKeyValue,
+    ULONG                               BehaviorFlags,
+    BOOL *                              pfDeleted
+    )
+{
+    HRESULT hr = NOERROR;
+    ULONG index;
+
+    VARIANT varIndex;
+    VariantInit( &varIndex );
+
+    *pfDeleted = FALSE;
+
+    hr = FindElementInCollection(
+             pCollection,
+             szKeyName,
+             szKeyValue,
+             BehaviorFlags,
+             &index
+             );
+
+    if (FAILED(hr))
+    {
+        DBGERROR_HR(hr);
+        goto exit;
+    }
+
+    if (hr == S_FALSE)
+    {
+        //
+        // Not found.
+        //
+
+        goto exit;
+    }
+
+    varIndex.vt = VT_UI4;
+    varIndex.ulVal = index;
+
+    hr = pCollection->DeleteElement( varIndex );
+
+    if( FAILED(hr) )
+    {
+        DBGERROR_HR(hr);
+        goto exit;
+    }
+
+    *pfDeleted = TRUE;
+
+exit:
+
+    return hr;
+}
+
+HRESULT
+DeleteAllElementsFromCollection(
+    IAppHostElementCollection           *pCollection,
+    CONST WCHAR *                       szKeyName,
+    CONST WCHAR *                       szKeyValue,
+    ULONG                               BehaviorFlags,
+    UINT *                              pNumDeleted
+    )
+{
+    HRESULT hr = S_OK;
+    UINT numDeleted = 0;
+    BOOL fDeleted = TRUE;
+
+    while (fDeleted)
+    {
+        hr = DeleteElementFromCollection(
+                 pCollection,
+                 szKeyName,
+                 szKeyValue,
+                 BehaviorFlags,
+                 &fDeleted
+                 );
+
+        if (hr == S_FALSE)
+        {
+            hr = S_OK;
+            break;
+        }
+
+        if (FAILED(hr))
+        {
+            DBGERROR_HR(hr);
+            break;
+        }
+
+        if (fDeleted)
+        {
+            numDeleted++;
+        }
+    }
+
+    *pNumDeleted = numDeleted;
+    return hr;
+}
+
+BOOL
+FindCompareCaseSensitive(
+    CONST WCHAR * szLookupValue,
+    CONST WCHAR * szKeyValue
+    )
+{
+    return !wcscmp(szLookupValue, szKeyValue);
+}
+
+BOOL
+FindCompareCaseInsensitive(
+    CONST WCHAR * szLookupValue,
+    CONST WCHAR * szKeyValue
+    )
+{
+    return !_wcsicmp(szLookupValue, szKeyValue);
+}
+
+typedef
+BOOL
+(*PFN_FIND_COMPARE_PROC)(
+    CONST WCHAR *szLookupValue,
+    CONST WCHAR *szKeyValue
+    );
+
+HRESULT
+FindElementInCollection(
+    IAppHostElementCollection           *pCollection,
+    CONST WCHAR *                       szKeyName,
+    CONST WCHAR *                       szKeyValue,
+    ULONG                               BehaviorFlags,
+    OUT   ULONG *                       pIndex
+    )
+{
+    HRESULT hr = NOERROR;
+
+    CComPtr<IAppHostElement>        pElement;
+    CComPtr<IAppHostProperty>       pKeyProperty;
+
+    VARIANT varIndex;
+    VariantInit( &varIndex );
+
+    VARIANT varKeyValue;
+    VariantInit( &varKeyValue );
+
+    DWORD   count;
+    DWORD   i;
+
+    BSTR bstrKeyName = NULL;
+    PFN_FIND_COMPARE_PROC compareProc;
+
+    compareProc = (BehaviorFlags & FIND_ELEMENT_CASE_INSENSITIVE)
+                      ? &FindCompareCaseInsensitive
+                      : &FindCompareCaseSensitive;
+
+    bstrKeyName = SysAllocString( szKeyName );
+    if( !bstrKeyName )
+    {
+        hr = E_OUTOFMEMORY;
+        DBGERROR_HR(hr);
+        goto exit;
+    }
+
+    hr = pCollection->get_Count( &count );
+    if( FAILED(hr) )
+    {
+        DBGERROR_HR(hr);
+        goto exit;
+    }
+
+    for( i = 0; i < count; i++ )
+    {
+        varIndex.vt = VT_UI4;
+        varIndex.ulVal = i;
+
+        hr = pCollection->get_Item( varIndex,
+                                    &pElement );
+        if( FAILED(hr) )
+        {
+            DBGERROR_HR(hr);
+            goto tryNext;
+        }
+
+        hr = pElement->GetPropertyByName( bstrKeyName,
+                                          &pKeyProperty );
+        if( FAILED(hr) )
+        {
+            DBGERROR_HR(hr);
+            goto tryNext;
+        }
+
+        hr = pKeyProperty->get_Value( &varKeyValue );
+
+        if( FAILED(hr) )
+        {
+            DBGERROR_HR(hr);
+            goto tryNext;
+        }
+
+        if ((compareProc)(szKeyValue, varKeyValue.bstrVal))
+        {
+            *pIndex = i;
+            break;
+        }
+
+tryNext:
+
+        pElement.Release();
+        pKeyProperty.Release();
+
+        VariantClear( &varKeyValue );
+    }
+
+    if (i >= count)
+    {
+        hr = S_FALSE;
+    }
+
+exit:
+
+    SysFreeString( bstrKeyName );
+    VariantClear( &varKeyValue );
+
+    return hr;
+}
+
+HRESULT
+VariantAssign(
+    IN OUT      VARIANT *       pv,
+    IN          CONST WCHAR *   sz
+    )
+{
+    if( !pv || !sz )
+    {
+        return E_INVALIDARG;
+    }
+
+    HRESULT hr = NOERROR;
+
+    BSTR bstr = SysAllocString( sz );
+    if( !bstr )
+    {
+        hr = E_OUTOFMEMORY;
+        DBGERROR_HR( hr );
+        goto exit;
+    }
+
+    hr = VariantClear( pv );
+    if( FAILED(hr) )
+    {
+        DBGERROR_HR( hr );
+        goto exit;
+    }
+
+    pv->vt = VT_BSTR;
+    pv->bstrVal = bstr;
+    bstr = NULL;
+
+exit:
+
+    SysFreeString( bstr );
+
+    return hr;
+}
+
+HRESULT
+GetLocationFromFile(
+    IN      IAppHostAdminManager *      pAdminMgr,
+    IN      CONST WCHAR *               szConfigPath,
+    IN      CONST WCHAR *               szLocationPath,
+    OUT     IAppHostConfigLocation **   ppLocation,
+    OUT     BOOL *                      pFound
+    )
+{
+    HRESULT hr = NOERROR;
+
+    CComPtr<IAppHostConfigLocationCollection>   pLocationCollection;
+    CComPtr<IAppHostConfigLocation>             pLocation;
+
+    BSTR bstrLocationPath = NULL;
+
+    *ppLocation = NULL;
+    *pFound = FALSE;
+
+    hr = GetLocationCollection( pAdminMgr,
+                                szConfigPath,
+                                &pLocationCollection );
+
+    if( FAILED(hr) )
+    {
+        DBGERROR_HR(hr);
+        goto exit;
+    }
+
+    DWORD count;
+    DWORD i;
+    VARIANT varIndex;
+    VariantInit( &varIndex );
+
+    hr = pLocationCollection->get_Count( &count );
+    if( FAILED(hr) )
+    {
+        DBGERROR_HR(hr);
+        goto exit;
+    }
+
+    for( i = 0; i < count; i++ )
+    {
+        varIndex.vt = VT_UI4;
+        varIndex.ulVal = i;
+
+        hr = pLocationCollection->get_Item( varIndex,
+                                            &pLocation );
+        if( FAILED(hr) )
+        {
+            DBGERROR_HR(hr);
+            goto exit;
+        }
+
+        hr = pLocation->get_Path( &bstrLocationPath );
+        if( FAILED(hr) )
+        {
+            DBGERROR_HR(hr);
+            goto exit;
+        }
+
+        if( 0 == wcscmp ( szLocationPath, bstrLocationPath ) )
+        {
+            *pFound = TRUE;
+            *ppLocation = pLocation.Detach();
+            break;
+        }
+
+
+        pLocation.Release();
+
+        SysFreeString( bstrLocationPath );
+        bstrLocationPath = NULL;
+    }
+
+exit:
+
+    SysFreeString( bstrLocationPath );
+
+    return hr;
+}
+
+HRESULT
+GetSectionFromLocation(
+    IN      IAppHostConfigLocation *            pLocation,
+    IN      CONST WCHAR *                       szSectionName,
+    OUT     IAppHostElement **                  ppSectionElement,
+    OUT     BOOL *                              pFound
+    )
+{
+    HRESULT hr = NOERROR;
+
+    CComPtr<IAppHostElement>    pSectionElement;
+
+    DWORD count;
+    DWORD i;
+
+    VARIANT varIndex;
+    VariantInit( &varIndex );
+
+    BSTR bstrSectionName = NULL;
+
+    *pFound = FALSE;
+    *ppSectionElement = NULL;
+
+    hr = pLocation->get_Count( &count );
+    if( FAILED(hr) )
+    {
+        DBGERROR_HR(hr);
+        goto exit;
+    }
+
+    for( i = 0; i < count; i++ )
+    {
+        varIndex.vt = VT_UI4;
+        varIndex.ulVal = i;
+
+
+        hr = pLocation->get_Item( varIndex,
+                                  &pSectionElement );
+        if( FAILED(hr) )
+        {
+            DBGERROR_HR(hr);
+            goto exit;
+        }
+
+        hr = pSectionElement->get_Name( &bstrSectionName );
+        if( FAILED(hr) )
+        {
+            DBGERROR_HR(hr);
+            goto exit;
+        }
+
+        if( 0 == wcscmp ( szSectionName, bstrSectionName ) )
+        {
+            *pFound = TRUE;
+            *ppSectionElement = pSectionElement.Detach();
+            break;
+        }
+
+        pSectionElement.Release();
+
+        SysFreeString( bstrSectionName );
+        bstrSectionName = NULL;
+    }
+
+exit:
+
+    SysFreeString( bstrSectionName );
+
+    return hr;
+}
+
+
+HRESULT
+GetAdminElement(
+    IN      IAppHostAdminManager *      pAdminMgr,
+    IN      CONST WCHAR *               szConfigPath,
+    IN      CONST WCHAR *               szElementName,
+    OUT     IAppHostElement **          pElement
+)
+{
+    HRESULT hr = S_OK;
+    BSTR bstrConfigPath = NULL;
+    BSTR bstrElementName = NULL;
+
+    bstrConfigPath = SysAllocString(szConfigPath);
+    bstrElementName = SysAllocString(szElementName);
+
+    if (bstrConfigPath == NULL || bstrElementName == NULL)
+    {
+        hr = E_OUTOFMEMORY;
+        DBGERROR_HR(hr);
+        goto exit;
+    }
+
+    hr = pAdminMgr->GetAdminSection( bstrElementName,
+                                     bstrConfigPath,
+                                     pElement );
+
+    if (FAILED(hr))
+    {
+        DBGERROR_HR(hr);
+        goto exit;
+    }
+
+exit:
+
+    if ( bstrElementName != NULL )
+    {
+        SysFreeString(bstrElementName);
+        bstrElementName = NULL;
+    }
+    if ( bstrConfigPath != NULL )
+    {
+        SysFreeString(bstrConfigPath);
+        bstrConfigPath = NULL;
+    }
+
+    return hr;
+}
+
+
+HRESULT
+ClearAdminElement(
+    IN      IAppHostAdminManager *      pAdminMgr,
+    IN      CONST WCHAR *               szConfigPath,
+    IN      CONST WCHAR *               szElementName
+    )
+{
+    HRESULT hr;
+    CComPtr<IAppHostElement> pElement;
+
+    hr = GetAdminElement(
+             pAdminMgr,
+             szConfigPath,
+             szElementName,
+             &pElement
+             );
+
+    if (FAILED(hr))
+    {
+        if (hr == HRESULT_FROM_WIN32(ERROR_NOT_FOUND))
+        {
+            hr = S_OK;
+        }
+        else
+        {
+            DBGERROR_HR(hr);
+        }
+
+        goto exit;
+    }
+
+    hr = pElement->Clear();
+
+    if (FAILED(hr))
+    {
+        DBGERROR_HR(hr);
+        goto exit;
+    }
+
+exit:
+
+    return hr;
+}
+
+
+HRESULT
+ClearElementFromAllSites(
+    IN      IAppHostAdminManager *      pAdminMgr,
+    IN      CONST WCHAR *               szConfigPath,
+    IN      CONST WCHAR *               szElementName
+    )
+{
+    HRESULT hr;
+    CComPtr<IAppHostElementCollection> pSitesCollection;
+    CComPtr<IAppHostElement> pSiteElement;
+    CComPtr<IAppHostChildElementCollection> pChildCollection;
+    ENUM_INDEX index;
+    BOOL found;
+
+    //
+    // Enumerate the sites, remove the specified elements.
+    //
+
+    hr = GetSitesCollection(
+             pAdminMgr,
+             szConfigPath,
+             &pSitesCollection
+             );
+
+    if (FAILED(hr))
+    {
+        DBGERROR_HR(hr);
+        goto exit;
+    }
+
+    for (hr = FindFirstElement(pSitesCollection, &index, &pSiteElement) ;
+         SUCCEEDED(hr) ;
+         hr = FindNextElement(pSitesCollection, &index, &pSiteElement))
+    {
+        if (hr == S_FALSE)
+        {
+            hr = S_OK;
+            break;
+        }
+
+        hr = pSiteElement->get_ChildElements(&pChildCollection);
+
+        if (FAILED(hr))
+        {
+            DBGERROR_HR(hr);
+            goto exit;
+        }
+
+        if (pChildCollection)
+        {
+            hr = ClearChildElementsByName(
+                    pChildCollection,
+                    szElementName,
+                    &found
+                    );
+
+            if (FAILED(hr))
+            {
+                DBGERROR_HR(hr);
+                goto exit;
+            }
+        }
+
+        pSiteElement.Release();
+    }
+
+exit:
+
+    return hr;
+
+}
+
+
+HRESULT
+ClearElementFromAllLocations(
+    IN      IAppHostAdminManager *      pAdminMgr,
+    IN      CONST WCHAR *               szConfigPath,
+    IN      CONST WCHAR *               szElementName
+    )
+{
+    HRESULT hr;
+    CComPtr<IAppHostConfigLocationCollection> pLocationCollection;
+    CComPtr<IAppHostConfigLocation> pLocation;
+    CComPtr<IAppHostChildElementCollection> pChildCollection;
+    ENUM_INDEX index;
+
+    //
+    // Enum the <location> tags, remove the specified elements.
+    //
+
+    hr = GetLocationCollection(
+            pAdminMgr,
+            szConfigPath,
+            &pLocationCollection
+            );
+
+    if (FAILED(hr))
+    {
+        DBGERROR_HR(hr);
+        goto exit;
+    }
+
+    for (hr = FindFirstLocation(pLocationCollection, &index, &pLocation) ;
+         SUCCEEDED(hr) ;
+         hr = FindNextLocation(pLocationCollection, &index, &pLocation))
+    {
+        if (hr == S_FALSE)
+        {
+            hr = S_OK;
+            break;
+        }
+
+        hr = ClearLocationElements(pLocation, szElementName);
+
+        if (FAILED(hr))
+        {
+            DBGERROR_HR(hr);
+            goto exit;
+        }
+
+        pLocation.Release();
+    }
+
+exit:
+
+    return hr;
+
+}
+
+HRESULT
+ClearLocationElements(
+    IN      IAppHostConfigLocation *    pLocation,
+    IN      CONST WCHAR *               szElementName
+    )
+{
+    HRESULT hr;
+    CComPtr<IAppHostElement> pElement;
+    ENUM_INDEX index;
+    BOOL matched;
+
+    for (hr = FindFirstLocationElement(pLocation, &index, &pElement) ;
+         SUCCEEDED(hr) ;
+         hr = FindNextLocationElement(pLocation, &index, &pElement))
+    {
+        if (hr == S_FALSE)
+        {
+            hr = S_OK;
+            break;
+        }
+
+        hr = CompareElementName(pElement, szElementName, &matched);
+
+        if (FAILED(hr))
+        {
+            DBGERROR_HR(hr);
+            goto exit;
+        }
+
+        if (matched)
+        {
+            pElement->Clear();
+        }
+
+        pElement.Release();
+    }
+
+exit:
+
+    return hr;
+}
+
+HRESULT
+CompareElementName(
+    IN      IAppHostElement *           pElement,
+    IN      CONST WCHAR *               szNameToMatch,
+    OUT     BOOL *                      pMatched
+    )
+{
+    HRESULT hr;
+    BSTR bstrElementName = NULL;
+
+    *pMatched = FALSE;  // until proven otherwise
+
+    hr = pElement->get_Name(&bstrElementName);
+
+    if (FAILED(hr))
+    {
+        DBGERROR_HR(hr);
+        goto exit;
+    }
+
+    if( 0 == wcscmp ( szNameToMatch, bstrElementName ) )
+    {
+        *pMatched = TRUE;
+    }
+
+exit:
+
+    SysFreeString(bstrElementName);
+    return hr;
+}
+
+
+HRESULT
+ClearChildElementsByName(
+    IN      IAppHostChildElementCollection *    pCollection,
+    IN      CONST WCHAR *                       szElementName,
+    OUT     BOOL *                              pFound
+    )
+{
+    HRESULT hr;
+    CComPtr<IAppHostElement> pElement;
+    ENUM_INDEX index;
+    BOOL matched;
+
+    *pFound = FALSE;
+
+    for (hr = FindFirstChildElement(pCollection, &index, &pElement) ;
+         SUCCEEDED(hr) ;
+         hr = FindNextChildElement(pCollection, &index, &pElement))
+    {
+        if (hr == S_FALSE)
+        {
+            hr = S_OK;
+            break;
+        }
+
+        hr = CompareElementName(pElement, szElementName, &matched);
+
+        if (FAILED(hr))
+        {
+            DBGERROR_HR(hr);
+            goto exit;
+        }
+
+        if (matched)
+        {
+            hr = pElement->Clear();
+
+            if (FAILED(hr))
+            {
+                DBGERROR_HR(hr);
+                goto exit;
+            }
+
+            *pFound = TRUE;
+        }
+
+        pElement.Release();
+    }
+
+exit:
+
+    return hr;
+}
+
+
+HRESULT
+GetSitesCollection(
+    IN      IAppHostAdminManager *              pAdminMgr,
+    IN      CONST WCHAR *                       szConfigPath,
+    OUT     IAppHostElementCollection **        pSitesCollection
+    )
+{
+    HRESULT hr;
+    CComPtr<IAppHostElement> pSitesElement;
+    BSTR bstrConfigPath;
+    BSTR bstrSitesSectionName;
+
+    bstrConfigPath = SysAllocString(szConfigPath);
+    bstrSitesSectionName = SysAllocString(L"system.applicationHost/sites");
+    *pSitesCollection = NULL;
+
+    if (bstrConfigPath == NULL || bstrSitesSectionName == NULL)
+    {
+        hr = E_OUTOFMEMORY;
+        DBGERROR_HR(hr);
+        goto exit;
+    }
+
+    //
+    // Chase down the sites collection.
+    //
+
+    hr = pAdminMgr->GetAdminSection( bstrSitesSectionName,
+                                     bstrConfigPath,
+                                     &pSitesElement );
+
+    if (FAILED(hr))
+    {
+        DBGERROR_HR(hr);
+        goto exit;
+    }
+
+    hr = pSitesElement->get_Collection(pSitesCollection);
+
+    if (FAILED(hr))
+    {
+        DBGERROR_HR(hr);
+        goto exit;
+    }
+
+exit:
+
+    SysFreeString(bstrSitesSectionName);
+    SysFreeString(bstrConfigPath);
+    return hr;
+}
+
+
+HRESULT
+GetLocationCollection(
+    IN      IAppHostAdminManager *              pAdminMgr,
+    IN      CONST WCHAR *                       szConfigPath,
+    OUT     IAppHostConfigLocationCollection ** pLocationCollection
+    )
+{
+    HRESULT hr;
+    BSTR bstrConfigPath;
+    CComPtr<IAppHostConfigManager>      pConfigMgr;
+    CComPtr<IAppHostConfigFile>         pConfigFile;
+
+    bstrConfigPath = SysAllocString(szConfigPath);
+    *pLocationCollection = NULL;
+
+    if (bstrConfigPath == NULL)
+    {
+        hr = E_OUTOFMEMORY;
+        DBGERROR_HR(hr);
+        goto exit;
+    }
+
+    hr = pAdminMgr->get_ConfigManager(&pConfigMgr);
+
+    if (FAILED(hr))
+    {
+        DBGERROR_HR(hr);
+        goto exit;
+    }
+
+    hr = pConfigMgr->GetConfigFile(bstrConfigPath, &pConfigFile);
+
+    if (FAILED(hr))
+    {
+        DBGERROR_HR(hr);
+        goto exit;
+    }
+
+    hr = pConfigFile->get_Locations(pLocationCollection);
+
+    if (FAILED(hr))
+    {
+        DBGERROR_HR(hr);
+        goto exit;
+    }
+
+exit:
+
+    SysFreeString(bstrConfigPath);
+    return hr;
+}
+
+
+HRESULT
+FindFirstElement(
+    IN      IAppHostElementCollection *         pCollection,
+    OUT     ENUM_INDEX *                        pIndex,
+    OUT     IAppHostElement **                  pElement
+    )
+{
+    HRESULT hr;
+
+    hr = pCollection->get_Count(&pIndex->Count);
+
+    if (FAILED(hr))
+    {
+        DBGERROR_HR(hr);
+        return hr;
+    }
+
+    VariantInit(&pIndex->Index);
+    pIndex->Index.vt = VT_UI4;
+    pIndex->Index.ulVal = 0;
+
+    return FindNextElement(pCollection, pIndex, pElement);
+}
+
+HRESULT
+FindNextElement(
+    IN      IAppHostElementCollection *         pCollection,
+    IN OUT  ENUM_INDEX *                        pIndex,
+    OUT     IAppHostElement **                  pElement
+    )
+{
+    HRESULT hr;
+
+    *pElement = NULL;
+
+    if (pIndex->Index.ulVal >= pIndex->Count)
+    {
+        return S_FALSE;
+    }
+
+    hr = pCollection->get_Item(pIndex->Index, pElement);
+
+    if (SUCCEEDED(hr))
+    {
+        pIndex->Index.ulVal++;
+    }
+
+    return hr;
+}
+
+HRESULT
+FindFirstChildElement(
+    IN      IAppHostChildElementCollection *    pCollection,
+    OUT     ENUM_INDEX *                        pIndex,
+    OUT     IAppHostElement **                  pElement
+    )
+{
+    HRESULT hr;
+
+    hr = pCollection->get_Count(&pIndex->Count);
+
+    if (FAILED(hr))
+    {
+        DBGERROR_HR(hr);
+        return hr;
+    }
+
+    VariantInit(&pIndex->Index);
+    pIndex->Index.vt = VT_UI4;
+    pIndex->Index.ulVal = 0;
+
+    return FindNextChildElement(pCollection, pIndex, pElement);
+}
+
+HRESULT
+FindNextChildElement(
+    IN      IAppHostChildElementCollection *    pCollection,
+    IN OUT  ENUM_INDEX *                        pIndex,
+    OUT     IAppHostElement **                  pElement
+    )
+{
+    HRESULT hr;
+
+    *pElement = NULL;
+
+    if (pIndex->Index.ulVal >= pIndex->Count)
+    {
+        return S_FALSE;
+    }
+
+    hr = pCollection->get_Item(pIndex->Index, pElement);
+
+    if (SUCCEEDED(hr))
+    {
+        pIndex->Index.ulVal++;
+    }
+
+    return hr;
+}
+
+HRESULT
+FindFirstLocation(
+    IN      IAppHostConfigLocationCollection *  pCollection,
+    OUT     ENUM_INDEX *                        pIndex,
+    OUT     IAppHostConfigLocation **           pLocation
+    )
+{
+    HRESULT hr;
+
+    hr = pCollection->get_Count(&pIndex->Count);
+
+    if (FAILED(hr))
+    {
+        DBGERROR_HR(hr);
+        return hr;
+    }
+
+    VariantInit(&pIndex->Index);
+    pIndex->Index.vt = VT_UI4;
+    pIndex->Index.ulVal = 0;
+
+    return FindNextLocation(pCollection, pIndex, pLocation);
+}
+
+HRESULT
+FindNextLocation(
+    IN      IAppHostConfigLocationCollection *  pCollection,
+    IN OUT  ENUM_INDEX *                        pIndex,
+    OUT     IAppHostConfigLocation **           pLocation
+    )
+{
+    HRESULT hr;
+
+    *pLocation = NULL;
+
+    if (pIndex->Index.ulVal >= pIndex->Count)
+    {
+        return S_FALSE;
+    }
+
+    hr = pCollection->get_Item(pIndex->Index, pLocation);
+
+    if (SUCCEEDED(hr))
+    {
+        pIndex->Index.ulVal++;
+    }
+
+    return hr;
+}
+
+HRESULT
+FindFirstLocationElement(
+    IN      IAppHostConfigLocation *            pLocation,
+    OUT     ENUM_INDEX *                        pIndex,
+    OUT     IAppHostElement **                  pElement
+    )
+{
+    HRESULT hr;
+
+    hr = pLocation->get_Count(&pIndex->Count);
+
+    if (FAILED(hr))
+    {
+        DBGERROR_HR(hr);
+        return hr;
+    }
+
+    VariantInit(&pIndex->Index);
+    pIndex->Index.vt = VT_UI4;
+    pIndex->Index.ulVal = 0;
+
+    return FindNextLocationElement(pLocation, pIndex, pElement);
+}
+
+HRESULT
+FindNextLocationElement(
+    IN      IAppHostConfigLocation *            pLocation,
+    IN OUT  ENUM_INDEX *                        pIndex,
+    OUT     IAppHostElement **                  pElement
+    )
+{
+    HRESULT hr;
+
+    *pElement = NULL;
+
+    if (pIndex->Index.ulVal >= pIndex->Count)
+    {
+        return S_FALSE;
+    }
+
+    hr = pLocation->get_Item(pIndex->Index, pElement);
+
+    if (SUCCEEDED(hr))
+    {
+        pIndex->Index.ulVal++;
+    }
+
+    return hr;
+}
+
+HRESULT
+GetSharedConfigEnabled(
+    BOOL * pfIsSharedConfig
+)
+/*++
+
+Routine Description:
+   Search the configuration for the shared configuration property.
+
+Arguments:
+
+    pfIsSharedConfig - true if shared configuration is enabled
+
+Return Value:
+    HRESULT
+
+--*/
+{
+    HRESULT                 hr = S_OK;
+    IAppHostAdminManager    *pAdminManager = NULL;
+
+    BSTR                    bstrSectionName = NULL;
+    BSTR                    bstrConfigPath = NULL;
+
+    IAppHostElement *       pConfigRedirSection = NULL;
+
+
+    bstrSectionName = SysAllocString( L"configurationRedirection" );
+
+    if ( bstrSectionName == NULL )
+    {
+        hr = E_OUTOFMEMORY;
+        DBGERROR_HR(hr);
+        goto exit;
+    }
+
+    bstrConfigPath = SysAllocString( L"MACHINE/REDIRECTION" );
+    if ( bstrConfigPath == NULL )
+    {
+        hr = E_OUTOFMEMORY;
+        DBGERROR_HR(hr);
+        goto exit;
+    }
+
+    hr = CoCreateInstance( CLSID_AppHostAdminManager,
+                           NULL,
+                           CLSCTX_INPROC_SERVER,
+                           IID_IAppHostAdminManager,
+                           (VOID **)&pAdminManager );
+    if( FAILED(hr) )
+    {
+        DBGERROR_HR(hr);
+        goto exit;
+    }
+
+    hr = pAdminManager->GetAdminSection( bstrSectionName,
+                                         bstrConfigPath,
+                                         &pConfigRedirSection );
+    if( FAILED(hr) )
+    {
+        DBGERROR_HR(hr);
+        goto exit;
+    }
+
+    hr = GetElementBoolProperty( pConfigRedirSection,
+                                 L"enabled",
+                                 pfIsSharedConfig );
+
+    if ( FAILED( hr ) )
+    {
+        DBGERROR_HR(hr);
+        goto exit;
+    }
+
+    pConfigRedirSection->Release();
+    pConfigRedirSection = NULL;
+
+
+exit:
+
+    //
+    // dump config exception to setup log file (if available)
+    //
+
+    if ( pConfigRedirSection != NULL )
+    {
+        pConfigRedirSection->Release();
+    }
+
+    if ( pAdminManager != NULL )
+    {
+        pAdminManager->Release();
+    }
+
+    if ( bstrConfigPath != NULL )
+    {
+        SysFreeString( bstrConfigPath );
+    }
+
+    if ( bstrSectionName != NULL )
+    {
+        SysFreeString( bstrSectionName );
+    }
+
+    return hr;
+}
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/IISLib/ahutil.h b/src/IISIntegration/src/AspNetCoreModuleV2/IISLib/ahutil.h
new file mode 100644
index 0000000000000000000000000000000000000000..5694b21b7ec261870b79d0f42d95c2028ec00c79
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/IISLib/ahutil.h
@@ -0,0 +1,258 @@
+// 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<Windows.h>
+
+HRESULT
+SetElementProperty(
+    IN          IAppHostElement *   pElement,
+    IN          CONST WCHAR *       szPropName,
+    IN          CONST VARIANT *     varPropValue
+    );
+
+HRESULT
+SetElementStringProperty(
+    IN          IAppHostElement *   pElement,
+    IN          CONST WCHAR *       szPropName,
+    IN          CONST WCHAR *       szPropValue
+    );
+
+HRESULT
+GetElementStringProperty(
+    IN          IAppHostElement *   pElement,
+    IN          CONST WCHAR *       szPropName,
+    OUT         BSTR *              pbstrPropValue
+    );
+
+HRESULT
+GetElementStringProperty(
+    IN          IAppHostElement *   pElement,
+    IN          CONST WCHAR *       szPropName,
+    OUT         STRU *              pstrPropValue
+    );
+
+HRESULT
+GetElementBoolProperty(
+    IN IAppHostElement * pElement,
+    IN LPCWSTR           pszPropertyName,
+    OUT BOOL *           pBool
+    );
+
+HRESULT
+GetElementBoolProperty(
+    IN IAppHostElement * pElement,
+    IN LPCWSTR           pszPropertyName,
+    OUT bool *           pBool
+    );
+
+HRESULT
+GetElementChildByName(
+    IN IAppHostElement *    pElement,
+    IN LPCWSTR              pszElementName,
+    OUT IAppHostElement **  ppChildElement
+    );
+
+HRESULT
+GetElementDWORDProperty(
+    IN IAppHostElement * pElement,
+    IN LPCWSTR           pszPropertyName,
+    OUT DWORD *          pdwValue
+    );
+
+HRESULT
+GetElementLONGLONGProperty(
+    IN IAppHostElement * pElement,
+    IN LPCWSTR           pszPropertyName,
+    OUT LONGLONG *       pllValue
+);
+
+
+HRESULT
+GetElementRawTimeSpanProperty(
+    IN IAppHostElement * pElement,
+    IN LPCWSTR           pszPropertyName,
+    OUT ULONGLONG *      pulonglong
+    );
+
+#define FIND_ELEMENT_CASE_SENSITIVE     0x00000000
+#define FIND_ELEMENT_CASE_INSENSITIVE   0x00000001
+
+HRESULT
+DeleteElementFromCollection(
+    IAppHostElementCollection           *pCollection,
+    CONST WCHAR *                       szKeyName,
+    CONST WCHAR *                       szKeyValue,
+    ULONG                               BehaviorFlags,
+    BOOL *                              pfDeleted
+    );
+
+HRESULT
+DeleteAllElementsFromCollection(
+    IAppHostElementCollection           *pCollection,
+    CONST WCHAR *                       szKeyName,
+    CONST WCHAR *                       szKeyValue,
+    ULONG                               BehaviorFlags,
+    UINT *                              pNumDeleted
+    );
+
+HRESULT
+FindElementInCollection(
+    IAppHostElementCollection           *pCollection,
+    CONST WCHAR *                       szKeyName,
+    CONST WCHAR *                       szKeyValue,
+    ULONG                               BehaviorFlags,
+    OUT   ULONG *                       pIndex
+    );
+
+HRESULT
+VariantAssign(
+    IN OUT      VARIANT *       pv,
+    IN          CONST WCHAR *   sz
+    );
+
+HRESULT
+GetLocationFromFile(
+    IN      IAppHostAdminManager *      pAdminMgr,
+    IN      CONST WCHAR *               szConfigPath,
+    IN      CONST WCHAR *               szLocationPath,
+    OUT     IAppHostConfigLocation **   ppLocation,
+    OUT     BOOL *                      pFound
+    );
+
+HRESULT
+GetSectionFromLocation(
+    IN      IAppHostConfigLocation *            pLocation,
+    IN      CONST WCHAR *                       szSectionName,
+    OUT     IAppHostElement **                  ppSectionElement,
+    OUT     BOOL *                              pFound
+    );
+
+HRESULT
+GetAdminElement(
+    IN      IAppHostAdminManager *      pAdminMgr,
+    IN      CONST WCHAR *               szConfigPath,
+    IN      CONST WCHAR *               szElementName,
+    OUT     IAppHostElement **          pElement
+    );
+
+HRESULT
+ClearAdminElement(
+    IN      IAppHostAdminManager *      pAdminMgr,
+    IN      CONST WCHAR *               szConfigPath,
+    IN      CONST WCHAR *               szElementName
+    );
+
+HRESULT
+ClearElementFromAllSites(
+    IN      IAppHostAdminManager *      pAdminMgr,
+    IN      CONST WCHAR *               szConfigPath,
+    IN      CONST WCHAR *               szElementName
+    );
+
+HRESULT
+ClearElementFromAllLocations(
+    IN      IAppHostAdminManager *      pAdminMgr,
+    IN      CONST WCHAR *               szConfigPath,
+    IN      CONST WCHAR *               szElementName
+    );
+
+HRESULT
+ClearLocationElements(
+    IN      IAppHostConfigLocation *    pLocation,
+    IN      CONST WCHAR *               szElementName
+    );
+
+HRESULT
+CompareElementName(
+    IN      IAppHostElement *           pElement,
+    IN      CONST WCHAR *               szNameToMatch,
+    OUT     BOOL *                      pMatched
+    );
+
+HRESULT
+ClearChildElementsByName(
+    IN      IAppHostChildElementCollection *    pCollection,
+    IN      CONST WCHAR *                       szElementName,
+    OUT     BOOL *                              pFound
+    );
+
+HRESULT
+GetSitesCollection(
+    IN      IAppHostAdminManager *              pAdminMgr,
+    IN      CONST WCHAR *                       szConfigPath,
+    OUT     IAppHostElementCollection **        pSitesCollection
+    );
+
+HRESULT
+GetLocationCollection(
+    IN      IAppHostAdminManager *              pAdminMgr,
+    IN      CONST WCHAR *                       szConfigPath,
+    OUT     IAppHostConfigLocationCollection ** pLocationCollection
+    );
+
+struct ENUM_INDEX
+{
+    VARIANT Index;
+    ULONG Count;
+};
+
+HRESULT
+FindFirstElement(
+    IN      IAppHostElementCollection *         pCollection,
+    OUT     ENUM_INDEX *                        pIndex,
+    OUT     IAppHostElement **                  pElement
+    );
+
+HRESULT
+FindNextElement(
+    IN      IAppHostElementCollection *         pCollection,
+    IN OUT  ENUM_INDEX *                        pIndex,
+    OUT     IAppHostElement **                  pElement
+    );
+
+HRESULT
+FindFirstChildElement(
+    IN      IAppHostChildElementCollection *    pCollection,
+    OUT     ENUM_INDEX *                        pIndex,
+    OUT     IAppHostElement **                  pElement
+    );
+
+HRESULT
+FindNextChildElement(
+    IN      IAppHostChildElementCollection *    pCollection,
+    IN OUT  ENUM_INDEX *                        pIndex,
+    OUT     IAppHostElement **                  pElement
+    );
+
+HRESULT
+FindFirstLocation(
+    IN      IAppHostConfigLocationCollection *  pCollection,
+    OUT     ENUM_INDEX *                        pIndex,
+    OUT     IAppHostConfigLocation **           pLocation
+    );
+
+HRESULT
+FindNextLocation(
+    IN      IAppHostConfigLocationCollection *  pCollection,
+    IN OUT  ENUM_INDEX *                        pIndex,
+    OUT     IAppHostConfigLocation **           pLocation
+    );
+
+HRESULT
+FindFirstLocationElement(
+    IN      IAppHostConfigLocation *            pLocation,
+    OUT     ENUM_INDEX *                        pIndex,
+    OUT     IAppHostElement **                  pElement
+    );
+
+HRESULT
+FindNextLocationElement(
+    IN      IAppHostConfigLocation *            pLocation,
+    IN OUT  ENUM_INDEX *                        pIndex,
+    OUT     IAppHostElement **                  pElement
+    );
+
+HRESULT GetSharedConfigEnabled(
+    BOOL * pfIsSharedConfig
+);
\ No newline at end of file
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/IISLib/base64.cpp b/src/IISIntegration/src/AspNetCoreModuleV2/IISLib/base64.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..b8b6a0bf742e5ef5aaf36bfd8eb50b9927c945f8
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/IISLib/base64.cpp
@@ -0,0 +1,482 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#include "precomp.h"
+
+DWORD
+Base64Encode(
+    __in_bcount(cbDecodedBufferSize)    VOID *  pDecodedBuffer,
+    IN      DWORD       cbDecodedBufferSize,
+    __out_ecount_opt(cchEncodedStringSize) PWSTR    pszEncodedString,
+    IN      DWORD       cchEncodedStringSize,
+    __out_opt DWORD *   pcchEncoded
+    )
+/*++
+
+Routine Description:
+
+    Decode a base64-encoded string.
+
+Arguments:
+
+    pDecodedBuffer (IN) - buffer to encode.
+    cbDecodedBufferSize (IN) - size of buffer to encode.
+    cchEncodedStringSize (IN) - size of the buffer for the encoded string.
+    pszEncodedString (OUT) = the encoded string.
+    pcchEncoded (OUT) - size in characters of the encoded string.
+
+Return Values:
+
+    0 - success.
+    E_OUTOFMEMORY
+
+--*/
+{
+    static WCHAR rgchEncodeTable[64] = {
+        'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
+        'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
+        'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
+        'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
+        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
+    };
+
+    DWORD   ib;
+    DWORD   ich;
+    DWORD   cchEncoded;
+    BYTE    b0, b1, b2;
+    BYTE *  pbDecodedBuffer = (BYTE *) pDecodedBuffer;
+
+    // Calculate encoded string size.
+    cchEncoded = 1 + (cbDecodedBufferSize + 2) / 3 * 4;
+
+    if (NULL != pcchEncoded) {
+        *pcchEncoded = cchEncoded;
+    }
+
+    if (cchEncodedStringSize == 0 && pszEncodedString == NULL) {
+        return ERROR_SUCCESS;
+    }
+
+    if (cchEncodedStringSize < cchEncoded) {
+        // Given buffer is too small to hold encoded string.
+        return ERROR_INSUFFICIENT_BUFFER;
+    }
+
+    // Encode data byte triplets into four-byte clusters.
+    ib = ich = 0;
+    while (ib < cbDecodedBufferSize) {
+        b0 = pbDecodedBuffer[ib++];
+        b1 = (ib < cbDecodedBufferSize) ? pbDecodedBuffer[ib++] : 0;
+        b2 = (ib < cbDecodedBufferSize) ? pbDecodedBuffer[ib++] : 0;
+
+        //
+        // The checks below for buffer overflow seems redundant to me.
+        // But it's the only way I can find to keep OACR quiet so it
+        // will have to do.
+        //
+
+        pszEncodedString[ich++] = rgchEncodeTable[b0 >> 2];
+        if ( ich >= cchEncodedStringSize )
+        {
+            DBG_ASSERT( FALSE );
+            return ERROR_BUFFER_OVERFLOW;
+        }
+
+        pszEncodedString[ich++] = rgchEncodeTable[((b0 << 4) & 0x30) | ((b1 >> 4) & 0x0f)];
+        if ( ich >= cchEncodedStringSize )
+        {
+            DBG_ASSERT( FALSE );
+            return ERROR_BUFFER_OVERFLOW;
+        }
+
+        pszEncodedString[ich++] = rgchEncodeTable[((b1 << 2) & 0x3c) | ((b2 >> 6) & 0x03)];
+        if ( ich >= cchEncodedStringSize )
+        {
+            DBG_ASSERT( FALSE );
+            return ERROR_BUFFER_OVERFLOW;
+        }
+
+        pszEncodedString[ich++] = rgchEncodeTable[b2 & 0x3f];
+        if ( ich >= cchEncodedStringSize )
+        {
+            DBG_ASSERT( FALSE );
+            return ERROR_BUFFER_OVERFLOW;
+        }
+    }
+
+    // Pad the last cluster as necessary to indicate the number of data bytes
+    // it represents.
+    switch (cbDecodedBufferSize % 3) {
+      case 0:
+        break;
+      case 1:
+        pszEncodedString[ich - 2] = '=';
+        __fallthrough;
+      case 2:
+        pszEncodedString[ich - 1] = '=';
+        break;
+    }
+
+    // Null-terminate the encoded string.
+    pszEncodedString[ich++] = '\0';
+
+    DBG_ASSERT(ich == cchEncoded);
+
+    return ERROR_SUCCESS;
+}
+
+
+DWORD
+Base64Decode(
+    __in    PCWSTR      pszEncodedString,
+    __out_opt VOID *      pDecodeBuffer,
+    __in    DWORD       cbDecodeBufferSize,
+    __out_opt DWORD *   pcbDecoded
+    )
+/*++
+
+Routine Description:
+
+    Decode a base64-encoded string.
+
+Arguments:
+
+    pszEncodedString (IN) - base64-encoded string to decode.
+    cbDecodeBufferSize (IN) - size in bytes of the decode buffer.
+    pbDecodeBuffer (OUT) - holds the decoded data.
+    pcbDecoded (OUT) - number of data bytes in the decoded data (if success or
+        STATUS_BUFFER_TOO_SMALL).
+
+Return Values:
+
+    0 - success.
+    E_OUTOFMEMORY
+    E_INVALIDARG
+
+--*/
+{
+#define NA (255)
+#define DECODE(x) (((ULONG)(x) < sizeof(rgbDecodeTable)) ? rgbDecodeTable[x] : NA)
+
+    static BYTE rgbDecodeTable[128] = {
+       NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,  // 0-15
+       NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,  // 16-31
+       NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, 62, NA, NA, NA, 63,  // 32-47
+       52, 53, 54, 55, 56, 57, 58, 59, 60, 61, NA, NA, NA,  0, NA, NA,  // 48-63
+       NA,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,  // 64-79
+       15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, NA, NA, NA, NA, NA,  // 80-95
+       NA, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,  // 96-111
+       41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, NA, NA, NA, NA, NA,  // 112-127
+    };
+
+    DWORD   cbDecoded;
+    DWORD   cchEncodedSize;
+    DWORD   ich;
+    DWORD   ib;
+    BYTE    b0, b1, b2, b3;
+    BYTE *  pbDecodeBuffer = (BYTE *) pDecodeBuffer;
+
+    cchEncodedSize = (DWORD)wcslen(pszEncodedString);
+    if (NULL != pcbDecoded) {
+        *pcbDecoded = 0;
+    }
+
+    if ((0 == cchEncodedSize) || (0 != (cchEncodedSize % 4))) {
+        // Input string is not sized correctly to be base64.
+        return ERROR_INVALID_PARAMETER;
+    }
+
+    // Calculate decoded buffer size.
+    cbDecoded = (cchEncodedSize + 3) / 4 * 3;
+    if (pszEncodedString[cchEncodedSize-1] == '=') {
+        if (pszEncodedString[cchEncodedSize-2] == '=') {
+            // Only one data byte is encoded in the last cluster.
+            cbDecoded -= 2;
+        }
+        else {
+            // Only two data bytes are encoded in the last cluster.
+            cbDecoded -= 1;
+        }
+    }
+
+    if (NULL != pcbDecoded) {
+        *pcbDecoded = cbDecoded;
+    }
+
+    if (cbDecodeBufferSize == 0 && pDecodeBuffer == NULL) {
+        return ERROR_SUCCESS;
+    }
+
+    if (cbDecoded > cbDecodeBufferSize) {
+        // Supplied buffer is too small.
+        return ERROR_INSUFFICIENT_BUFFER;
+    }
+
+    // Decode each four-byte cluster into the corresponding three data bytes.
+    ich = ib = 0;
+    while (ich < cchEncodedSize) {
+        b0 = DECODE(pszEncodedString[ich]); ich++;
+        b1 = DECODE(pszEncodedString[ich]); ich++;
+        b2 = DECODE(pszEncodedString[ich]); ich++;
+        b3 = DECODE(pszEncodedString[ich]); ich++;
+
+        if ((NA == b0) || (NA == b1) || (NA == b2) || (NA == b3)) {
+            // Contents of input string are not base64.
+            return ERROR_INVALID_PARAMETER;
+        }
+
+        pbDecodeBuffer[ib++] = (b0 << 2) | (b1 >> 4);
+
+        if (ib < cbDecoded) {
+            pbDecodeBuffer[ib++] = (b1 << 4) | (b2 >> 2);
+
+            if (ib < cbDecoded) {
+                pbDecodeBuffer[ib++] = (b2 << 6) | b3;
+            }
+        }
+    }
+
+    DBG_ASSERT(ib == cbDecoded);
+
+    return ERROR_SUCCESS;
+}
+
+
+DWORD
+Base64Encode(
+    __in_bcount(cbDecodedBufferSize)    VOID *  pDecodedBuffer,
+    IN      DWORD       cbDecodedBufferSize,
+    __out_ecount_opt(cchEncodedStringSize) PSTR     pszEncodedString,
+    IN      DWORD       cchEncodedStringSize,
+    __out_opt DWORD *   pcchEncoded
+    )
+/*++
+
+Routine Description:
+
+    Decode a base64-encoded string.
+
+Arguments:
+
+    pDecodedBuffer (IN) - buffer to encode.
+    cbDecodedBufferSize (IN) - size of buffer to encode.
+    cchEncodedStringSize (IN) - size of the buffer for the encoded string.
+    pszEncodedString (OUT) = the encoded string.
+    pcchEncoded (OUT) - size in characters of the encoded string.
+
+Return Values:
+
+    0 - success.
+    E_OUTOFMEMORY
+
+--*/
+{
+    static CHAR rgchEncodeTable[64] = {
+        'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
+        'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
+        'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
+        'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
+        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
+    };
+
+    DWORD   ib;
+    DWORD   ich;
+    DWORD   cchEncoded;
+    BYTE    b0, b1, b2;
+    BYTE *  pbDecodedBuffer = (BYTE *) pDecodedBuffer;
+
+    // Calculate encoded string size.
+    cchEncoded = 1 + (cbDecodedBufferSize + 2) / 3 * 4;
+
+    if (NULL != pcchEncoded) {
+        *pcchEncoded = cchEncoded;
+    }
+
+    if (cchEncodedStringSize == 0 && pszEncodedString == NULL) {
+        return ERROR_SUCCESS;
+    }
+
+    if (cchEncodedStringSize < cchEncoded) {
+        // Given buffer is too small to hold encoded string.
+        return ERROR_INSUFFICIENT_BUFFER;
+    }
+
+    // Encode data byte triplets into four-byte clusters.
+    ib = ich = 0;
+    while (ib < cbDecodedBufferSize) {
+        b0 = pbDecodedBuffer[ib++];
+        b1 = (ib < cbDecodedBufferSize) ? pbDecodedBuffer[ib++] : 0;
+        b2 = (ib < cbDecodedBufferSize) ? pbDecodedBuffer[ib++] : 0;
+
+        //
+        // The checks below for buffer overflow seems redundant to me.
+        // But it's the only way I can find to keep OACR quiet so it
+        // will have to do.
+        //
+
+        pszEncodedString[ich++] = rgchEncodeTable[b0 >> 2];
+        if ( ich >= cchEncodedStringSize )
+        {
+            DBG_ASSERT( FALSE );
+            return ERROR_BUFFER_OVERFLOW;
+        }
+
+        pszEncodedString[ich++] = rgchEncodeTable[((b0 << 4) & 0x30) | ((b1 >> 4) & 0x0f)];
+        if ( ich >= cchEncodedStringSize )
+        {
+            DBG_ASSERT( FALSE );
+            return ERROR_BUFFER_OVERFLOW;
+        }
+
+        pszEncodedString[ich++] = rgchEncodeTable[((b1 << 2) & 0x3c) | ((b2 >> 6) & 0x03)];
+        if ( ich >= cchEncodedStringSize )
+        {
+            DBG_ASSERT( FALSE );
+            return ERROR_BUFFER_OVERFLOW;
+        }
+
+        pszEncodedString[ich++] = rgchEncodeTable[b2 & 0x3f];
+        if ( ich >= cchEncodedStringSize )
+        {
+            DBG_ASSERT( FALSE );
+            return ERROR_BUFFER_OVERFLOW;
+        }
+    }
+
+    // Pad the last cluster as necessary to indicate the number of data bytes
+    // it represents.
+    switch (cbDecodedBufferSize % 3) {
+      case 0:
+        break;
+      case 1:
+        pszEncodedString[ich - 2] = '=';
+        __fallthrough;
+      case 2:
+        pszEncodedString[ich - 1] = '=';
+        break;
+    }
+
+    // Null-terminate the encoded string.
+    pszEncodedString[ich++] = '\0';
+
+    DBG_ASSERT(ich == cchEncoded);
+
+    return ERROR_SUCCESS;
+}
+
+
+DWORD
+Base64Decode(
+    __in    PCSTR       pszEncodedString,
+    __out_opt   VOID *      pDecodeBuffer,
+    __in    DWORD       cbDecodeBufferSize,
+    __out_opt DWORD *   pcbDecoded
+    )
+/*++
+
+Routine Description:
+
+    Decode a base64-encoded string.
+
+Arguments:
+
+    pszEncodedString (IN) - base64-encoded string to decode.
+    cbDecodeBufferSize (IN) - size in bytes of the decode buffer.
+    pbDecodeBuffer (OUT) - holds the decoded data.
+    pcbDecoded (OUT) - number of data bytes in the decoded data (if success or
+        STATUS_BUFFER_TOO_SMALL).
+
+Return Values:
+
+    0 - success.
+    E_OUTOFMEMORY
+    E_INVALIDARG
+
+--*/
+{
+#define NA (255)
+#define DECODE(x) (((ULONG)(x) < sizeof(rgbDecodeTable)) ? rgbDecodeTable[x] : NA)
+
+    static BYTE rgbDecodeTable[128] = {
+       NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,  // 0-15
+       NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,  // 16-31
+       NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, 62, NA, NA, NA, 63,  // 32-47
+       52, 53, 54, 55, 56, 57, 58, 59, 60, 61, NA, NA, NA,  0, NA, NA,  // 48-63
+       NA,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,  // 64-79
+       15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, NA, NA, NA, NA, NA,  // 80-95
+       NA, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,  // 96-111
+       41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, NA, NA, NA, NA, NA,  // 112-127
+    };
+
+    DWORD   cbDecoded;
+    DWORD   cchEncodedSize;
+    DWORD   ich;
+    DWORD   ib;
+    BYTE    b0, b1, b2, b3;
+    BYTE *  pbDecodeBuffer = (BYTE *) pDecodeBuffer;
+
+    cchEncodedSize = (DWORD)strlen(pszEncodedString);
+    if (NULL != pcbDecoded) {
+        *pcbDecoded = 0;
+    }
+
+    if ((0 == cchEncodedSize) || (0 != (cchEncodedSize % 4))) {
+        // Input string is not sized correctly to be base64.
+        return ERROR_INVALID_PARAMETER;
+    }
+
+    // Calculate decoded buffer size.
+    cbDecoded = (cchEncodedSize + 3) / 4 * 3;
+    if (pszEncodedString[cchEncodedSize-1] == '=') {
+        if (pszEncodedString[cchEncodedSize-2] == '=') {
+            // Only one data byte is encoded in the last cluster.
+            cbDecoded -= 2;
+        }
+        else {
+            // Only two data bytes are encoded in the last cluster.
+            cbDecoded -= 1;
+        }
+    }
+
+    if (NULL != pcbDecoded) {
+        *pcbDecoded = cbDecoded;
+    }
+
+    if (cbDecodeBufferSize == 0 && pDecodeBuffer == NULL) {
+        return ERROR_SUCCESS;
+    }
+
+    if (cbDecoded > cbDecodeBufferSize) {
+        // Supplied buffer is too small.
+        return ERROR_INSUFFICIENT_BUFFER;
+    }
+
+    // Decode each four-byte cluster into the corresponding three data bytes.
+    ich = ib = 0;
+    while (ich < cchEncodedSize) {
+        b0 = DECODE(pszEncodedString[ich]); ich++;
+        b1 = DECODE(pszEncodedString[ich]); ich++;
+        b2 = DECODE(pszEncodedString[ich]); ich++;
+        b3 = DECODE(pszEncodedString[ich]); ich++;
+
+        if ((NA == b0) || (NA == b1) || (NA == b2) || (NA == b3)) {
+            // Contents of input string are not base64.
+            return ERROR_INVALID_PARAMETER;
+        }
+
+        pbDecodeBuffer[ib++] = (b0 << 2) | (b1 >> 4);
+
+        if (ib < cbDecoded) {
+            pbDecodeBuffer[ib++] = (b1 << 4) | (b2 >> 2);
+
+            if (ib < cbDecoded) {
+                pbDecodeBuffer[ib++] = (b2 << 6) | b3;
+            }
+        }
+    }
+
+    DBG_ASSERT(ib == cbDecoded);
+
+    return ERROR_SUCCESS;
+}
+
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/IISLib/base64.h b/src/IISIntegration/src/AspNetCoreModuleV2/IISLib/base64.h
new file mode 100644
index 0000000000000000000000000000000000000000..469b074d73cd6e5b5ad5341b9f6dc7c922aecd25
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/IISLib/base64.h
@@ -0,0 +1,42 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#ifndef _BASE64_H_
+#define _BASE64_H_
+
+DWORD
+Base64Encode(
+    __in_bcount( cbDecodedBufferSize ) VOID *   pDecodedBuffer,
+    IN      DWORD                               cbDecodedBufferSize,
+    __out_ecount_opt( cchEncodedStringSize ) PWSTR  pszEncodedString,
+    IN      DWORD                               cchEncodedStringSize,
+    __out_opt DWORD *                           pcchEncoded
+    );
+
+DWORD
+Base64Decode(
+    __in    PCWSTR                              pszEncodedString,
+    __out_opt   VOID *                              pDecodeBuffer,
+    __in    DWORD                               cbDecodeBufferSize,
+    __out_opt DWORD *                           pcbDecoded
+    );
+
+DWORD
+Base64Encode(
+    __in_bcount( cbDecodedBufferSize ) VOID *   pDecodedBuffer,
+    IN      DWORD                               cbDecodedBufferSize,
+    __out_ecount_opt( cchEncodedStringSize ) PSTR   pszEncodedString,
+    IN      DWORD                               cchEncodedStringSize,
+    __out_opt DWORD *                           pcchEncoded
+    );
+
+DWORD
+Base64Decode(
+    __in    PCSTR                               pszEncodedString,
+    __out_opt   VOID *                              pDecodeBuffer,
+    __in    DWORD                               cbDecodeBufferSize,
+    __out_opt DWORD *                           pcbDecoded
+    );
+
+#endif // _BASE64_HXX_
+
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/IISLib/buffer.h b/src/IISIntegration/src/AspNetCoreModuleV2/IISLib/buffer.h
new file mode 100644
index 0000000000000000000000000000000000000000..1d68155387beb1c924ca53ae18f33534da80be2b
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/IISLib/buffer.h
@@ -0,0 +1,271 @@
+// 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 <crtdbg.h>
+
+
+//
+// BUFFER_T class shouldn't be used directly. Use BUFFER specialization class instead.
+// The only BUFFER_T partners are STRU and STRA classes.
+// BUFFER_T cannot hold other but primitive types since it doesn't call
+// constructor and destructor.
+//
+// Note: Size is in bytes.
+//
+template<typename T, DWORD LENGTH>
+class BUFFER_T
+{
+public:
+
+    BUFFER_T()
+      : m_cbBuffer( sizeof(m_rgBuffer) ),
+        m_fHeapAllocated( false ),
+        m_pBuffer(m_rgBuffer)
+    /*++
+        Description:
+
+            Default constructor where the inline buffer is used.
+
+        Arguments:
+
+            None.
+
+        Returns:
+            
+            None.
+
+    --*/    
+    {
+    }
+
+    BUFFER_T(
+        __inout_bcount(cbInit) T* pbInit, 
+        __in DWORD cbInit
+    ) : m_pBuffer( pbInit ),
+        m_cbBuffer( cbInit ),
+        m_fHeapAllocated( false )
+    /*++
+        Description:
+
+            Instantiate BUFFER, initially using pbInit as buffer
+            This is useful for stack-buffers and inline-buffer class members 
+            (see STACK_BUFFER and INLINE_BUFFER_INIT below)
+
+            BUFFER does not free pbInit.
+
+        Arguments:
+
+            pbInit - Initial buffer to use.
+            cbInit - Size of pbInit in bytes (not in elements).
+
+        Returns:
+            
+            None.
+
+    --*/
+    {
+        _ASSERTE( NULL != pbInit );
+        _ASSERTE( cbInit > 0 );
+    }
+
+    ~BUFFER_T()
+    {
+        if( IsHeapAllocated() )
+        {
+            _ASSERTE( NULL != m_pBuffer );
+            HeapFree( GetProcessHeap(), 0, m_pBuffer );
+            m_pBuffer = NULL;
+            m_cbBuffer = 0;
+            m_fHeapAllocated = false;
+        }
+    }
+
+    T*
+    QueryPtr(
+        VOID
+    ) const
+    {
+        //
+        // Return pointer to data buffer.
+        //
+        return m_pBuffer;
+    }
+
+    DWORD 
+    QuerySize(
+        VOID
+    ) const  
+    { 
+        //
+        // Return number of bytes.
+        //
+        return m_cbBuffer; 
+    }
+
+    __success(return == true)
+    bool 
+    Resize(
+        const SIZE_T   cbNewSize,
+        const bool     fZeroMemoryBeyondOldSize = false
+    )
+    /*++
+        Description:
+
+            Resizes the buffer.
+
+        Arguments:
+
+            cbNewSize   - Size in bytes to grow to.
+            fZeroMemoryBeyondOldSize 
+                        - Whether to zero the region of memory of the
+                          new buffer beyond the original size.
+
+        Returns:
+            
+            TRUE on success, FALSE on failure.
+
+    --*/
+    {
+        PVOID pNewMem;
+
+        if ( cbNewSize <= m_cbBuffer )
+        {
+            return true;
+        }
+
+        if ( cbNewSize > MAXDWORD )
+        {
+            SetLastError( ERROR_INVALID_PARAMETER );
+            return false;
+        }
+
+        DWORD dwHeapAllocFlags = fZeroMemoryBeyondOldSize ? HEAP_ZERO_MEMORY : 0;
+
+        if( IsHeapAllocated() )
+        {
+            pNewMem = HeapReAlloc( GetProcessHeap(), dwHeapAllocFlags, m_pBuffer, cbNewSize );
+        }
+        else
+        {
+            pNewMem = HeapAlloc( GetProcessHeap(), dwHeapAllocFlags, cbNewSize );
+        }
+
+        if( pNewMem == NULL )
+        {
+            SetLastError( ERROR_NOT_ENOUGH_MEMORY );
+            return false;
+        }
+
+        if( !IsHeapAllocated() ) 
+        {
+            //
+            // First time this block is allocated. Copy over old contents.
+            //
+            memcpy_s( pNewMem, static_cast<DWORD>(cbNewSize), m_pBuffer, m_cbBuffer );
+            m_fHeapAllocated = true;
+        }
+
+        m_pBuffer = reinterpret_cast<T*>(pNewMem);
+        m_cbBuffer = static_cast<DWORD>(cbNewSize);
+
+        _ASSERTE( m_pBuffer != NULL );
+
+        return true;
+    }
+
+private:
+
+    bool 
+    IsHeapAllocated(
+        VOID
+    ) const 
+    {   
+        return m_fHeapAllocated; 
+    }
+
+    //
+    // The default inline buffer.
+    // This member should be at the beginning for alignment purposes.
+    //
+    T       m_rgBuffer[LENGTH];
+    
+    //
+    // Is m_pBuffer dynamically allocated?
+    //
+    bool    m_fHeapAllocated;
+
+    //
+    // Size of the buffer as requested by client in bytes.
+    //
+    DWORD   m_cbBuffer;
+
+    //
+    // Pointer to buffer.
+    //
+    __field_bcount_full(m_cbBuffer)
+    T*      m_pBuffer;
+};
+
+//
+// Resizes the buffer by 2 if the ideal size is bigger
+// than the buffer length. That give us lg(n) allocations.
+//
+// Use template inferring like:
+//
+//   BUFFER buff;
+//   hr = ResizeBufferByTwo(buff, 100);
+//
+template<typename T, DWORD LENGTH>
+HRESULT
+ResizeBufferByTwo(
+    BUFFER_T<T,LENGTH>& Buffer,
+    SIZE_T              cbIdealSize,
+    bool                fZeroMemoryBeyondOldSize = false
+)
+{
+    if (cbIdealSize > Buffer.QuerySize())
+    {
+        if (!Buffer.Resize(max(cbIdealSize, static_cast<SIZE_T>(Buffer.QuerySize() * 2)),
+                           fZeroMemoryBeyondOldSize))
+        {
+            return E_OUTOFMEMORY;
+        }
+    }
+    return S_OK;
+}
+    
+
+//
+//
+// Lots of code uses BUFFER class to store a bunch of different
+// structures, so m_rgBuffer needs to be 8 byte aligned when it is used
+// as an opaque buffer.
+//
+#define INLINED_BUFFER_LEN 32
+typedef BUFFER_T<BYTE, INLINED_BUFFER_LEN> BUFFER;
+
+//
+// Assumption of macros below for pointer alignment purposes
+//
+C_ASSERT( sizeof(VOID*) <= sizeof(ULONGLONG) );
+
+//
+//  Declare a BUFFER that will use stack memory of <size>
+//  bytes. If the buffer overflows then a heap buffer will be allocated.
+//
+#define STACK_BUFFER( _name, _size )    \
+    ULONGLONG   __aqw##_name[ ( ( (_size) + sizeof(ULONGLONG) - 1 ) / sizeof(ULONGLONG) ) ]; \
+    BUFFER      _name( (BYTE*)__aqw##_name, sizeof(__aqw##_name) )
+
+//
+// Macros for declaring and initializing a BUFFER that will use inline memory
+// of <size> bytes as a member of an object.
+//
+#define INLINE_BUFFER( _name, _size )   \
+    ULONGLONG   __aqw##_name[ ( ( (_size) + sizeof(ULONGLONG) - 1 ) / sizeof(ULONGLONG) ) ]; \
+    BUFFER      _name;
+
+#define INLINE_BUFFER_INIT( _name )     \
+    _name( (BYTE*)__aqw##_name, sizeof( __aqw##_name ) )
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/IISLib/datetime.h b/src/IISIntegration/src/AspNetCoreModuleV2/IISLib/datetime.h
new file mode 100644
index 0000000000000000000000000000000000000000..fd09b7a6a06b1aac51c3054fdc3c6e3e9362b125
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/IISLib/datetime.h
@@ -0,0 +1,14 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#ifndef _DATETIME_H_
+#define _DATETIME_H_
+
+BOOL
+StringTimeToFileTime(
+    PCSTR           pszTime,
+    ULONGLONG *     pulTime
+);
+
+#endif
+
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/IISLib/dbgutil.h b/src/IISIntegration/src/AspNetCoreModuleV2/IISLib/dbgutil.h
new file mode 100644
index 0000000000000000000000000000000000000000..45c26777a91cfc354f1db8e1d3493c6aad1b24b5
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/IISLib/dbgutil.h
@@ -0,0 +1,102 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#ifndef _DBGUTIL_H_
+#define _DBGUTIL_H_
+
+#include <crtdbg.h>
+
+//
+// TODO 
+//      Using _CrtDbg implementation. If hooking is desired
+//      wrappers should be provided here so that we can reimplement
+//      if neecessary.
+// 
+//      IF_DEBUG/DEBUG FLAGS
+//
+//      registry configuration
+//
+
+//
+// Debug error levels for DEBUG_FLAGS_VAR.
+//
+
+#define DEBUG_FLAG_INFO     0x00000001
+#define DEBUG_FLAG_WARN     0x00000002
+#define DEBUG_FLAG_ERROR    0x00000004
+
+//
+// Predefined error level values. These are backwards from the
+// windows definitions.
+//
+
+#define DEBUG_FLAGS_INFO    (DEBUG_FLAG_ERROR | DEBUG_FLAG_WARN | DEBUG_FLAG_INFO)
+#define DEBUG_FLAGS_WARN    (DEBUG_FLAG_ERROR | DEBUG_FLAG_WARN)
+#define DEBUG_FLAGS_ERROR   (DEBUG_FLAG_ERROR)
+#define DEBUG_FLAGS_ANY     (DEBUG_FLAG_INFO | DEBUG_FLAG_WARN | DEBUG_FLAG_ERROR)
+
+//
+// Global variables to control tracing. Generally per module
+//
+
+#ifndef DEBUG_FLAGS_VAR
+#define DEBUG_FLAGS_VAR g_dwDebugFlags
+#endif
+
+#ifndef DEBUG_LABEL_VAR
+#define DEBUG_LABEL_VAR g_szDebugLabel
+#endif
+
+extern PCSTR DEBUG_LABEL_VAR;
+extern DWORD DEBUG_FLAGS_VAR;
+
+//
+// Module should make this declaration globally.
+//
+
+#define DECLARE_DEBUG_PRINT_OBJECT( _pszLabel_ )                \
+    PCSTR DEBUG_LABEL_VAR = _pszLabel_;                 \
+    DWORD DEBUG_FLAGS_VAR = DEBUG_FLAGS_ANY;            \
+
+#define DECLARE_DEBUG_PRINT_OBJECT2( _pszLabel_, _dwLevel_ )    \
+    PCSTR DEBUG_LABEL_VAR = _pszLabel_;                 \
+    DWORD DEBUG_FLAGS_VAR = _dwLevel_;                  \
+
+//
+// This doesn't do anything now. Should be safe to call in dll main.
+//
+
+#define CREATE_DEBUG_PRINT_OBJECT
+
+//
+// Trace macros
+//
+
+#define DBG_CONTEXT     _CRT_WARN, __FILE__, __LINE__, DEBUG_LABEL_VAR
+
+#ifdef DEBUG
+#define DBGINFO(args)   \
+{if (DEBUG_FLAGS_VAR & DEBUG_FLAG_INFO) { _CrtDbgReport args; }}
+#define DBGWARN(args)   \
+{if (DEBUG_FLAGS_VAR & DEBUG_FLAG_WARN) { _CrtDbgReport args; }}
+#define DBGERROR(args)  \
+{if (DEBUG_FLAGS_VAR & DEBUG_FLAG_ERROR) { _CrtDbgReport args; }}
+#else
+#define DBGINFO
+#define DBGWARN
+#define DBGERROR
+#endif
+
+#define DBGPRINTF           DBGINFO
+
+//
+// Simple error traces
+//
+
+#define DBGERROR_HR( _hr_ ) \
+    DBGERROR((DBG_CONTEXT, "hr=0x%x\n", _hr_))
+
+#define DBGERROR_STATUS( _status_ ) \
+    DBGERROR((DBG_CONTEXT, "status=%d\n", _status_))
+
+#endif
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/IISLib/hashfn.h b/src/IISIntegration/src/AspNetCoreModuleV2/IISLib/hashfn.h
new file mode 100644
index 0000000000000000000000000000000000000000..a7bfeda2cfade8e065c99a404f2b609032e92d2b
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/IISLib/hashfn.h
@@ -0,0 +1,325 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#ifndef __HASHFN_H__
+#define __HASHFN_H__
+
+
+// Produce a scrambled, randomish number in the range 0 to RANDOM_PRIME-1.
+// Applying this to the results of the other hash functions is likely to
+// produce a much better distribution, especially for the identity hash
+// functions such as Hash(char c), where records will tend to cluster at
+// the low end of the hashtable otherwise.  LKRhash applies this internally
+// to all hash signatures for exactly this reason.
+
+inline DWORD
+HashScramble(DWORD dwHash)
+{
+    // Here are 10 primes slightly greater than 10^9
+    //  1000000007, 1000000009, 1000000021, 1000000033, 1000000087,
+    //  1000000093, 1000000097, 1000000103, 1000000123, 1000000181.
+
+    // default value for "scrambling constant"
+    const DWORD RANDOM_CONSTANT = 314159269UL;
+    // large prime number, also used for scrambling
+    const DWORD RANDOM_PRIME =   1000000007UL;
+
+    return (RANDOM_CONSTANT * dwHash) % RANDOM_PRIME ;
+}
+
+
+// Faster scrambling function suggested by Eric Jacobsen
+
+inline DWORD
+HashRandomizeBits(DWORD dw)
+{
+	return (((dw * 1103515245 + 12345) >> 16)
+            | ((dw * 69069 + 1) & 0xffff0000));
+}
+
+
+// Small prime number used as a multiplier in the supplied hash functions
+const DWORD HASH_MULTIPLIER = 101;
+
+#undef HASH_SHIFT_MULTIPLY
+
+#ifdef HASH_SHIFT_MULTIPLY
+# define HASH_MULTIPLY(dw)   (((dw) << 7) - (dw))
+#else
+# define HASH_MULTIPLY(dw)   ((dw) * HASH_MULTIPLIER)
+#endif
+
+// Fast, simple hash function that tends to give a good distribution.
+// Apply HashScramble to the result if you're using this for something
+// other than LKRhash.
+
+inline DWORD
+HashString(
+    const char* psz,
+    DWORD       dwHash = 0)
+{
+    // force compiler to use unsigned arithmetic
+    const unsigned char* upsz = (const unsigned char*) psz;
+
+    for ( ; *upsz; ++upsz)
+        dwHash = HASH_MULTIPLY(dwHash) + *upsz;
+
+    return dwHash;
+}
+
+inline DWORD
+HashString(
+    __in_ecount(cch) const char* psz,
+    __in DWORD cch,
+    __in DWORD dwHash
+)
+{
+    // force compiler to use unsigned arithmetic
+    const unsigned char* upsz = (const unsigned char*) psz;
+
+    for (DWORD Index = 0; 
+         Index < cch;
+         ++Index, ++upsz)
+    {
+        dwHash = HASH_MULTIPLY(dwHash) + *upsz;
+    }
+
+    return dwHash;
+}
+
+
+// Unicode version of above
+
+inline DWORD
+HashString(
+    const wchar_t* pwsz,
+    DWORD          dwHash = 0)
+{
+    for (  ;  *pwsz;  ++pwsz)
+        dwHash = HASH_MULTIPLY(dwHash) + *pwsz;
+
+    return dwHash;
+}
+
+// Based on length of the string instead of null-terminating character
+
+inline DWORD
+HashString(
+    __in_ecount(cch) const wchar_t* pwsz,
+    __in DWORD          cch,
+    __in DWORD          dwHash
+)
+{
+    for (DWORD Index = 0; 
+         Index < cch;
+         ++Index, ++pwsz)
+    {
+        dwHash = HASH_MULTIPLY(dwHash) + *pwsz;
+    }
+
+    return dwHash;
+}
+
+
+// Quick-'n'-dirty case-insensitive string hash function.
+// Make sure that you follow up with _stricmp or _mbsicmp.  You should
+// also cache the length of strings and check those first.  Caching
+// an uppercase version of a string can help too.
+// Again, apply HashScramble to the result if using with something other
+// than LKRhash.
+// Note: this is not really adequate for MBCS strings.
+
+inline DWORD
+HashStringNoCase(
+    const char* psz,
+    DWORD       dwHash = 0)
+{
+    const unsigned char* upsz = (const unsigned char*) psz;
+
+    for (  ;  *upsz;  ++upsz)
+        dwHash = HASH_MULTIPLY(dwHash)
+                    + (*upsz & 0xDF);  // strip off lowercase bit
+
+    return dwHash;
+}
+
+inline DWORD
+HashStringNoCase(
+    __in_ecount(cch)
+    const char* psz,
+    SIZE_T      cch,
+    DWORD       dwHash)
+{
+    const unsigned char* upsz = (const unsigned char*) psz;
+
+    for (SIZE_T Index = 0;
+         Index < cch;
+         ++Index, ++upsz)
+    {
+        dwHash = HASH_MULTIPLY(dwHash)
+                    + (*upsz & 0xDF);  // strip off lowercase bit
+    }
+    return dwHash;
+}
+
+
+// Unicode version of above
+
+inline DWORD
+HashStringNoCase(
+    const wchar_t* pwsz,
+    DWORD          dwHash = 0)
+{
+    for (  ;  *pwsz;  ++pwsz)
+        dwHash = HASH_MULTIPLY(dwHash) + (*pwsz & 0xFFDF);
+
+    return dwHash;
+}
+
+// Unicode version of above with length
+
+inline DWORD
+HashStringNoCase(
+    __in_ecount(cch)
+    const wchar_t* pwsz,
+    SIZE_T         cch,
+    DWORD          dwHash)
+{
+    for (SIZE_T Index = 0;
+         Index < cch;
+         ++Index, ++pwsz)
+    {
+        dwHash = HASH_MULTIPLY(dwHash) + (*pwsz & 0xFFDF);
+    }
+    return dwHash;
+}
+
+
+// HashBlob returns the hash of a blob of arbitrary binary data.
+// 
+// Warning: HashBlob is generally not the right way to hash a class object.
+// Consider:
+//     class CFoo {
+//     public:
+//         char   m_ch;
+//         double m_d;
+//         char*  m_psz;
+//     };
+// 
+//     inline DWORD Hash(const CFoo& rFoo)
+//     { return HashBlob(&rFoo, sizeof(CFoo)); }
+//
+// This is the wrong way to hash a CFoo for two reasons: (a) there will be
+// a 7-byte gap between m_ch and m_d imposed by the alignment restrictions
+// of doubles, which will be filled with random data (usually non-zero for
+// stack variables), and (b) it hashes the address (rather than the
+// contents) of the string m_psz.  Similarly,
+// 
+//     bool operator==(const CFoo& rFoo1, const CFoo& rFoo2)
+//     { return memcmp(&rFoo1, &rFoo2, sizeof(CFoo)) == 0; }
+//
+// does the wrong thing.  Much better to do this:
+//
+//     DWORD Hash(const CFoo& rFoo)
+//     {
+//         return HashString(rFoo.m_psz,
+//                           HASH_MULTIPLIER * Hash(rFoo.m_ch)
+//                              + Hash(rFoo.m_d));
+//     }
+//
+// Again, apply HashScramble if using with something other than LKRhash.
+
+inline DWORD
+HashBlob(
+    const void* pv,
+    size_t      cb,
+    DWORD       dwHash = 0)
+{
+    const BYTE * pb = static_cast<const BYTE *>(pv);
+
+    while (cb-- > 0)
+        dwHash = HASH_MULTIPLY(dwHash) + *pb++;
+
+    return dwHash;
+}
+
+
+
+//
+// Overloaded hash functions for all the major builtin types.
+// Again, apply HashScramble to result if using with something other than
+// LKRhash.
+//
+
+inline DWORD Hash(const char* psz)
+{ return HashString(psz); }
+
+inline DWORD Hash(const unsigned char* pusz)
+{ return HashString(reinterpret_cast<const char*>(pusz)); }
+
+inline DWORD Hash(const signed char* pssz)
+{ return HashString(reinterpret_cast<const char*>(pssz)); }
+
+inline DWORD Hash(const wchar_t* pwsz)
+{ return HashString(pwsz); }
+
+inline DWORD
+Hash(
+    const GUID* pguid,
+    DWORD       dwHash = 0)
+{
+    
+    return * reinterpret_cast<const DWORD *>(const_cast<GUID*>(pguid)) + dwHash;
+}
+
+// Identity hash functions: scalar values map to themselves
+inline DWORD Hash(char c)
+{ return c; }
+
+inline DWORD Hash(unsigned char uc)
+{ return uc; }
+
+inline DWORD Hash(signed char sc)
+{ return sc; }
+
+inline DWORD Hash(short sh)
+{ return sh; }
+
+inline DWORD Hash(unsigned short ush)
+{ return ush; }
+
+inline DWORD Hash(int i)
+{ return i; }
+
+inline DWORD Hash(unsigned int u)
+{ return u; }
+
+inline DWORD Hash(long l)
+{ return l; }
+
+inline DWORD Hash(unsigned long ul)
+{ return ul; }
+
+inline DWORD Hash(float f)
+{
+    // be careful of rounding errors when computing keys
+    union {
+        float f;
+        DWORD dw;
+    } u;
+    u.f = f;
+    return u.dw;
+}
+
+inline DWORD Hash(double dbl)
+{
+    // be careful of rounding errors when computing keys
+    union {
+        double dbl;
+        DWORD  dw[2];
+    } u;
+    u.dbl = dbl;
+    return u.dw[0] * HASH_MULTIPLIER + u.dw[1];
+}
+
+#endif // __HASHFN_H__
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/IISLib/hashtable.h b/src/IISIntegration/src/AspNetCoreModuleV2/IISLib/hashtable.h
new file mode 100644
index 0000000000000000000000000000000000000000..9319e5643d34c36c1ebb4989b5eb7adef8436ba4
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/IISLib/hashtable.h
@@ -0,0 +1,666 @@
+// 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 <crtdbg.h>
+#include "rwlock.h"
+#include "prime.h"
+
+template <class _Record>
+class HASH_NODE
+{
+    template <class _Record, class _Key>
+    friend class HASH_TABLE;
+
+    HASH_NODE(
+        _Record *       pRecord,
+        DWORD           dwHash
+    ) : _pNext (NULL),
+        _pRecord (pRecord),
+        _dwHash (dwHash)
+    {}
+
+    ~HASH_NODE()
+    {
+        _ASSERTE(_pRecord == NULL);
+    }
+
+ private:
+    // Next node in the hash table look-aside
+    HASH_NODE<_Record> *_pNext;
+
+    // actual record
+    _Record *           _pRecord;
+
+    // hash value
+    DWORD               _dwHash;
+};
+
+template <class _Record, class _Key>
+class HASH_TABLE
+{
+protected:
+    typedef BOOL
+    (PFN_DELETE_IF)(
+        _Record *           pRecord,
+        PVOID               pvContext
+    );
+
+    typedef VOID
+    (PFN_APPLY)(
+        _Record *           pRecord,
+        PVOID               pvContext
+    );
+
+public:
+    HASH_TABLE(
+        VOID
+    )
+      : _ppBuckets( NULL ),
+        _nBuckets( 0 ),
+        _nItems( 0 )
+    {
+    }
+
+    virtual
+    ~HASH_TABLE();
+
+    virtual
+    VOID
+    ReferenceRecord(
+        _Record *   pRecord
+    ) = 0;
+
+    virtual
+    VOID
+    DereferenceRecord(
+        _Record *   pRecord
+    ) = 0;
+
+    virtual
+    _Key
+    ExtractKey(
+        _Record *   pRecord
+    ) = 0;
+
+    virtual
+    DWORD
+    CalcKeyHash(
+        _Key        key
+    ) = 0;
+
+    virtual
+    BOOL
+    EqualKeys(
+        _Key        key1,
+        _Key        key2
+    ) = 0;
+
+    DWORD
+    Count(
+        VOID
+    ) const;
+
+    bool
+    IsInitialized(
+        VOID
+    ) const;
+
+    virtual
+    VOID
+    Clear();
+
+    HRESULT
+    Initialize(
+        DWORD           nBucketSize
+    );
+
+    virtual
+    VOID
+    FindKey(
+        _Key        key,
+        _Record **  ppRecord
+    );
+
+    virtual
+    HRESULT
+    InsertRecord(
+        _Record *   pRecord
+    );
+
+    virtual
+    VOID
+    DeleteKey(
+        _Key        key
+    );
+
+    virtual
+    VOID
+    DeleteIf(
+        PFN_DELETE_IF       pfnDeleteIf,
+        PVOID               pvContext
+    );
+
+    VOID
+    Apply(
+        PFN_APPLY           pfnApply,
+        PVOID               pvContext
+    );
+
+private:
+
+    __success(*ppNode != NULL && return != FALSE)
+    BOOL
+    FindNodeInternal(
+        _Key                    key,
+        DWORD                   dwHash,
+        __deref_out
+        HASH_NODE<_Record> **   ppNode,
+        __deref_opt_out
+        HASH_NODE<_Record> ***  pppPreviousNodeNextPointer = NULL
+    );
+
+    VOID
+    DeleteNode(
+        HASH_NODE<_Record> *    pNode
+    )
+    {
+        if (pNode->_pRecord != NULL)
+        {
+            DereferenceRecord(pNode->_pRecord);
+            pNode->_pRecord = NULL;
+        }
+
+        delete pNode;
+    }
+
+    VOID
+    RehashTableIfNeeded(
+        VOID
+    );
+
+    HASH_NODE<_Record> **   _ppBuckets;
+    DWORD                   _nBuckets;
+    DWORD                   _nItems;
+    //
+    // Allow to use lock object in const methods.
+    //
+    mutable
+    CWSDRWLock              _tableLock;
+};
+
+template <class _Record, class _Key>
+HRESULT
+HASH_TABLE<_Record,_Key>::Initialize(
+    DWORD   nBuckets
+)
+{
+    HRESULT hr = S_OK;
+
+    if ( nBuckets == 0 )
+    {
+        hr = E_INVALIDARG;
+        goto Failed;
+    }
+
+    if (nBuckets >= MAXDWORD/sizeof(HASH_NODE<_Record> *))
+    {
+        hr = E_INVALIDARG;
+        goto Failed;
+    }
+
+    _ASSERTE(_ppBuckets == NULL );
+    if ( _ppBuckets != NULL )
+    {
+        hr = E_INVALIDARG;
+        goto Failed;
+    }
+
+    hr = _tableLock.Init();
+    if ( FAILED( hr ) )
+    {
+        goto Failed;
+    }
+
+    _ppBuckets = (HASH_NODE<_Record> **)HeapAlloc(
+                            GetProcessHeap(),
+                            HEAP_ZERO_MEMORY,
+                            nBuckets*sizeof(HASH_NODE<_Record> *));
+    if (_ppBuckets == NULL)
+    {
+        hr = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
+        goto Failed;
+    }
+    _nBuckets = nBuckets;
+
+    return S_OK;
+
+Failed:
+
+    if (_ppBuckets)
+    {
+        HeapFree(GetProcessHeap(),
+                 0,
+                 _ppBuckets);
+        _ppBuckets = NULL;
+    }
+
+    return hr;
+}
+
+
+template <class _Record, class _Key>
+HASH_TABLE<_Record,_Key>::~HASH_TABLE()
+{
+    if (_ppBuckets == NULL)
+    {
+        return;
+    }
+
+    _ASSERTE(_nItems == 0);
+
+    HeapFree(GetProcessHeap(),
+             0,
+             _ppBuckets);
+    _ppBuckets = NULL;
+    _nBuckets = 0;
+}
+
+template< class _Record, class _Key>
+DWORD
+HASH_TABLE<_Record,_Key>::Count() const
+{
+    return _nItems;
+}
+
+template< class _Record, class _Key>
+bool
+HASH_TABLE<_Record,_Key>::IsInitialized(
+    VOID
+) const
+{
+    return _ppBuckets != NULL;
+}
+
+
+template <class _Record, class _Key>
+VOID
+HASH_TABLE<_Record,_Key>::Clear()
+{
+    HASH_NODE<_Record> *pCurrent;
+    HASH_NODE<_Record> *pNext;
+
+    // This is here in the off cases where someone instantiates a hashtable
+    // and then does an automatic "clear" before its destruction WITHOUT
+    // ever initializing it.
+    if ( ! _tableLock.QueryInited() )
+    {
+        return;
+    }
+
+    _tableLock.ExclusiveAcquire();
+
+    for (DWORD i=0; i<_nBuckets; i++)
+    {
+        pCurrent = _ppBuckets[i];
+        _ppBuckets[i] = NULL;
+        while (pCurrent != NULL)
+        {
+            pNext = pCurrent->_pNext;
+            DeleteNode(pCurrent);
+            pCurrent = pNext;
+        }
+    }
+
+    _nItems = 0;
+    _tableLock.ExclusiveRelease();
+}
+
+template <class _Record, class _Key>
+__success(*ppNode != NULL && return != FALSE)
+BOOL
+HASH_TABLE<_Record,_Key>::FindNodeInternal(
+    _Key                    key,
+    DWORD                   dwHash,
+    __deref_out
+    HASH_NODE<_Record> **   ppNode,
+    __deref_opt_out
+    HASH_NODE<_Record> ***  pppPreviousNodeNextPointer
+)
+/*++
+  Return value indicates whether the item is found
+  key, dwHash - key and hash for the node to find
+  ppNode - on successful return, the node found, on failed return, the first
+  node with hash value greater than the node to be found
+  pppPreviousNodeNextPointer - the pointer to previous node's _pNext
+
+  This routine may be called under either read or write lock
+--*/
+{
+    HASH_NODE<_Record> **ppPreviousNodeNextPointer;
+    HASH_NODE<_Record> *pNode;
+    BOOL fFound = FALSE;
+
+    ppPreviousNodeNextPointer = _ppBuckets + (dwHash % _nBuckets);
+    pNode = *ppPreviousNodeNextPointer;
+    while (pNode != NULL)
+    {
+        if (pNode->_dwHash == dwHash)
+        {
+            if (EqualKeys(key,
+                          ExtractKey(pNode->_pRecord)))
+            {
+                fFound = TRUE;
+                break;
+            }
+        }
+        else if (pNode->_dwHash > dwHash)
+        {
+            break;
+        }
+
+        ppPreviousNodeNextPointer = &(pNode->_pNext);
+        pNode = *ppPreviousNodeNextPointer;
+    }
+
+    __analysis_assume( (pNode == NULL && fFound == FALSE) ||
+                       (pNode != NULL && fFound == TRUE ) );
+    *ppNode = pNode;
+    if (pppPreviousNodeNextPointer != NULL)
+    {
+        *pppPreviousNodeNextPointer = ppPreviousNodeNextPointer;
+    }
+    return fFound;
+}
+
+template <class _Record, class _Key>
+VOID
+HASH_TABLE<_Record,_Key>::FindKey(
+    _Key                key,
+    _Record **          ppRecord
+)
+{
+    HASH_NODE<_Record> *pNode;
+
+    *ppRecord = NULL;
+
+    DWORD dwHash = CalcKeyHash(key);
+
+    _tableLock.SharedAcquire();
+
+    if (FindNodeInternal(key, dwHash, &pNode) &&
+        pNode->_pRecord != NULL)
+    {
+        ReferenceRecord(pNode->_pRecord);
+        *ppRecord = pNode->_pRecord;
+    }
+
+    _tableLock.SharedRelease();
+}
+
+template <class _Record, class _Key>
+HRESULT
+HASH_TABLE<_Record,_Key>::InsertRecord(
+    _Record *           pRecord
+)
+/*++
+  This method inserts a node for this record and also empty nodes for paths
+  in the heirarchy leading upto this path
+
+  The insert is done under only a read-lock - this is possible by keeping
+  the hashes in a bucket in increasing order and using interlocked operations
+  to actually insert the item in the hash-bucket lookaside list and the parent
+  children list
+
+  Returns HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS) if the record already exists.
+  Never leak this error to the end user because "*file* already exists" may be confusing.
+--*/
+{
+    BOOL fLocked = FALSE;
+    _Key key = ExtractKey(pRecord);
+    DWORD dwHash = CalcKeyHash(key);
+    HRESULT hr = S_OK;
+    HASH_NODE<_Record> *    pNewNode;
+    HASH_NODE<_Record> *    pNextNode;
+    HASH_NODE<_Record> **   ppPreviousNodeNextPointer;
+
+    //
+    // Ownership of pRecord is not transferred to pNewNode yet, so remember
+    // to either set it to null before deleting pNewNode or add an extra
+    // reference later - this is to make sure we do not do an extra ref/deref
+    // which users may view as getting flushed out of the hash-table
+    //
+    pNewNode = new HASH_NODE<_Record>(pRecord, dwHash);
+    if (pNewNode == NULL)
+    {
+        hr = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
+        goto Finished;
+    }
+
+    _tableLock.SharedAcquire();
+    fLocked = TRUE;
+
+    do
+    {
+        //
+        // Find the right place to add this node
+        //
+        if (FindNodeInternal(key, dwHash, &pNextNode, &ppPreviousNodeNextPointer))
+        {
+            //
+            // If node already there, return error
+            //
+            pNewNode->_pRecord = NULL;
+            DeleteNode(pNewNode);
+
+            //
+            // We should never leak this error to the end user
+            // because "file already exists" may be confusing.
+            //
+            hr = HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS);
+            goto Finished;
+        }
+
+        //
+        // If another node got inserted in between, we will have to retry
+        //
+        pNewNode->_pNext = pNextNode;
+    } while (InterlockedCompareExchangePointer((PVOID *)ppPreviousNodeNextPointer,
+                                               pNewNode,
+                                               pNextNode) != pNextNode);
+    // pass ownership of pRecord now
+    if (pRecord != NULL)
+    {
+        ReferenceRecord(pRecord);
+        pRecord = NULL;
+    }
+    InterlockedIncrement((LONG *)&_nItems);
+
+Finished:
+
+    if (fLocked)
+    {
+        _tableLock.SharedRelease();
+    }
+
+    if (SUCCEEDED(hr))
+    {
+        RehashTableIfNeeded();
+    }
+
+    return hr;
+}
+
+template <class _Record, class _Key>
+VOID
+HASH_TABLE<_Record,_Key>::DeleteKey(
+    _Key        key
+)
+{
+    HASH_NODE<_Record> *pNode;
+    HASH_NODE<_Record> **ppPreviousNodeNextPointer;
+
+    DWORD dwHash = CalcKeyHash(key);
+
+    _tableLock.ExclusiveAcquire();
+
+    if (FindNodeInternal(key, dwHash, &pNode, &ppPreviousNodeNextPointer))
+    {
+        *ppPreviousNodeNextPointer = pNode->_pNext;
+        DeleteNode(pNode);
+        _nItems--;
+    }
+
+    _tableLock.ExclusiveRelease();
+}
+
+template <class _Record, class _Key>
+VOID
+HASH_TABLE<_Record,_Key>::DeleteIf(
+    PFN_DELETE_IF               pfnDeleteIf,
+    PVOID                       pvContext
+)
+{
+    HASH_NODE<_Record> *pNode;
+    HASH_NODE<_Record> **ppPreviousNodeNextPointer;
+
+    _tableLock.ExclusiveAcquire();
+
+    for (DWORD i=0; i<_nBuckets; i++)
+    {
+        ppPreviousNodeNextPointer = _ppBuckets + i;
+        pNode = *ppPreviousNodeNextPointer;
+        while (pNode != NULL)
+        {
+            //
+            // Non empty nodes deleted based on DeleteIf, empty nodes deleted
+            // if they have no children
+            //
+            if (pfnDeleteIf(pNode->_pRecord, pvContext))
+            {
+                *ppPreviousNodeNextPointer = pNode->_pNext;
+                DeleteNode(pNode);
+                _nItems--;
+            }
+            else
+            {
+                ppPreviousNodeNextPointer = &pNode->_pNext;
+            }
+
+            pNode = *ppPreviousNodeNextPointer;
+        }
+    }
+
+    _tableLock.ExclusiveRelease();
+}
+
+template <class _Record, class _Key>
+VOID
+HASH_TABLE<_Record,_Key>::Apply(
+    PFN_APPLY                   pfnApply,
+    PVOID                       pvContext
+)
+{
+    HASH_NODE<_Record> *pNode;
+
+    _tableLock.SharedAcquire();
+
+    for (DWORD i=0; i<_nBuckets; i++)
+    {
+        pNode = _ppBuckets[i];
+        while (pNode != NULL)
+        {
+            if (pNode->_pRecord != NULL)
+            {
+                pfnApply(pNode->_pRecord, pvContext);
+            }
+
+            pNode = pNode->_pNext;
+        }
+    }
+
+    _tableLock.SharedRelease();
+}
+
+template <class _Record, class _Key>
+VOID
+HASH_TABLE<_Record,_Key>::RehashTableIfNeeded(
+    VOID
+)
+{
+    HASH_NODE<_Record> **ppBuckets;
+    DWORD nBuckets;
+    HASH_NODE<_Record> *pNode;
+    HASH_NODE<_Record> *pNextNode;
+    HASH_NODE<_Record> **ppNextPointer;
+    HASH_NODE<_Record> *pNewNextNode;
+    DWORD               nNewBuckets;
+
+    //
+    // If number of items has become too many, we will double the hash table
+    // size (we never reduce it however)
+    //
+    if (_nItems <= PRIME::GetPrime(2*_nBuckets))
+    {
+        return;
+    }
+
+    _tableLock.ExclusiveAcquire();
+
+    nNewBuckets = PRIME::GetPrime(2*_nBuckets);
+
+    if (_nItems <= nNewBuckets)
+    {
+        goto Finished;
+    }
+
+    nBuckets = nNewBuckets;
+    if (nBuckets >= 0xffffffff/sizeof(HASH_NODE<_Record> *))
+    {
+        goto Finished;
+    }
+    ppBuckets = (HASH_NODE<_Record> **)HeapAlloc(
+                        GetProcessHeap(),
+                        HEAP_ZERO_MEMORY,
+                        nBuckets*sizeof(HASH_NODE<_Record> *));
+    if (ppBuckets == NULL)
+    {
+        goto Finished;
+    }
+
+    //
+    // Take out nodes from the old hash table and insert in the new one, make
+    // sure to keep the hashes in increasing order
+    //
+    for (DWORD i=0; i<_nBuckets; i++)
+    {
+        pNode = _ppBuckets[i];
+        while (pNode != NULL)
+        {
+            pNextNode = pNode->_pNext;
+
+            ppNextPointer = ppBuckets + (pNode->_dwHash % nBuckets);
+            pNewNextNode = *ppNextPointer;
+            while (pNewNextNode != NULL &&
+                   pNewNextNode->_dwHash <= pNode->_dwHash)
+            {
+                ppNextPointer = &pNewNextNode->_pNext;
+                pNewNextNode = pNewNextNode->_pNext;
+            }
+            pNode->_pNext = pNewNextNode;
+            *ppNextPointer = pNode;
+
+            pNode = pNextNode;
+        }
+    }
+
+    HeapFree(GetProcessHeap(), 0, _ppBuckets);
+    _ppBuckets = ppBuckets;
+    _nBuckets = nBuckets;
+    ppBuckets = NULL;
+
+Finished:
+
+    _tableLock.ExclusiveRelease();
+}
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/IISLib/listentry.h b/src/IISIntegration/src/AspNetCoreModuleV2/IISLib/listentry.h
new file mode 100644
index 0000000000000000000000000000000000000000..80b70e97a937a07b8337eea20c81a09de3ec0a68
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/IISLib/listentry.h
@@ -0,0 +1,163 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#pragma once
+
+#ifndef _LIST_ENTRY_H
+#define _LIST_ENTRY_H
+
+//
+//  Doubly-linked list manipulation routines.
+//
+
+
+#define InitializeListHead32(ListHead) (\
+    (ListHead)->Flink = (ListHead)->Blink = PtrToUlong((ListHead)))
+
+
+FORCEINLINE
+VOID
+InitializeListHead(
+    IN PLIST_ENTRY ListHead
+    )
+{
+    ListHead->Flink = ListHead->Blink = ListHead;
+}
+
+FORCEINLINE
+BOOLEAN
+IsListEmpty(
+    IN const LIST_ENTRY * ListHead
+    )
+{
+    return (BOOLEAN)(ListHead->Flink == ListHead);
+}
+
+FORCEINLINE
+BOOLEAN
+RemoveEntryList(
+    IN PLIST_ENTRY Entry
+    )
+{
+    PLIST_ENTRY Blink;
+    PLIST_ENTRY Flink;
+
+    Flink = Entry->Flink;
+    Blink = Entry->Blink;
+    Blink->Flink = Flink;
+    Flink->Blink = Blink;
+    return (BOOLEAN)(Flink == Blink);
+}
+
+FORCEINLINE
+PLIST_ENTRY
+RemoveHeadList(
+    IN PLIST_ENTRY ListHead
+    )
+{
+    PLIST_ENTRY Flink;
+    PLIST_ENTRY Entry;
+
+    Entry = ListHead->Flink;
+    Flink = Entry->Flink;
+    ListHead->Flink = Flink;
+    Flink->Blink = ListHead;
+    return Entry;
+}
+
+
+
+FORCEINLINE
+PLIST_ENTRY
+RemoveTailList(
+    IN PLIST_ENTRY ListHead
+    )
+{
+    PLIST_ENTRY Blink;
+    PLIST_ENTRY Entry;
+
+    Entry = ListHead->Blink;
+    Blink = Entry->Blink;
+    ListHead->Blink = Blink;
+    Blink->Flink = ListHead;
+    return Entry;
+}
+
+
+FORCEINLINE
+VOID
+InsertTailList(
+    IN PLIST_ENTRY ListHead,
+    IN PLIST_ENTRY Entry
+    )
+{
+    PLIST_ENTRY Blink;
+
+    Blink = ListHead->Blink;
+    Entry->Flink = ListHead;
+    Entry->Blink = Blink;
+    Blink->Flink = Entry;
+    ListHead->Blink = Entry;
+}
+
+
+FORCEINLINE
+VOID
+InsertHeadList(
+    IN PLIST_ENTRY ListHead,
+    IN PLIST_ENTRY Entry
+    )
+{
+    PLIST_ENTRY Flink;
+
+    Flink = ListHead->Flink;
+    Entry->Flink = Flink;
+    Entry->Blink = ListHead;
+    Flink->Blink = Entry;
+    ListHead->Flink = Entry;
+}
+
+FORCEINLINE
+VOID
+AppendTailList(
+    IN PLIST_ENTRY ListHead,
+    IN PLIST_ENTRY ListToAppend
+    )
+{
+    PLIST_ENTRY ListEnd = ListHead->Blink;
+
+    ListHead->Blink->Flink = ListToAppend;
+    ListHead->Blink = ListToAppend->Blink;
+    ListToAppend->Blink->Flink = ListHead;
+    ListToAppend->Blink = ListEnd;
+}
+
+FORCEINLINE
+PSINGLE_LIST_ENTRY
+PopEntryList(
+    PSINGLE_LIST_ENTRY ListHead
+    )
+{
+    PSINGLE_LIST_ENTRY FirstEntry;
+    FirstEntry = ListHead->Next;
+    if (FirstEntry != NULL) {
+        ListHead->Next = FirstEntry->Next;
+    }
+
+    return FirstEntry;
+}
+
+
+FORCEINLINE
+VOID
+PushEntryList(
+    PSINGLE_LIST_ENTRY ListHead,
+    PSINGLE_LIST_ENTRY Entry
+    )
+{
+    Entry->Next = ListHead->Next;
+    ListHead->Next = Entry;
+}
+
+
+#endif
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/IISLib/macros.h b/src/IISIntegration/src/AspNetCoreModuleV2/IISLib/macros.h
new file mode 100644
index 0000000000000000000000000000000000000000..960f663a98c1dba4654365e83d1c9ec129c68577
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/IISLib/macros.h
@@ -0,0 +1,63 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#ifndef _MACROS_H
+#define _MACROS_H
+
+//
+// The DIFF macro should be used around an expression involving pointer
+// subtraction. The expression passed to DIFF is cast to a size_t type,
+// allowing the result to be easily assigned to any 32-bit variable or
+// passed to a function expecting a 32-bit argument.
+//
+
+#define DIFF(x)     ((size_t)(x))
+
+// Change a hexadecimal digit to its numerical equivalent
+#define TOHEX( ch )                                     \
+    ((ch) > L'9' ?                                      \
+        (ch) >= L'a' ?                                  \
+            (ch) - L'a' + 10 :                          \
+            (ch) - L'A' + 10                            \
+        : (ch) - L'0')
+
+
+// Change a number to its Hexadecimal equivalent
+
+#define TODIGIT( nDigit )                               \
+     (CHAR)((nDigit) > 9 ?                              \
+          (nDigit) - 10 + 'A'                           \
+        : (nDigit) + '0')
+
+
+inline int
+SAFEIsSpace(UCHAR c)
+{
+    return isspace( c );
+}
+
+inline int
+SAFEIsAlNum(UCHAR c)
+{
+    return isalnum( c );
+}
+
+inline int
+SAFEIsAlpha(UCHAR c)
+{
+    return isalpha( c );
+}
+
+inline int
+SAFEIsXDigit(UCHAR c)
+{
+    return isxdigit( c );
+}
+
+inline int
+SAFEIsDigit(UCHAR c)
+{
+    return isdigit( c );
+}
+
+#endif // _MACROS_H
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/IISLib/multisz.cpp b/src/IISIntegration/src/AspNetCoreModuleV2/IISLib/multisz.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..775ec4cd0c96fe11a6c5268d5fd9e5114562e562
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/IISLib/multisz.cpp
@@ -0,0 +1,474 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+
+#pragma warning (disable : 4267)
+
+#include "precomp.h"
+#include "multisz.h"
+#include <tchar.h>
+
+//
+//  Private Definitions
+//
+
+#define MAXULONG 4294967295
+#define ISWHITE( ch )       ((ch) == L' ' || (ch) == L'\t' || (ch) == L'\r')
+
+//
+//  When appending data, this is the extra amount we request to avoid
+//  reallocations
+//
+#define STR_SLOP        128
+
+
+DWORD
+MULTISZ::CalcLength( const WCHAR * str,
+                     LPDWORD pcStrings )
+{
+    DWORD count = 0;
+    DWORD total = 1;
+    DWORD len;
+
+    while( *str ) {
+        len = ::wcslen( str ) + 1;
+        total += len;
+        str += len;
+        count++;
+    }
+
+    if( pcStrings != NULL ) {
+        *pcStrings = count;
+    }
+
+    return total;
+
+}   // MULTISZ::CalcLength
+
+
+BOOL
+MULTISZ::FindString( const WCHAR * str )
+{
+
+    WCHAR * multisz;
+
+    //
+    // Sanity check.
+    //
+
+    DBG_ASSERT( QueryStr() != NULL );
+    DBG_ASSERT( str != NULL );
+    DBG_ASSERT( *str != '\0' );
+
+    //
+    // Scan it.
+    //
+
+    multisz = QueryStr();
+
+    while( *multisz != '\0' ) {
+
+        if( !::wcscmp( multisz, str ) ) {
+
+            return TRUE;
+
+        }
+
+        multisz += ::wcslen( multisz ) + 1;
+
+    }
+
+    return FALSE;
+
+}   // MULTISZ::FindString
+
+
+BOOL
+MULTISZ::FindStringNoCase( const WCHAR * str )
+{
+
+    WCHAR * multisz;
+
+    //
+    // Sanity check.
+    //
+
+    DBG_ASSERT( QueryStr() != NULL );
+    DBG_ASSERT( str != NULL );
+    DBG_ASSERT( *str != '\0' );
+
+    //
+    // Scan it.
+    //
+
+    multisz = QueryStr();
+
+    while( *multisz != '\0' ) {
+
+        if( !_wcsicmp( multisz, str ) ) {
+
+            return TRUE;
+
+        }
+
+        multisz += wcslen( multisz ) + 1;
+
+    }
+
+    return FALSE;
+
+}   // MULTISZ::FindStringNoCase
+
+
+VOID
+MULTISZ::AuxInit( const WCHAR * pInit )
+{
+    BOOL fRet;
+
+    if ( pInit )
+    {
+        DWORD cStrings;
+        int cbCopy = CalcLength( pInit, &cStrings ) * sizeof(WCHAR);
+        fRet = Resize( cbCopy );
+
+        if ( fRet ) {
+            CopyMemory( QueryPtr(), pInit, cbCopy );
+            m_cchLen = (cbCopy)/sizeof(WCHAR);
+            m_cStrings = cStrings;
+        } else {
+//            BUFFER::SetValid( FALSE);
+        }
+
+    } else {
+
+        Reset();
+
+    }
+
+} // MULTISZ::AuxInit()
+
+
+/*******************************************************************
+
+    NAME:       MULTISZ::AuxAppend
+
+    SYNOPSIS:   Appends the string onto the multisz.
+
+    ENTRY:      Object to append
+********************************************************************/
+
+BOOL MULTISZ::AuxAppend( const WCHAR * pStr, UINT cbStr, BOOL fAddSlop )
+{
+    DBG_ASSERT( pStr != NULL );
+
+    UINT cbThis = QueryCB();
+
+    DBG_ASSERT( cbThis >= 2 );
+
+    if( cbThis == 4 ) {
+
+        //
+        // It's empty, so start at the beginning.
+        //
+
+        cbThis = 0;
+
+    } else {
+
+        //
+        // It's not empty, so back up over the final terminating NULL.
+        //
+
+        cbThis -= sizeof(WCHAR);
+
+    }
+
+    //
+    //  Only resize when we have to.  When we do resize, we tack on
+    //  some extra space to avoid extra reallocations.
+    //
+    //  Note: QuerySize returns the requested size of the string buffer,
+    //        *not* the strlen of the buffer
+    //
+
+    //AcIncrement( CacMultiszAppend);
+    
+    // 
+    // Check for the arithmetic overflow
+    //
+    // ( 2 * sizeof( WCHAR ) ) is for the double terminator
+    //
+    ULONGLONG cb64Required = (ULONGLONG)cbThis + cbStr + 2 * sizeof(WCHAR);
+    if ( cb64Required > MAXULONG )
+    {
+        SetLastError( ERROR_ARITHMETIC_OVERFLOW );
+        return FALSE;
+    }
+    if ( QuerySize() < (DWORD) cb64Required )
+    {
+        ULONGLONG cb64AllocSize = cb64Required + (fAddSlop ? STR_SLOP : 0 );
+        // 
+        // Check for the arithmetic overflow
+        //
+        if ( cb64AllocSize > MAXULONG )
+        {
+            SetLastError( ERROR_ARITHMETIC_OVERFLOW );
+            return FALSE;
+        }
+        if ( !Resize( (DWORD) cb64AllocSize ) )
+            return FALSE;
+    }
+
+    // copy the exact string and tack on the double terminator
+    memcpy( (BYTE *) QueryPtr() + cbThis,
+            pStr,
+            cbStr);
+    *(WCHAR *)((BYTE *)QueryPtr() + cbThis + cbStr) = L'\0';
+    *(WCHAR *)((BYTE *)QueryPtr() + cbThis + cbStr + sizeof(WCHAR) ) = L'\0';
+
+    m_cchLen = CalcLength( (const WCHAR *)QueryPtr(), &m_cStrings );
+    return TRUE;
+
+} // MULTISZ::AuxAppend()
+
+
+#if 0
+
+BOOL
+MULTISZ::CopyToBuffer( WCHAR * lpszBuffer, LPDWORD lpcch) const
+/*++
+    Description:
+        Copies the string into the WCHAR buffer passed in if the buffer
+        is sufficient to hold the translated string.
+        If the buffer is small, the function returns small and sets *lpcch
+        to contain the required number of characters.
+
+    Arguments:
+        lpszBuffer      pointer to WCHAR buffer which on return contains
+                        the UNICODE version of string on success.
+        lpcch           pointer to DWORD containing the length of the buffer.
+                        If *lpcch == 0 then the function returns TRUE with
+                        the count of characters required stored in *lpcch.
+                        Also in this case lpszBuffer is not affected.
+    Returns:
+        TRUE on success.
+        FALSE on failure.  Use GetLastError() for further details.
+--*/
+{
+   BOOL fReturn = TRUE;
+
+    if ( lpcch == NULL) {
+        SetLastError( ERROR_INVALID_PARAMETER);
+        return ( FALSE);
+    }
+
+    if ( *lpcch == 0) {
+
+      //
+      //  Inquiring the size of buffer alone
+      //
+      *lpcch = QueryCCH() + 1;    // add one character for terminating null
+    } else {
+
+        //
+        // Copy after conversion from ANSI to Unicode
+        //
+        int  iRet;
+        iRet = MultiByteToWideChar( CP_ACP,
+                                    MB_PRECOMPOSED | MB_ERR_INVALID_CHARS,
+                                    QueryStrA(),  QueryCCH() + 1,
+                                    lpszBuffer, (int )*lpcch);
+
+        if ( iRet == 0 || iRet != (int ) *lpcch) {
+
+            //
+            // Error in conversion.
+            //
+            fReturn = FALSE;
+        }
+    }
+
+    return ( fReturn);
+} // MULTISZ::CopyToBuffer()
+#endif
+
+BOOL
+MULTISZ::CopyToBuffer( __out_ecount_opt(*lpcch) WCHAR * lpszBuffer, LPDWORD lpcch) const
+/*++
+    Description:
+        Copies the string into the WCHAR buffer passed in if the buffer
+          is sufficient to hold the translated string.
+        If the buffer is small, the function returns small and sets *lpcch
+          to contain the required number of characters.
+
+    Arguments:
+        lpszBuffer      pointer to WCHAR buffer which on return contains
+                        the string on success.
+        lpcch           pointer to DWORD containing the length of the buffer.
+                        If *lpcch == 0 then the function returns TRUE with
+                        the count of characters required stored in lpcch.
+                        Also in this case lpszBuffer is not affected.
+    Returns:
+        TRUE on success.
+        FALSE on failure.  Use GetLastError() for further details.
+--*/
+{
+   BOOL fReturn = TRUE;
+
+    if ( lpcch == NULL) {
+        SetLastError( ERROR_INVALID_PARAMETER);
+        return ( FALSE);
+    }
+
+    register DWORD cch = QueryCCH();
+
+    if ( *lpcch >= cch) {
+
+        DBG_ASSERT( lpszBuffer);
+        memcpy( lpszBuffer, QueryStr(), cch * sizeof(WCHAR));
+    } else {
+        DBG_ASSERT( *lpcch < cch);
+        SetLastError( ERROR_INSUFFICIENT_BUFFER);
+        fReturn = FALSE;
+    }
+
+    *lpcch = cch;
+
+    return ( fReturn);
+} // MULTISZ::CopyToBuffer()
+
+BOOL
+MULTISZ::Equals(
+    MULTISZ* pmszRhs
+)
+//
+// Compares this to pmszRhs, returns TRUE if equal
+//
+{
+    DBG_ASSERT( NULL != pmszRhs );
+
+    PCWSTR pszLhs = First( );
+    PCWSTR pszRhs = pmszRhs->First( );
+
+    if( m_cStrings != pmszRhs->m_cStrings )
+    {
+        return FALSE;
+    }
+
+    while( NULL != pszLhs )
+    {
+        DBG_ASSERT( NULL != pszRhs );
+
+        if( 0 != wcscmp( pszLhs, pszRhs ) )
+        {
+            return FALSE;
+        }
+
+        pszLhs = Next( pszLhs );
+        pszRhs = pmszRhs->Next( pszRhs );
+    }
+
+    return TRUE;
+}
+
+HRESULT
+SplitCommaDelimitedString(
+    PCWSTR                      pszList,
+    BOOL                        fTrimEntries,
+    BOOL                        fRemoveEmptyEntries,
+    MULTISZ *                   pmszList
+)
+/*++
+
+Routine Description:
+
+    Split comma delimited string into a multisz. Additional leading empty
+    entries after the first are discarded.
+
+Arguments:
+
+    pszList - List to split up
+    fTrimEntries - Whether each entry should be trimmed before added to multisz
+    fRemoveEmptyEntries - Whether empty entires should be discarded
+    pmszList - Filled with MULTISZ list
+
+Return Value:
+
+    HRESULT
+
+--*/
+{
+    HRESULT                 hr = S_OK;
+
+    if ( pszList == NULL ||
+         pmszList == NULL )
+    {
+        DBG_ASSERT( FALSE );
+        hr = HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
+        goto Finished;
+    }
+    
+    pmszList->Reset();
+
+    /*
+        pszCurrent: start of the current entry which may be the comma that
+                    precedes the next entry if the entry is empty
+
+        pszNext: the comma that precedes the next entry. If
+                 pszCurrent == pszNext, then the entry is empty
+
+        pszEnd: just past the end of the current entry
+    */
+    
+    for ( PCWSTR pszCurrent = pszList,
+                 pszNext = wcschr( pszCurrent, L',' )
+            ;
+            ;
+          pszCurrent = pszNext + 1,
+          pszNext = wcschr( pszCurrent, L',' ) )
+    {
+        PCWSTR pszEnd = NULL;
+
+        if ( pszNext != NULL )
+        {
+            pszEnd = pszNext;
+        }
+        else
+        {
+            pszEnd = pszCurrent + wcslen( pszCurrent );
+        }
+
+        if ( fTrimEntries )
+        {
+            while ( pszCurrent < pszEnd && ISWHITE( pszCurrent[ 0 ] ) )
+            {
+                pszCurrent++;
+            }
+
+            while ( pszEnd > pszCurrent && ISWHITE( pszEnd[ -1 ] ) )
+            {
+                pszEnd--;
+            }
+        }
+
+        if ( pszCurrent != pszEnd || !fRemoveEmptyEntries  )
+        {
+            if ( !pmszList->Append( pszCurrent, (DWORD) ( pszEnd - pszCurrent ) ) )
+            {
+                hr = HRESULT_FROM_WIN32( GetLastError() );
+                goto Finished;
+            }
+        }
+        
+        if ( pszNext == NULL )
+        {
+            break;
+        }
+    }
+
+Finished:
+
+    return hr;
+}
+
+#pragma warning(default:4267)
\ No newline at end of file
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/IISLib/multisz.h b/src/IISIntegration/src/AspNetCoreModuleV2/IISLib/multisz.h
new file mode 100644
index 0000000000000000000000000000000000000000..f65c151d4ff0820121e750d8942156bb665c9aa1
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/IISLib/multisz.h
@@ -0,0 +1,225 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#ifndef _MULTISZ_H_
+#define _MULTISZ_H_
+
+#include "stringu.h"
+#include "ntassert.h"
+
+/*++
+  class MULTISZ:
+
+  Intention:
+    A light-weight multi-string class supporting encapsulated string class.
+
+    This object is derived from BUFFER class.
+    It maintains following state:
+
+     m_fValid  - whether this object is valid -
+        used only by MULTISZ() init functions
+        * NYI: I need to kill this someday *
+     m_cchLen - string length cached when we update the string.
+     m_cStrings - number of strings.
+
+  Member Functions:
+    There are two categories of functions:
+      1) Safe Functions - which do integrity checking of state
+      2) UnSafe Functions - which do not do integrity checking, but
+                     enable writing to the data stream freely.
+             (someday this will be enabled as Safe versions without
+               problem for users)
+
+--*/
+class MULTISZ : public BUFFER
+{
+public:
+
+    MULTISZ()
+      : BUFFER   (),
+        m_cchLen ( 0),
+        m_cStrings(0)
+    { Reset(); }
+
+    // creates a stack version of the MULTISZ object - uses passed in stack buffer
+    //  MULTISZ does not free this pbInit on its own.
+    MULTISZ( __in_bcount(cbInit) WCHAR * pbInit, DWORD cbInit)
+        : BUFFER( (BYTE *) pbInit, cbInit),
+          m_cchLen (0),
+          m_cStrings(0)
+    {}
+
+    MULTISZ( const WCHAR * pchInit )
+        : BUFFER   (),
+          m_cchLen ( 0),
+          m_cStrings(0)
+    { AuxInit(pchInit); }
+
+    MULTISZ( const MULTISZ & str )
+        : BUFFER   (),
+          m_cchLen ( 0),
+          m_cStrings(0)
+    { AuxInit( str.QueryStr()); }
+
+//    BOOL IsValid(VOID) const { return ( BUFFER::IsValid()) ; }
+    //
+    //  Checks and returns TRUE if this string has no valid data else FALSE
+    //
+    BOOL IsEmpty( VOID) const      { return ( *QueryStr() == L'\0'); }
+
+    BOOL Append( const WCHAR  * pchInit ) {
+      return ((pchInit != NULL) ? (AuxAppend( pchInit,
+                                              (DWORD) (::wcslen(pchInit)) * sizeof(WCHAR)
+                                              )) :
+              TRUE);
+    }
+
+
+    BOOL Append( const WCHAR  * pchInit, DWORD cchLen ) {
+      return ((pchInit != NULL) ? (AuxAppend( pchInit,
+                                              cchLen * sizeof(WCHAR))) :
+              TRUE);
+    }
+
+    BOOL Append( STRU & str )
+      { return AuxAppend( str.QueryStr(),
+                          (str.QueryCCH()) * sizeof(WCHAR)); }
+
+    // Resets the internal string to be NULL string. Buffer remains cached.
+    VOID Reset( VOID)
+    { DBG_ASSERT( QueryPtr() != NULL);
+      QueryStr()[0] = L'\0';
+      QueryStr()[1] = L'\0';
+      m_cchLen = 2;
+      m_cStrings = 0;
+    }
+
+    BOOL Copy( const WCHAR  * pchInit, IN DWORD cbLen ) {
+      if ( QueryPtr() ) { Reset(); }
+      return ( (pchInit != NULL) ?
+               AuxAppend( pchInit, cbLen, FALSE ):
+               TRUE);
+    }
+
+    BOOL Copy( const MULTISZ   & str )
+    { return ( Copy(str.QueryStr(), str.QueryCB())); }
+
+    //
+    //  Returns the number of bytes in the string including the terminating
+    //  NULLs
+    //
+    UINT QueryCB( VOID ) const
+        { return ( m_cchLen * sizeof(WCHAR)); }
+
+    //
+    //  Returns # of characters in the string including the terminating NULLs
+    //
+    UINT QueryCCH( VOID ) const { return (m_cchLen); }
+
+    //
+    //  Returns # of strings in the multisz.
+    //
+
+    DWORD QueryStringCount( VOID ) const { return m_cStrings; }
+
+    //
+    // Makes a copy of the stored string in given buffer
+    //
+    BOOL CopyToBuffer( __out_ecount_opt(*lpcch) WCHAR * lpszBuffer,  LPDWORD lpcch) const;
+
+    //
+    //  Return the string buffer
+    //
+    WCHAR * QueryStrA( VOID ) const { return ( QueryStr()); }
+    WCHAR * QueryStr( VOID ) const { return ((WCHAR *) QueryPtr()); }
+
+    //
+    //  Makes a clone of the current string in the string pointer passed in.
+    //
+    BOOL
+      Clone( OUT MULTISZ * pstrClone) const
+        {
+          return ((pstrClone == NULL) ?
+                  (SetLastError(ERROR_INVALID_PARAMETER), FALSE) :
+                  (pstrClone->Copy( *this))
+                  );
+        } // MULTISZ::Clone()
+
+    //
+    //  Recalculates the length of *this because we've modified the buffers
+    //  directly
+    //
+
+    VOID RecalcLen( VOID )
+        { m_cchLen = MULTISZ::CalcLength( QueryStr(), &m_cStrings ); }
+
+    //
+    // Calculate total character length of a MULTI_SZ, including the
+    // terminating NULLs.
+    //
+
+    static DWORD CalcLength( const WCHAR * str,
+                                    LPDWORD pcStrings = NULL );
+
+    //
+    // Determine if the MULTISZ contains a specific string.
+    //
+
+    BOOL FindString( const WCHAR * str );
+
+    BOOL FindString( STRU & str )
+        { return FindString( str.QueryStr() ); }
+
+    //
+    // Determine if the MULTISZ contains a specific string - case-insensitive
+    //
+
+    BOOL FindStringNoCase( const WCHAR * str );
+
+    BOOL FindStringNoCase( STRU & str )
+        { return FindStringNoCase( str.QueryStr() ); }
+
+    //
+    // Used for scanning a multisz.
+    //
+
+    const WCHAR * First( VOID ) const
+        { return *QueryStr() == L'\0' ? NULL : QueryStr(); }
+
+    const WCHAR * Next( const WCHAR * Current ) const
+        { Current += ::wcslen( Current ) + 1;
+          return *Current == L'\0' ? NULL : Current; }
+
+    BOOL
+    Equals(
+        MULTISZ* pmszRhs
+    );
+
+private:
+
+    DWORD m_cchLen;
+    DWORD m_cStrings;
+    VOID AuxInit( const WCHAR * pInit );
+    BOOL AuxAppend( const WCHAR * pInit,
+                           UINT cbStr, BOOL fAddSlop = TRUE );
+
+};
+
+//
+//  Quick macro for declaring a MULTISZ that will use stack memory of <size>
+//  bytes.  If the buffer overflows then a heap buffer will be allocated
+//
+
+#define STACK_MULTISZ( name, size )     WCHAR __ach##name[size]; \
+                                    MULTISZ name( __ach##name, sizeof( __ach##name ))
+
+HRESULT
+SplitCommaDelimitedString(
+    PCWSTR                      pszList,
+    BOOL                        fTrimEntries,
+    BOOL                        fRemoveEmptyEntries,
+    MULTISZ *                   pmszList
+);
+
+#endif // !_MULTISZ_HXX_
+
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/IISLib/multisza.cpp b/src/IISIntegration/src/AspNetCoreModuleV2/IISLib/multisza.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..54717edf052858b70feb9f77e5413646e7541b12
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/IISLib/multisza.cpp
@@ -0,0 +1,408 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#pragma warning (disable : 4267)
+#include "precomp.h"
+#include "multisza.h"
+#include <tchar.h>
+
+//
+//  Private Definitions
+//
+
+#define MAXULONG 4294967295
+#define ISWHITE( ch )       ((ch) == L' ' || (ch) == L'\t' || (ch) == L'\r')
+
+//
+//  When appending data, this is the extra amount we request to avoid
+//  reallocations
+//
+#define STR_SLOP        128
+
+
+DWORD
+MULTISZA::CalcLength( const CHAR * str,
+                     LPDWORD pcStrings )
+{
+    DWORD count = 0;
+    DWORD total = 1;
+    DWORD len;
+
+    while( *str ) {
+        len = ::strlen( str ) + 1;
+        total += len;
+        str += len;
+        count++;
+    }
+
+    if( pcStrings != NULL ) {
+        *pcStrings = count;
+    }
+
+    return total;
+
+}   // MULTISZA::CalcLength
+
+
+BOOL
+MULTISZA::FindString( const CHAR * str )
+{
+
+    CHAR * multisz;
+
+    //
+    // Sanity check.
+    //
+
+    DBG_ASSERT( QueryStr() != NULL );
+    DBG_ASSERT( str != NULL );
+    DBG_ASSERT( *str != '\0' );
+
+    //
+    // Scan it.
+    //
+
+    multisz = QueryStr();
+
+    while( *multisz != '\0' ) {
+
+        if( !::strcmp( multisz, str ) ) {
+
+            return TRUE;
+
+        }
+
+        multisz += ::strlen( multisz ) + 1;
+
+    }
+
+    return FALSE;
+
+}   // MULTISZA::FindString
+
+
+BOOL
+MULTISZA::FindStringNoCase( const CHAR * str )
+{
+
+    CHAR * multisz;
+
+    //
+    // Sanity check.
+    //
+
+    DBG_ASSERT( QueryStr() != NULL );
+    DBG_ASSERT( str != NULL );
+    DBG_ASSERT( *str != '\0' );
+
+    //
+    // Scan it.
+    //
+
+    multisz = QueryStr();
+
+    while( *multisz != '\0' ) {
+
+        if( !_stricmp( multisz, str ) ) {
+
+            return TRUE;
+
+        }
+
+        multisz += strlen( multisz ) + 1;
+
+    }
+
+    return FALSE;
+
+}   // MULTISZA::FindStringNoCase
+
+
+VOID
+MULTISZA::AuxInit( const CHAR * pInit )
+{
+    BOOL fRet;
+
+    if ( pInit )
+    {
+        DWORD cStrings;
+        int cbCopy = CalcLength( pInit, &cStrings ) * sizeof(CHAR);
+        fRet = Resize( cbCopy );
+
+        if ( fRet ) {
+            CopyMemory( QueryPtr(), pInit, cbCopy );
+            m_cchLen = (cbCopy)/sizeof(CHAR);
+            m_cStrings = cStrings;
+        } else {
+//            BUFFER::SetValid( FALSE);
+        }
+
+    } else {
+
+        Reset();
+
+    }
+
+} // MULTISZA::AuxInit()
+
+
+/*******************************************************************
+
+    NAME:       MULTISZA::AuxAppend
+
+    SYNOPSIS:   Appends the string onto the MULTISZA.
+
+    ENTRY:      Object to append
+********************************************************************/
+
+BOOL MULTISZA::AuxAppend( const CHAR * pStr, UINT cbStr, BOOL fAddSlop )
+{
+    DBG_ASSERT( pStr != NULL );
+
+    UINT cbThis = QueryCB();
+
+    if( cbThis == 2 ) {
+
+        //
+        // It's empty, so start at the beginning.
+        //
+
+        cbThis = 0;
+
+    } else {
+
+        //
+        // It's not empty, so back up over the final terminating NULL.
+        //
+
+        cbThis -= sizeof(CHAR);
+
+    }
+
+    //
+    //  Only resize when we have to.  When we do resize, we tack on
+    //  some extra space to avoid extra reallocations.
+    //
+    //  Note: QuerySize returns the requested size of the string buffer,
+    //        *not* the strlen of the buffer
+    //
+
+    //AcIncrement( CacMultiszAppend);
+    
+    // 
+    // Check for the arithmetic overflow
+    //
+    // ( 2 * sizeof( CHAR ) ) is for the double terminator
+    //
+    ULONGLONG cb64Required = (ULONGLONG)cbThis + cbStr + 2 * sizeof(CHAR);
+    if ( cb64Required > MAXULONG )
+    {
+        SetLastError( ERROR_ARITHMETIC_OVERFLOW );
+        return FALSE;
+    }
+    if ( QuerySize() < (DWORD) cb64Required )
+    {
+        ULONGLONG cb64AllocSize = cb64Required + (fAddSlop ? STR_SLOP : 0 );
+        // 
+        // Check for the arithmetic overflow
+        //
+        if ( cb64AllocSize > MAXULONG )
+        {
+            SetLastError( ERROR_ARITHMETIC_OVERFLOW );
+            return FALSE;
+        }
+        if ( !Resize( (DWORD) cb64AllocSize ) )
+            return FALSE;
+    }
+
+    // copy the exact string and tack on the double terminator
+    memcpy( (BYTE *) QueryPtr() + cbThis,
+            pStr,
+            cbStr);
+    *(CHAR *)((BYTE *)QueryPtr() + cbThis + cbStr) = L'\0';
+    *(CHAR *)((BYTE *)QueryPtr() + cbThis + cbStr + sizeof(CHAR) ) = L'\0';
+
+    m_cchLen = CalcLength( (const CHAR *)QueryPtr(), &m_cStrings );
+    return TRUE;
+
+} // MULTISZA::AuxAppend()
+
+BOOL
+MULTISZA::CopyToBuffer( __out_ecount_opt(*lpcch) CHAR * lpszBuffer, LPDWORD lpcch) const
+/*++
+    Description:
+        Copies the string into the CHAR buffer passed in if the buffer
+          is sufficient to hold the translated string.
+        If the buffer is small, the function returns small and sets *lpcch
+          to contain the required number of characters.
+
+    Arguments:
+        lpszBuffer      pointer to CHAR buffer which on return contains
+                        the string on success.
+        lpcch           pointer to DWORD containing the length of the buffer.
+                        If *lpcch == 0 then the function returns TRUE with
+                        the count of characters required stored in lpcch.
+                        Also in this case lpszBuffer is not affected.
+    Returns:
+        TRUE on success.
+        FALSE on failure.  Use GetLastError() for further details.
+--*/
+{
+   BOOL fReturn = TRUE;
+
+    if ( lpcch == NULL) {
+        SetLastError( ERROR_INVALID_PARAMETER);
+        return ( FALSE);
+    }
+
+    register DWORD cch = QueryCCH();
+
+    if ( *lpcch >= cch) {
+
+        DBG_ASSERT( lpszBuffer);
+        memcpy( lpszBuffer, QueryStr(), cch * sizeof(CHAR));
+    } else {
+        DBG_ASSERT( *lpcch < cch);
+        SetLastError( ERROR_INSUFFICIENT_BUFFER);
+        fReturn = FALSE;
+    }
+
+    *lpcch = cch;
+
+    return ( fReturn);
+} // MULTISZA::CopyToBuffer()
+
+BOOL
+MULTISZA::Equals(
+    MULTISZA* pmszRhs
+)
+//
+// Compares this to pmszRhs, returns TRUE if equal
+//
+{
+    DBG_ASSERT( NULL != pmszRhs );
+
+    PCSTR pszLhs = First( );
+    PCSTR pszRhs = pmszRhs->First( );
+
+    if( m_cStrings != pmszRhs->m_cStrings )
+    {
+        return FALSE;
+    }
+
+    while( NULL != pszLhs )
+    {
+        DBG_ASSERT( NULL != pszRhs );
+
+        if( 0 != strcmp( pszLhs, pszRhs ) )
+        {
+            return FALSE;
+        }
+
+        pszLhs = Next( pszLhs );
+        pszRhs = pmszRhs->Next( pszRhs );
+    }
+
+    return TRUE;
+}
+
+HRESULT
+SplitCommaDelimitedString(
+    PCSTR                        pszList,
+    BOOL                         fTrimEntries,
+    BOOL                         fRemoveEmptyEntries,
+    MULTISZA *                   pmszList
+)
+/*++
+
+Routine Description:
+
+    Split comma delimited string into a MULTISZA. Additional leading empty
+    entries after the first are discarded.
+
+Arguments:
+
+    pszList - List to split up
+    fTrimEntries - Whether each entry should be trimmed before added to MULTISZA
+    fRemoveEmptyEntries - Whether empty entires should be discarded
+    pmszList - Filled with MULTISZA list
+
+Return Value:
+
+    HRESULT
+
+--*/
+{
+    HRESULT                 hr = S_OK;
+
+    if ( pszList == NULL ||
+         pmszList == NULL )
+    {
+        DBG_ASSERT( FALSE );
+        hr = HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
+        goto Finished;
+    }
+    
+    pmszList->Reset();
+
+    /*
+        pszCurrent: start of the current entry which may be the comma that
+                    precedes the next entry if the entry is empty
+
+        pszNext: the comma that precedes the next entry. If
+                 pszCurrent == pszNext, then the entry is empty
+
+        pszEnd: just past the end of the current entry
+    */
+    
+    for ( PCSTR pszCurrent = pszList,
+                 pszNext = strchr( pszCurrent, L',' )
+            ;
+            ;
+          pszCurrent = pszNext + 1,
+          pszNext = strchr( pszCurrent, L',' ) )
+    {
+        PCSTR pszEnd = NULL;
+
+        if ( pszNext != NULL )
+        {
+            pszEnd = pszNext;
+        }
+        else
+        {
+            pszEnd = pszCurrent + strlen( pszCurrent );
+        }
+
+        if ( fTrimEntries )
+        {
+            while ( pszCurrent < pszEnd && ISWHITE( pszCurrent[ 0 ] ) )
+            {
+                pszCurrent++;
+            }
+
+            while ( pszEnd > pszCurrent && ISWHITE( pszEnd[ -1 ] ) )
+            {
+                pszEnd--;
+            }
+        }
+
+        if ( pszCurrent != pszEnd || !fRemoveEmptyEntries  )
+        {
+            if ( !pmszList->Append( pszCurrent, (DWORD) ( pszEnd - pszCurrent ) ) )
+            {
+                hr = HRESULT_FROM_WIN32( GetLastError() );
+                goto Finished;
+            }
+        }
+        
+        if ( pszNext == NULL )
+        {
+            break;
+        }
+    }
+
+Finished:
+
+    return hr;
+}
+#pragma warning(default:4267)
\ No newline at end of file
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/IISLib/multisza.h b/src/IISIntegration/src/AspNetCoreModuleV2/IISLib/multisza.h
new file mode 100644
index 0000000000000000000000000000000000000000..d575ec94239bdb77b3ff7891f3c5d6452614278d
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/IISLib/multisza.h
@@ -0,0 +1,226 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#ifndef _MULTISZA_H_
+#define _MULTISZA_H_
+
+#include <Windows.h>
+#include "stringa.h"
+
+
+/*++
+  class MULTISZ:
+
+  Intention:
+    A light-weight multi-string class supporting encapsulated string class.
+
+    This object is derived from BUFFER class.
+    It maintains following state:
+
+     m_fValid  - whether this object is valid -
+        used only by MULTISZ() init functions
+        * NYI: I need to kill this someday *
+     m_cchLen - string length cached when we update the string.
+     m_cStrings - number of strings.
+
+  Member Functions:
+    There are two categories of functions:
+      1) Safe Functions - which do integrity checking of state
+      2) UnSafe Functions - which do not do integrity checking, but
+                     enable writing to the data stream freely.
+             (someday this will be enabled as Safe versions without
+               problem for users)
+
+--*/
+class MULTISZA : public BUFFER
+{
+public:
+
+    MULTISZA()
+      : BUFFER   (),
+        m_cchLen ( 0),
+        m_cStrings(0)
+    { Reset(); }
+
+    // creates a stack version of the MULTISZA object - uses passed in stack buffer
+    //  MULTISZA does not free this pbInit on its own.
+    MULTISZA( __in_bcount(cbInit) CHAR * pbInit, DWORD cbInit)
+        : BUFFER( (BYTE *) pbInit, cbInit),
+          m_cchLen (0),
+          m_cStrings(0)
+    {}
+
+    MULTISZA( const CHAR * pchInit )
+        : BUFFER   (),
+          m_cchLen ( 0),
+          m_cStrings(0)
+    { AuxInit(pchInit); }
+
+    MULTISZA( const MULTISZA & str )
+        : BUFFER   (),
+          m_cchLen ( 0),
+          m_cStrings(0)
+    { AuxInit( str.QueryStr()); }
+
+//    BOOL IsValid(VOID) const { return ( BUFFER::IsValid()) ; }
+    //
+    //  Checks and returns TRUE if this string has no valid data else FALSE
+    //
+    BOOL IsEmpty( VOID) const      { return ( *QueryStr() == L'\0'); }
+
+    BOOL Append( const CHAR  * pchInit ) {
+      return ((pchInit != NULL) ? (AuxAppend( pchInit,
+                                              (DWORD) (::strlen(pchInit)) * sizeof(CHAR)
+                                              )) :
+              TRUE);
+    }
+
+
+    BOOL Append( const CHAR  * pchInit, DWORD cchLen ) {
+      return ((pchInit != NULL) ? (AuxAppend( pchInit,
+                                              cchLen * sizeof(CHAR))) :
+              TRUE);
+    }
+
+    BOOL Append( STRA & str )
+      { return AuxAppend( str.QueryStr(),
+                          (str.QueryCCH()) * sizeof(CHAR)); }
+
+    // Resets the internal string to be NULL string. Buffer remains cached.
+    VOID Reset( VOID)
+    { DBG_ASSERT( QueryPtr() != NULL);
+      QueryStr()[0] = L'\0';
+      QueryStr()[1] = L'\0';
+      m_cchLen = 2;
+      m_cStrings = 0;
+    }
+
+    BOOL Copy( const CHAR  * pchInit, IN DWORD cbLen ) {
+      if ( QueryPtr() ) { Reset(); }
+      return ( (pchInit != NULL) ?
+               AuxAppend( pchInit, cbLen, FALSE ):
+               TRUE);
+    }
+
+    BOOL Copy( const MULTISZA   & str )
+    { return ( Copy(str.QueryStr(), str.QueryCB())); }
+
+    //
+    //  Returns the number of bytes in the string including the terminating
+    //  NULLs
+    //
+    UINT QueryCB( VOID ) const
+        { return ( m_cchLen * sizeof(CHAR)); }
+
+    //
+    //  Returns # of characters in the string including the terminating NULLs
+    //
+    UINT QueryCCH( VOID ) const { return (m_cchLen); }
+
+    //
+    //  Returns # of strings in the MULTISZA.
+    //
+
+    DWORD QueryStringCount( VOID ) const { return m_cStrings; }
+
+    //
+    // Makes a copy of the stored string in given buffer
+    //
+    BOOL CopyToBuffer( __out_ecount_opt(*lpcch) CHAR * lpszBuffer,  LPDWORD lpcch) const;
+
+    //
+    //  Return the string buffer
+    //
+    CHAR * QueryStrA( VOID ) const { return ( QueryStr()); }
+    CHAR * QueryStr( VOID ) const { return ((CHAR *) QueryPtr()); }
+
+    //
+    //  Makes a clone of the current string in the string pointer passed in.
+    //
+    BOOL
+      Clone( OUT MULTISZA * pstrClone) const
+        {
+          return ((pstrClone == NULL) ?
+                  (SetLastError(ERROR_INVALID_PARAMETER), FALSE) :
+                  (pstrClone->Copy( *this))
+                  );
+        } // MULTISZA::Clone()
+
+    //
+    //  Recalculates the length of *this because we've modified the buffers
+    //  directly
+    //
+
+    VOID RecalcLen( VOID )
+        { m_cchLen = MULTISZA::CalcLength( QueryStr(), &m_cStrings ); }
+
+    //
+    // Calculate total character length of a MULTI_SZ, including the
+    // terminating NULLs.
+    //
+
+    static DWORD CalcLength( const CHAR * str,
+                                    LPDWORD pcStrings = NULL );
+
+    //
+    // Determine if the MULTISZA contains a specific string.
+    //
+
+    BOOL FindString( const CHAR * str );
+
+    BOOL FindString( STRA & str )
+        { return FindString( str.QueryStr() ); }
+
+    //
+    // Determine if the MULTISZA contains a specific string - case-insensitive
+    //
+
+    BOOL FindStringNoCase( const CHAR * str );
+
+    BOOL FindStringNoCase( STRA & str )
+        { return FindStringNoCase( str.QueryStr() ); }
+
+    //
+    // Used for scanning a MULTISZA.
+    //
+
+    const CHAR * First( VOID ) const
+        { return *QueryStr() == L'\0' ? NULL : QueryStr(); }
+
+    const CHAR * Next( const CHAR * Current ) const
+        { Current += ::strlen( Current ) + 1;
+          return *Current == L'\0' ? NULL : Current; }
+
+    BOOL
+    Equals(
+        MULTISZA* pmszRhs
+    );
+
+private:
+
+    DWORD m_cchLen;
+    DWORD m_cStrings;
+    VOID AuxInit( const CHAR * pInit );
+    BOOL AuxAppend( const CHAR * pInit,
+                           UINT cbStr, BOOL fAddSlop = TRUE );
+
+};
+
+//
+//  Quick macro for declaring a MULTISZA that will use stack memory of <size>
+//  bytes.  If the buffer overflows then a heap buffer will be allocated
+//
+
+#define STACK_MULTISZA( name, size )     CHAR __ach##name[size]; \
+                                    MULTISZA name( __ach##name, sizeof( __ach##name ))
+
+HRESULT
+SplitCommaDelimitedString(
+    PCSTR                       pszList,
+    BOOL                        fTrimEntries,
+    BOOL                        fRemoveEmptyEntries,
+    MULTISZA *                  pmszList
+);
+
+#endif // !_MULTISZA_HXX_
+
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/IISLib/ntassert.h b/src/IISIntegration/src/AspNetCoreModuleV2/IISLib/ntassert.h
new file mode 100644
index 0000000000000000000000000000000000000000..6d2f3b9a300d07a8e91e6b947f7bd1e3af60338a
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/IISLib/ntassert.h
@@ -0,0 +1,32 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#pragma once
+
+#ifdef _ASSERTE
+    #undef _ASSERTE
+#endif
+
+#ifdef ASSERT
+    #undef ASSERT
+#endif
+
+#if defined( DBG ) && DBG
+    #define SX_ASSERT( _x )         ( (VOID)( ( ( _x ) ) ? TRUE : ( __annotation( L"Debug", L"AssertFail", L#_x  ), DbgRaiseAssertionFailure(), FALSE ) ) )
+    #define SX_ASSERTMSG( _m, _x )  ( (VOID)( ( ( _x ) ) ? TRUE : ( __annotation( L"Debug", L"AssertFail", L##_m ), DbgRaiseAssertionFailure(), FALSE ) ) )
+    #define SX_VERIFY( _x )         SX_ASSERT( _x )
+    #define _ASSERTE( _x )          SX_ASSERT( _x )
+    #define ASSERT( _x )            SX_ASSERT( _x )
+    #define assert( _x )            SX_ASSERT( _x )
+    #define DBG_ASSERT( _x )        SX_ASSERT( _x )
+    #define DBG_REQUIRE( _x )       SX_ASSERT( _x )
+#else
+    #define SX_ASSERT( _x )         ( (VOID)0 )
+    #define SX_ASSERTMSG( _m, _x )  ( (VOID)0 )
+    #define SX_VERIFY( _x )         ( (VOID)( ( _x ) ? TRUE : FALSE ) )
+    #define _ASSERTE( _x )          ( (VOID)0 )
+    #define assert( _x )            ( (VOID)0 )
+    #define DBG_ASSERT( _x )        ( (VOID)0 )
+    #define DBG_REQUIRE( _x )       ((VOID)(_x))
+#endif
+
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/IISLib/percpu.h b/src/IISIntegration/src/AspNetCoreModuleV2/IISLib/percpu.h
new file mode 100644
index 0000000000000000000000000000000000000000..5d3c56393520fbb0940e03dc7f84c05288d44520
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/IISLib/percpu.h
@@ -0,0 +1,305 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#pragma once
+
+template<typename T>
+class PER_CPU
+{
+public:
+
+    template<typename FunctionInitializer>
+    inline
+    static
+    HRESULT
+    Create(
+        FunctionInitializer         Initializer,
+        __deref_out PER_CPU<T> **   ppInstance
+    );
+
+    inline
+    T *
+    GetLocal(
+        VOID
+    );
+
+    template<typename FunctionForEach>
+    inline
+    VOID
+    ForEach(
+        FunctionForEach Function
+    );
+
+    inline
+    VOID
+    Dispose(
+        VOID
+    );
+
+private:
+
+    PER_CPU(
+        VOID
+    )
+    {
+        //
+        // Don't perform any operation during constructor.
+        // Constructor will never be called.
+        //
+    }
+
+    ~PER_CPU(
+        VOID
+    )
+    {
+        //
+        // Don't perform any operation during destructor.
+        // Constructor will never be called.
+        //
+    }
+
+    template<typename FunctionInitializer>
+    HRESULT
+    Initialize(
+        FunctionInitializer Initializer,
+        DWORD               NumberOfVariables,
+        DWORD               Alignment
+    );
+
+    T *
+    GetObject(
+        DWORD Index
+    );
+
+    static
+    HRESULT
+    GetProcessorInformation(
+        __out DWORD * pCacheLineSize,
+        __out DWORD * pNumberOfProcessors
+    );
+
+    //
+    // Pointer to the begining of the inlined array.
+    //
+    PVOID   m_pVariables;
+    SIZE_T  m_Alignment;
+    SIZE_T  m_VariablesCount;
+};
+
+template<typename T>
+template<typename FunctionInitializer>
+inline
+// static
+HRESULT
+PER_CPU<T>::Create(
+    FunctionInitializer        Initializer,
+    __deref_out PER_CPU<T> **  ppInstance
+)
+{
+    HRESULT         hr = S_OK;
+    DWORD           CacheLineSize = 0;
+    DWORD           ObjectCacheLineSize = 0;
+    DWORD           NumberOfProcessors = 0;
+    PER_CPU<T> *    pInstance = NULL;
+    
+    hr = GetProcessorInformation(&CacheLineSize,
+                                 &NumberOfProcessors);
+    if (FAILED(hr))
+    {
+        goto Finished;
+    }
+
+    if (sizeof(T) > CacheLineSize)
+    {
+        //
+        // Round to the next multiple of the cache line size.
+        //
+        ObjectCacheLineSize = (sizeof(T) + CacheLineSize-1) & (CacheLineSize-1);
+    }
+    else
+    {
+        ObjectCacheLineSize = CacheLineSize;
+    }
+
+    //
+    // Calculate the size of the PER_CPU<T> object, including the array.
+    // The first cache line is for the member variables and the array
+    // starts in the next cache line.
+    //
+    SIZE_T Size = CacheLineSize + NumberOfProcessors * ObjectCacheLineSize;
+
+    pInstance = (PER_CPU<T>*) _aligned_malloc(Size, CacheLineSize);
+    if (pInstance == NULL)
+    {
+        hr = E_OUTOFMEMORY;
+        goto Finished;
+    }
+    ZeroMemory(pInstance, Size);
+
+    //
+    // The array start in the 2nd cache line.
+    //
+    pInstance->m_pVariables = reinterpret_cast<PBYTE>(pInstance) + CacheLineSize;
+    
+    //
+    // Pass a disposer for disposing initialized items in case of failure.
+    //
+    hr = pInstance->Initialize(Initializer,
+                               NumberOfProcessors,
+                               ObjectCacheLineSize);
+    if (FAILED(hr))
+    {
+        goto Finished;
+    }
+
+    *ppInstance = pInstance;
+    pInstance = NULL;
+
+Finished:
+
+    if (pInstance != NULL)
+    {
+        //
+        // Free the instance without disposing it.
+        //
+        pInstance->Dispose();
+        pInstance = NULL;
+    }
+
+    return hr;
+}
+
+template<typename T>
+inline
+T *
+PER_CPU<T>::GetLocal(
+    VOID
+)
+{
+    // Use GetCurrentProcessorNumber (up to 64 logical processors) instead of
+    // GetCurrentProcessorNumberEx (more than 64 logical processors) because
+    // the number of processors are not densely packed per group.
+    // The idea of distributing variables per CPU is to have
+    // a scalability multiplier (could be NUMA node instead).
+    //
+    // Make sure the index don't go beyond the array size, if that happens,
+    // there won't be even distribution, but still better
+    // than one single variable.
+    //
+    return GetObject(GetCurrentProcessorNumber());
+}
+
+template<typename T>
+inline
+T *
+PER_CPU<T>::GetObject(
+    DWORD Index
+)
+{
+    return reinterpret_cast<T*>(static_cast<PBYTE>(m_pVariables) + Index * m_Alignment);
+}
+
+template<typename T>
+template<typename FunctionForEach>
+inline
+VOID
+PER_CPU<T>::ForEach(
+    FunctionForEach Function
+)
+{
+    for(DWORD Index = 0; Index < m_VariablesCount; ++Index)
+    {
+        T * pObject = GetObject(Index);
+        Function(pObject);
+    }
+}
+
+template<typename T>
+VOID
+PER_CPU<T>::Dispose(
+    VOID
+)
+{
+     _aligned_free(this);
+}
+
+template<typename T>
+template<typename FunctionInitializer>
+inline
+HRESULT
+PER_CPU<T>::Initialize(
+    FunctionInitializer Initializer,
+    DWORD               NumberOfVariables,
+    DWORD               Alignment
+)
+/*++
+
+Routine Description:
+
+    Initialize each object using the initializer function.
+    If initialization for any object fails, it dispose the
+    objects that were successfully initialized.
+
+Arguments:
+
+    Initializer - Function for initialize one object.
+                  Signature: HRESULT Func(T*)
+    Dispose - Function for disposing initialized objects in case of failure.
+              Signature: void Func(T*)
+    NumberOfVariables - The length of the array of variables.
+    Alignment - Alignment to use for avoiding false sharing.
+
+Return:
+
+    HRESULT - E_OUTOFMEMORY
+
+--*/
+{
+    HRESULT hr = S_OK;
+    DWORD Index = 0;
+
+    m_VariablesCount = NumberOfVariables;
+    m_Alignment = Alignment;
+
+    for (; Index < m_VariablesCount; ++Index)
+    {
+        T * pObject = GetObject(Index);
+        Initializer(pObject);
+    }
+
+    return hr;
+}
+
+template<typename T>
+// static
+HRESULT
+PER_CPU<T>::GetProcessorInformation(
+    __out DWORD * pCacheLineSize,
+    __out DWORD * pNumberOfProcessors
+)
+/*++
+
+Routine Description:
+
+    Gets the CPU cache-line size for the current system.
+    This information is used for avoiding CPU false sharing.
+
+Arguments:
+
+    pCacheLineSize - The processor cache-line size.
+    pNumberOfProcessors - Maximum number of processors per group.
+
+Return:
+
+    HRESULT - E_OUTOFMEMORY
+
+--*/
+{
+    SYSTEM_INFO     SystemInfo = { };
+
+    GetSystemInfo(&SystemInfo);
+    *pNumberOfProcessors = SystemInfo.dwNumberOfProcessors;
+    *pCacheLineSize = SYSTEM_CACHE_ALIGNMENT_SIZE;
+
+    return S_OK;
+}
\ No newline at end of file
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/IISLib/precomp.h b/src/IISIntegration/src/AspNetCoreModuleV2/IISLib/precomp.h
new file mode 100644
index 0000000000000000000000000000000000000000..9cccea4045571a33c659db79b7515c9bb18b55cf
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/IISLib/precomp.h
@@ -0,0 +1,22 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#include <windows.h>
+#include <ahadmin.h>
+#pragma warning( disable:4127 )
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <atlcomcli.h>
+#include <strsafe.h>
+#include <intsafe.h>
+
+#include "macros.h"
+#include "stringu.h"
+#include "stringa.h"
+#include "dbgutil.h"
+#include "ntassert.h"
+#include "ahutil.h"
+#include "acache.h"
+//#include "base64.hxx"
+
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/IISLib/prime.h b/src/IISIntegration/src/AspNetCoreModuleV2/IISLib/prime.h
new file mode 100644
index 0000000000000000000000000000000000000000..6a6a88ed780ee2f49fdad3799217db645bd8fe48
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/IISLib/prime.h
@@ -0,0 +1,85 @@
+// 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 <math.h>
+#include <stdlib.h>
+
+//
+// Pre-calculated prime numbers (up to 10,049,369).
+//
+extern __declspec(selectany) const DWORD g_Primes [] = {
+    3, 7, 11, 17, 23, 29, 37, 47, 59, 71, 89, 107, 131, 163, 197, 239, 293, 353, 431, 521, 631,
+    761, 919, 1103, 1327, 1597, 1931, 2333, 2801, 3371, 4049, 4861, 5839, 7013, 8419, 10103,
+    12143, 14591, 17519, 21023, 25229, 30293, 36353, 43627, 52361, 62851, 75431, 90523, 108631,
+    130363, 156437, 187751, 225307, 270371, 324449, 389357, 467237, 560689, 672827, 807403,
+    968897, 1162687, 1395263, 1674319, 2009191, 2411033, 2893249, 3471899, 4166287, 4999559,
+    5999471, 7199369, 7849369, 8649369, 9249369, 10049369
+};
+
+class PRIME
+{
+public:
+
+    static
+    DWORD
+    GetPrime(
+        DWORD dwMinimum
+    )
+    {
+        //
+        // Try to use the precalculated numbers.
+        //
+        for ( DWORD Index = 0; Index < _countof( g_Primes ); Index++ )
+        {
+            DWORD dwCandidate = g_Primes[Index];
+            if ( dwCandidate >= dwMinimum )
+            {
+                return dwCandidate;
+            }
+        }
+
+        //
+        // Do calculation.
+        //
+        for ( DWORD dwCandidate = dwMinimum | 1;
+             dwCandidate < MAXDWORD; 
+             dwCandidate += 2 )
+        {
+            if ( IsPrime( dwCandidate ) )
+            {
+                return dwCandidate;
+            }
+        }
+        return dwMinimum;
+    }
+
+private:
+
+    static
+    BOOL
+    IsPrime(
+        DWORD dwCandidate
+    )
+    {
+        if ((dwCandidate & 1) == 0)
+        {
+            return ( dwCandidate == 2 );
+        }
+
+        DWORD dwMax = static_cast<DWORD>(sqrt(static_cast<double>(dwCandidate)));
+
+        for ( DWORD Index = 3; Index <= dwMax; Index += 2 )
+        {
+            if ( (dwCandidate % Index) == 0 )
+            {
+                return FALSE;
+            }
+        }
+        return TRUE;
+    }
+
+    PRIME() {}
+    ~PRIME() {}
+};
\ No newline at end of file
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/IISLib/pudebug.h b/src/IISIntegration/src/AspNetCoreModuleV2/IISLib/pudebug.h
new file mode 100644
index 0000000000000000000000000000000000000000..7b0e35da0f1714f2c4fa62531b3018f3c93a3d99
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/IISLib/pudebug.h
@@ -0,0 +1,736 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+# ifndef _PUDEBUG_H_
+# define _PUDEBUG_H_
+
+#ifndef _NO_TRACING_
+# define _NO_TRACING_
+#endif // _NO_TRACING_
+
+/************************************************************
+ *     Include Headers
+ ************************************************************/
+
+# ifdef __cplusplus
+extern "C" {
+# endif // __cplusplus
+
+# include <windows.h>
+
+# ifndef dllexp
+# define dllexp   __declspec( dllexport)
+# endif // dllexp
+
+#include <specstrings.h>
+
+#ifndef IN_OUT
+#define IN_OUT __inout
+#endif
+
+/***********************************************************
+ *    Macros
+ ************************************************************/
+
+enum  PRINT_REASONS {
+    PrintNone     = 0x0,   // Nothing to be printed
+    PrintError    = 0x1,   // An error message
+    PrintWarning  = 0x2,   // A  warning message
+    PrintLog      = 0x3,   // Just logging. Indicates a trace of where ...
+    PrintMsg      = 0x4,   // Echo input message
+    PrintCritical = 0x5,   // Print and Exit
+    PrintAssertion= 0x6    // Printing for an assertion failure
+  };
+
+
+enum  DEBUG_OUTPUT_FLAGS {
+    DbgOutputNone     = 0x0,            // None
+    DbgOutputKdb      = 0x1,            // Output to Kernel Debugger
+    DbgOutputLogFile  = 0x2,            // Output to LogFile
+    DbgOutputTruncate = 0x4,            // Truncate Log File if necessary
+    DbgOutputStderr   = 0x8,            // Send output to std error
+    DbgOutputBackup   = 0x10,           // Make backup of debug file ?
+    DbgOutputMemory   = 0x20,           // Dump to memory buffer
+    DbgOutputAll      = 0xFFFFFFFF      // All the bits set.
+  };
+
+
+# define MAX_LABEL_LENGTH                 ( 100)
+
+
+// The following flags are used internally to track what level of tracing we
+// are currently using. Bitmapped for extensibility.
+#define DEBUG_FLAG_ODS          0x00000001
+//#define DEBUG_FLAG_INFO         0x00000002
+//#define DEBUG_FLAG_WARN         0x00000004
+//#define DEBUG_FLAG_ERROR        0x00000008
+// The following are used internally to determine whether to log or not based
+// on what the current state is
+//#define DEBUG_FLAGS_INFO        (DEBUG_FLAG_ODS | DEBUG_FLAG_INFO)
+//#define DEBUG_FLAGS_WARN        (DEBUG_FLAG_ODS | DEBUG_FLAG_INFO | DEBUG_FLAG_WARN)
+//#define DEBUG_FLAGS_ERROR       (DEBUG_FLAG_ODS | DEBUG_FLAG_INFO | DEBUG_FLAG_WARN | DEBUG_FLAG_ERROR)
+
+#define DEBUG_FLAGS_ANY         (DEBUG_FLAG_INFO | DEBUG_FLAG_WARN | DEBUG_FLAG_ERROR)
+
+//
+// user of DEBUG infrastructure may choose unique variable name for DEBUG_FLAGS
+// that's specially useful for cases where DEBUG infrastructure is used within
+// static library (static library may prefer to maintain it's own DebugFlags independent
+// on the main program it links to
+//
+#ifndef DEBUG_FLAGS_VAR
+#define DEBUG_FLAGS_VAR g_dwDebugFlags
+#endif
+
+extern
+#ifdef __cplusplus
+"C"
+# endif // _cplusplus
+ DWORD  DEBUG_FLAGS_VAR ;           // Debugging Flags
+
+# define DECLARE_DEBUG_VARIABLE()
+
+# define SET_DEBUG_FLAGS( dwFlags)         DEBUG_FLAGS_VAR = dwFlags
+# define GET_DEBUG_FLAGS()                 ( DEBUG_FLAGS_VAR )
+
+# define LOAD_DEBUG_FLAGS_FROM_REG(hkey, dwDefault)  \
+             DEBUG_FLAGS_VAR = PuLoadDebugFlagsFromReg((hkey), (dwDefault))
+
+# define LOAD_DEBUG_FLAGS_FROM_REG_STR(pszRegKey, dwDefault)  \
+             DEBUG_FLAGS_VAR = PuLoadDebugFlagsFromRegStr((pszRegKey), (dwDefault))
+
+# define SAVE_DEBUG_FLAGS_IN_REG(hkey, dwDbg)  \
+               PuSaveDebugFlagsInReg((hkey), (dwDbg))
+
+# define DEBUG_IF( arg, s)     if ( DEBUG_ ## arg & GET_DEBUG_FLAGS()) { \
+                                       s \
+                                } else {}
+
+# define IF_DEBUG( arg)        if ( DEBUG_## arg & GET_DEBUG_FLAGS())
+
+
+/*++
+  class DEBUG_PRINTS
+
+  This class is responsible for printing messages to log file / kernel debugger
+
+  Currently the class supports only member functions for <ANSI> char.
+   ( not unicode-strings).
+
+--*/
+
+
+typedef struct _DEBUG_PRINTS {
+
+    CHAR         m_rgchLabel[MAX_LABEL_LENGTH];
+    CHAR         m_rgchLogFilePath[MAX_PATH];
+    CHAR         m_rgchLogFileName[MAX_PATH];
+    HANDLE       m_LogFileHandle;
+    HANDLE       m_StdErrHandle;
+    BOOL         m_fInitialized;
+    BOOL         m_fBreakOnAssert;
+    DWORD        m_dwOutputFlags;
+    VOID        *m_pMemoryLog;
+} DEBUG_PRINTS, FAR * LPDEBUG_PRINTS;
+
+
+LPDEBUG_PRINTS
+PuCreateDebugPrintsObject(
+   IN const char * pszPrintLabel,
+   IN DWORD  dwOutputFlags);
+
+//
+// frees the debug prints object and closes any file if necessary.
+//  Returns NULL on success or returns pDebugPrints on failure.
+//
+LPDEBUG_PRINTS
+PuDeleteDebugPrintsObject(
+   IN_OUT LPDEBUG_PRINTS  pDebugPrints);
+
+
+VOID
+PuDbgPrint(
+   IN_OUT LPDEBUG_PRINTS   pDebugPrints,
+   IN const char *         pszFilePath,
+   IN int                  nLineNum,
+   IN const char *         pszFunctionName,
+   IN const char *         pszFormat,
+   ...);
+                           // arglist
+VOID
+PuDbgPrintW(
+   IN_OUT LPDEBUG_PRINTS   pDebugPrints,
+   IN const char *         pszFilePath,
+   IN int                  nLineNum,
+   IN const char *         pszFunctionName,
+   IN const WCHAR *        pszFormat,
+   ...);                               // arglist
+
+// PuDbgPrintError is similar to PuDbgPrint() but allows
+// one to print error code in friendly manner
+VOID
+PuDbgPrintError(
+   IN_OUT LPDEBUG_PRINTS   pDebugPrints,
+   IN const char *         pszFilePath,
+   IN int                  nLineNum,
+   IN const char *         pszFunctionName,
+   IN DWORD                dwError,
+   IN const char *         pszFormat,
+   ...);                               // arglist
+
+/*++
+  PuDbgDump() does not do any formatting of output.
+  It just dumps the given message onto the debug destinations.
+--*/
+VOID
+PuDbgDump(
+   IN_OUT LPDEBUG_PRINTS   pDebugPrints,
+   IN const char *         pszFilePath,
+   IN int                  nLineNum,
+   IN const char *         pszFunctionName,
+   IN const char *         pszDump
+   );
+
+//
+// PuDbgAssertFailed() *must* be __cdecl to properly capture the
+// thread context at the time of the failure.
+//
+
+INT
+__cdecl
+PuDbgAssertFailed(
+   IN_OUT LPDEBUG_PRINTS   pDebugPrints,
+   IN const char *         pszFilePath,
+   IN int                  nLineNum,
+   IN const char *         pszFunctionName,
+   IN const char *         pszExpression,
+   IN const char *         pszMessage);
+
+INT
+WINAPI
+PuDbgPrintAssertFailed(
+   IN_OUT LPDEBUG_PRINTS   pDebugPrints,
+   IN const char *         pszFilePath,
+   IN int                  nLineNum,
+   IN const char *         pszFunctionName,
+   IN const char *         pszExpression,
+   IN const char *         pszMessage);
+
+VOID
+PuDbgCaptureContext (
+    OUT PCONTEXT ContextRecord
+    );
+
+VOID
+PuDbgPrintCurrentTime(
+    IN_OUT LPDEBUG_PRINTS         pDebugPrints,
+    IN const char *               pszFilePath,
+    IN int                        nLineNum,
+    IN const char *               pszFunctionName
+    );
+
+VOID
+PuSetDbgOutputFlags(
+   IN_OUT LPDEBUG_PRINTS   pDebugPrints,
+   IN DWORD                dwFlags);
+
+DWORD
+PuGetDbgOutputFlags(
+   IN const LPDEBUG_PRINTS       pDebugPrints);
+
+
+//
+// Following functions return Win32 error codes.
+// NO_ERROR if success
+//
+
+DWORD
+PuOpenDbgPrintFile(
+   IN_OUT LPDEBUG_PRINTS   pDebugPrints,
+   IN const char *         pszFileName,
+   IN const char *         pszPathForFile);
+
+DWORD
+PuReOpenDbgPrintFile(
+   IN_OUT LPDEBUG_PRINTS   pDebugPrints);
+
+DWORD
+PuCloseDbgPrintFile(
+   IN_OUT LPDEBUG_PRINTS   pDebugPrints);
+
+DWORD
+PuOpenDbgMemoryLog(
+    IN_OUT LPDEBUG_PRINTS   pDebugPrints);
+
+DWORD
+PuCloseDbgMemoryLog(
+    IN_OUT LPDEBUG_PRINTS   pDebugPrints);
+
+DWORD
+PuLoadDebugFlagsFromReg(IN HKEY hkey, IN DWORD dwDefault);
+
+DWORD
+PuLoadDebugFlagsFromRegStr(IN LPCSTR pszRegKey, IN DWORD dwDefault);
+
+DWORD
+PuSaveDebugFlagsInReg(IN HKEY hkey, IN DWORD dwDbg);
+
+
+# define PuPrintToKdb( pszOutput)    \
+                    if ( pszOutput != NULL)   {   \
+                        OutputDebugString( pszOutput);  \
+                    } else {}
+
+
+
+# ifdef __cplusplus
+};
+# endif // __cplusplus
+
+// begin_user_unmodifiable
+
+
+
+/***********************************************************
+ *    Macros
+ ************************************************************/
+
+
+extern
+#ifdef __cplusplus
+"C"
+# endif // _cplusplus
+DEBUG_PRINTS  *  g_pDebug;        // define a global debug variable
+
+# if DBG
+
+// For the CHK build we want ODS enabled. For an explanation of these flags see
+// the comment just after the definition of DBG_CONTEXT
+# define DECLARE_DEBUG_PRINTS_OBJECT()                      \
+         DEBUG_PRINTS  *  g_pDebug = NULL;                  \
+         DWORD  DEBUG_FLAGS_VAR = DEBUG_FLAG_ERROR;
+
+#else // !DBG
+
+# define DECLARE_DEBUG_PRINTS_OBJECT()          \
+         DEBUG_PRINTS  *  g_pDebug = NULL;      \
+         DWORD  DEBUG_FLAGS_VAR = 0;
+
+#endif // !DBG
+
+
+//
+// Call the following macro as part of your initialization for program
+//  planning to use the debugging class.
+//
+/** DEBUGDEBUG
+# define CREATE_DEBUG_PRINT_OBJECT( pszLabel)  \
+        g_pDebug = PuCreateDebugPrintsObject( pszLabel, DEFAULT_OUTPUT_FLAGS);\
+         if  ( g_pDebug == NULL) {   \
+               OutputDebugStringA( "Unable to Create Debug Print Object \n"); \
+         }
+*/
+
+//
+// Call the following macro once as part of the termination of program
+//    which uses the debugging class.
+//
+# define DELETE_DEBUG_PRINT_OBJECT( )  \
+        g_pDebug = PuDeleteDebugPrintsObject( g_pDebug);
+
+
+# define VALID_DEBUG_PRINT_OBJECT()     \
+        ( ( g_pDebug != NULL) && g_pDebug->m_fInitialized)
+
+
+//
+//  Use the DBG_CONTEXT without any surrounding braces.
+//  This is used to pass the values for global DebugPrintObject
+//     and File/Line information
+//
+//# define DBG_CONTEXT        g_pDebug, __FILE__, __LINE__, __FUNCTION__
+
+// The 3 main tracing macros, each one corresponds to a different level of
+// tracing
+
+// The 3 main tracing macros, each one corresponds to a different level of
+// tracing
+//# define DBGINFO(args)      {if (DEBUG_FLAGS_VAR & DEBUG_FLAGS_INFO) { PuDbgPrint args; }}
+//# define DBGWARN(args)      {if (DEBUG_FLAGS_VAR & DEBUG_FLAGS_WARN) { PuDbgPrint args; }}
+//# define DBGERROR(args)     {if (DEBUG_FLAGS_VAR & DEBUG_FLAGS_ERROR) { PuDbgPrint args; }}
+
+# define DBGINFOW(args)     {if (DEBUG_FLAGS_VAR & DEBUG_FLAGS_INFO) { PuDbgPrintW args; }}
+# define DBGWARNW(args)     {if (DEBUG_FLAGS_VAR & DEBUG_FLAGS_WARN) { PuDbgPrintW args; }}
+# define DBGERRORW(args)    {if (DEBUG_FLAGS_VAR & DEBUG_FLAGS_ERROR) { PuDbgPrintW args; }}
+
+
+//
+//  DBGPRINTF() is printing function ( much like printf) but always called
+//    with the DBG_CONTEXT as follows
+//   DBGPRINTF( ( DBG_CONTEXT, format-string, arguments for format list));
+//
+# define DBGPRINTF DBGINFO
+
+//
+//  DPERROR() is printing function ( much like printf) but always called
+//    with the DBG_CONTEXT as follows
+//   DPERROR( ( DBG_CONTEXT, error, format-string,
+//                      arguments for format list));
+//
+# define DPERROR( args)       {if (DEBUG_FLAGS_VAR & DEBUG_FLAGS_ERROR) { PuDbgPrintError args; }}
+
+# if DBG
+
+# define DBG_CODE(s)          s          /* echoes code in debugging mode */
+
+// The same 3 main tracing macros however in this case the macros are only compiled
+// into the CHK build. This is necessary because some tracing info used functions or
+// variables which are not compiled into the FRE build.
+# define CHKINFO(args)      { PuDbgPrint args; }
+# define CHKWARN(args)      { PuDbgPrint args; }
+# define CHKERROR(args)     { PuDbgPrint args; }
+
+# define CHKINFOW(args)     { PuDbgPrintW args; }
+# define CHKWARNW(args)     { PuDbgPrintW args; }
+# define CHKERRORW(args)    { PuDbgPrintW args; }
+
+
+#ifndef DBG_ASSERT
+# ifdef _PREFAST_
+#  define DBG_ASSERT(exp)                         ((void)0) /* Do Nothing */
+#  define DBG_ASSERT_MSG(exp, pszMsg)             ((void)0) /* Do Nothing */
+#  define DBG_REQUIRE( exp)                       ((void) (exp))
+# else  // !_PREFAST_
+#  define DBG_ASSERT( exp )                  \
+    ( (VOID)( ( exp ) || ( DebugBreak(),    \
+                           PuDbgPrintAssertFailed( DBG_CONTEXT, #exp, "" ) ) ) )
+
+#  define DBG_ASSERT_MSG( exp, pszMsg)       \
+    ( (VOID)( ( exp ) || ( DebugBreak(),    \
+                           PuDbgPrintAssertFailed( DBG_CONTEXT, #exp, pszMsg ) ) ) )
+
+#  define DBG_REQUIRE( exp )                 \
+    DBG_ASSERT( exp )
+# endif // !_PREFAST_
+#endif
+
+
+# define DBG_LOG()      PuDbgPrint( DBG_CONTEXT, "\n" )
+
+# define DBG_OPEN_LOG_FILE( pszFile, pszPath )  \
+                        PuOpenDbgPrintFile( g_pDebug, (pszFile), (pszPath) )
+
+# define DBG_CLOSE_LOG_FILE( )  \
+                        PuCloseDbgPrintFile( g_pDebug )
+
+# define DBG_OPEN_MEMORY_LOG( ) \
+                        PuOpenDbgMemoryLog( g_pDebug )
+
+
+# define DBGDUMP( args )            PuDbgDump  args
+
+# define DBGPRINT_CURRENT_TIME()    PuDbgPrintCurrentTime( DBG_CONTEXT )
+
+# else // !DBG
+
+# define DBG_CODE(s)        ((void)0) /* Do Nothing */
+
+# define CHKINFO(args)      ((void)0) /* Do Nothing */
+# define CHKWARN(args)      ((void)0) /* Do Nothing */
+# define CHKERROR(args)     ((void)0) /* Do Nothing */
+
+# define CHKINFOW(args)     ((void)0) /* Do Nothing */
+# define CHKWARNW(args)     ((void)0) /* Do Nothing */
+# define CHKERRORW(args)    ((void)0) /* Do Nothing */
+
+#ifndef DBG_ASSERT
+# define DBG_ASSERT(exp)                         ((void)0) /* Do Nothing */
+
+# define DBG_ASSERT_MSG(exp, pszMsg)             ((void)0) /* Do Nothing */
+
+# define DBG_REQUIRE( exp)                       ((void) (exp))
+#endif // !DBG_ASSERT
+
+# define DBGDUMP( args)                          ((void)0) /* Do nothing */
+
+# define DBG_LOG()                               ((void)0) /* Do Nothing */
+
+# define DBG_OPEN_LOG_FILE( pszFile, pszPath)    ((void)0) /* Do Nothing */
+
+# define DBG_OPEN_MEMORY_LOG()                   ((void)0) /* Do Nothing */
+
+# define DBG_CLOSE_LOG_FILE()                    ((void)0) /* Do Nothing */
+
+# define DBGPRINT_CURRENT_TIME()                 ((void)0) /* Do Nothing */
+
+# endif // !DBG
+
+
+// end_user_unmodifiable
+
+// begin_user_unmodifiable
+
+
+#ifdef ASSERT
+# undef ASSERT
+#endif
+
+
+# define ASSERT( exp)           DBG_ASSERT( exp)
+
+
+// end_user_unmodifiable
+
+// begin_user_modifiable
+
+//
+//  Debugging constants consist of two pieces.
+//  All constants in the range 0x0 to 0x8000 are reserved
+//  User extensions may include additional constants (bit flags)
+//
+
+# define DEBUG_API_ENTRY                  0x00000001L
+# define DEBUG_API_EXIT                   0x00000002L
+# define DEBUG_INIT_CLEAN                 0x00000004L
+# define DEBUG_ERROR                      0x00000008L
+
+                   // End of Reserved Range
+# define DEBUG_RESERVED                   0x00000FFFL
+
+// end_user_modifiable
+
+
+
+/***********************************************************
+ *    Platform Type related variables and macros
+ ************************************************************/
+
+//
+// Enum for product types
+//
+
+typedef enum _PLATFORM_TYPE {
+
+    PtInvalid = 0,                 // Invalid
+    PtNtWorkstation = 1,           // NT Workstation
+    PtNtServer = 2,                // NT Server
+
+} PLATFORM_TYPE;
+
+//
+// IISGetPlatformType is the function used to the platform type
+//
+
+extern
+#ifdef __cplusplus
+"C"
+# endif // _cplusplus
+PLATFORM_TYPE
+IISGetPlatformType(
+        VOID
+        );
+
+//
+// External Macros
+//
+
+#define InetIsNtServer( _pt )           ((_pt) == PtNtServer)
+#define InetIsNtWksta( _pt )            ((_pt) == PtNtWorkstation)
+#define InetIsValidPT(_pt)              ((_pt) != PtInvalid)
+
+extern
+#ifdef __cplusplus
+"C"
+# endif // _cplusplus
+PLATFORM_TYPE    g_PlatformType;
+
+
+// Use the DECLARE_PLATFORM_TYPE macro to declare the platform type
+#define DECLARE_PLATFORM_TYPE()  \
+   PLATFORM_TYPE    g_PlatformType = PtInvalid;
+
+// Use the INITIALIZE_PLATFORM_TYPE to init the platform type
+// This should typically go inside the DLLInit or equivalent place.
+#define INITIALIZE_PLATFORM_TYPE()  \
+   g_PlatformType = IISGetPlatformType();
+
+//
+// Additional Macros to use the Platform Type
+//
+
+#define TsIsNtServer( )         InetIsNtServer(g_PlatformType)
+#define TsIsNtWksta( )          InetIsNtWksta(g_PlatformType)
+#define IISIsValidPlatform()    InetIsValidPT(g_PlatformType)
+#define IISPlatformType()       (g_PlatformType)
+
+
+/***********************************************************
+ *    Some utility functions for Critical Sections
+ ************************************************************/
+
+//
+// IISSetCriticalSectionSpinCount() provides a thunk for the
+// original NT4.0sp3 API SetCriticalSectionSpinCount() for CS with Spin counts
+// Users of this function should definitely dynlink with kernel32.dll,
+// Otherwise errors will surface to a large extent
+//
+extern
+# ifdef __cplusplus
+"C"
+# endif // _cplusplus
+DWORD
+IISSetCriticalSectionSpinCount(
+    LPCRITICAL_SECTION lpCriticalSection,
+    DWORD dwSpinCount
+);
+
+
+//
+// Macro for the calls to SetCriticalSectionSpinCount()
+//
+# define SET_CRITICAL_SECTION_SPIN_COUNT( lpCS, dwSpins) \
+  IISSetCriticalSectionSpinCount( (lpCS), (dwSpins))
+
+//
+// IIS_DEFAULT_CS_SPIN_COUNT is the default value of spins used by
+//  Critical sections defined within IIS.
+// NYI: We should have to switch the individual values based on experiments!
+// Current value is an arbitrary choice
+//
+# define IIS_DEFAULT_CS_SPIN_COUNT   (1000)
+
+//
+// Initializes a critical section and sets its spin count
+// to IIS_DEFAULT_CS_SPIN_COUNT.  Equivalent to
+// InitializeCriticalSectionAndSpinCount(lpCS, IIS_DEFAULT_CS_SPIN_COUNT),
+// but provides a safe thunking layer for older systems that don't provide
+// this API.
+//
+extern
+# ifdef __cplusplus
+"C"
+# endif // _cplusplus
+BOOL
+IISInitializeCriticalSection(
+    LPCRITICAL_SECTION lpCriticalSection
+);
+
+//
+// Macro for the calls to InitializeCriticalSection()
+//
+# define INITIALIZE_CRITICAL_SECTION(lpCS) IISInitializeCriticalSection(lpCS)
+
+# endif  /* _DEBUG_HXX_ */
+
+//
+// The following macros allow the automatic naming of certain Win32 objects.
+// See IIS\SVCS\IISRTL\WIN32OBJ.C for details on the naming convention.
+//
+// Set IIS_NAMED_WIN32_OBJECTS to a non-zero value to enable named events,
+// semaphores, and mutexes.
+//
+
+#if DBG
+#define IIS_NAMED_WIN32_OBJECTS 1
+#else
+#define IIS_NAMED_WIN32_OBJECTS 0
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+HANDLE
+PuDbgCreateEvent(
+    __in LPSTR FileName,
+    IN ULONG LineNumber,
+    __in LPSTR MemberName,
+    IN PVOID Address,
+    IN BOOL ManualReset,
+    IN BOOL InitialState
+    );
+
+HANDLE
+PuDbgCreateSemaphore(
+    __in LPSTR FileName,
+    IN ULONG LineNumber,
+    __in LPSTR MemberName,
+    IN PVOID Address,
+    IN LONG InitialCount,
+    IN LONG MaximumCount
+    );
+
+HANDLE
+PuDbgCreateMutex(
+    __in LPSTR FileName,
+    IN ULONG LineNumber,
+    __in LPSTR MemberName,
+    IN PVOID Address,
+    IN BOOL InitialOwner
+    );
+
+#ifdef __cplusplus
+}   // extern "C"
+#endif
+
+#if IIS_NAMED_WIN32_OBJECTS
+
+#define IIS_CREATE_EVENT( membername, address, manual, state )              \
+    PuDbgCreateEvent(                                                       \
+        (LPSTR)__FILE__,                                                    \
+        (ULONG)__LINE__,                                                    \
+        (membername),                                                       \
+        (PVOID)(address),                                                   \
+        (manual),                                                           \
+        (state)                                                             \
+        )
+
+#define IIS_CREATE_SEMAPHORE( membername, address, initial, maximum )       \
+    PuDbgCreateSemaphore(                                                   \
+        (LPSTR)__FILE__,                                                    \
+        (ULONG)__LINE__,                                                    \
+        (membername),                                                       \
+        (PVOID)(address),                                                   \
+        (initial),                                                          \
+        (maximum)                                                           \
+        )
+
+#define IIS_CREATE_MUTEX( membername, address, initial )                     \
+    PuDbgCreateMutex(                                                       \
+        (LPSTR)__FILE__,                                                    \
+        (ULONG)__LINE__,                                                    \
+        (membername),                                                       \
+        (PVOID)(address),                                                   \
+        (initial)                                                           \
+        )
+
+#else   // !IIS_NAMED_WIN32_OBJECTS
+
+#define IIS_CREATE_EVENT( membername, address, manual, state )              \
+    CreateEventA(                                                           \
+        NULL,                                                               \
+        (manual),                                                           \
+        (state),                                                            \
+        NULL                                                                \
+        )
+
+#define IIS_CREATE_SEMAPHORE( membername, address, initial, maximum )       \
+    CreateSemaphoreA(                                                       \
+        NULL,                                                               \
+        (initial),                                                          \
+        (maximum),                                                          \
+        NULL                                                                \
+        )
+
+#define IIS_CREATE_MUTEX( membername, address, initial )                     \
+    CreateMutexA(                                                           \
+        NULL,                                                               \
+        (initial),                                                          \
+        NULL                                                                \
+        )
+
+#endif  // IIS_NAMED_WIN32_OBJECTS
+
+
+/************************ End of File ***********************/
+
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/IISLib/reftrace.c b/src/IISIntegration/src/AspNetCoreModuleV2/IISLib/reftrace.c
new file mode 100644
index 0000000000000000000000000000000000000000..c1b2e13a6edeec9a65bcad2d7e61cbbd2bdb1ff7
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/IISLib/reftrace.c
@@ -0,0 +1,229 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#include <windows.h>
+#include "dbgutil.h"
+#include "pudebug.h"
+#include "reftrace.h"
+
+
+PTRACE_LOG
+CreateRefTraceLog(
+    IN LONG LogSize,
+    IN LONG ExtraBytesInHeader
+    )
+/*++
+
+Routine Description:
+
+    Creates a new (empty) ref count trace log buffer.
+
+Arguments:
+
+    LogSize - The number of entries in the log.
+
+    ExtraBytesInHeader - The number of extra bytes to include in the
+        log header. This is useful for adding application-specific
+        data to the log.
+
+Return Value:
+
+    PTRACE_LOG - Pointer to the newly created log if successful,
+        NULL otherwise.
+
+--*/
+{
+
+    return CreateTraceLog(
+               LogSize,
+               ExtraBytesInHeader,
+               sizeof(REF_TRACE_LOG_ENTRY)
+               );
+
+}   // CreateRefTraceLog
+
+
+VOID
+DestroyRefTraceLog(
+    IN PTRACE_LOG Log
+    )
+/*++
+
+Routine Description:
+
+    Destroys a ref count trace log buffer created with CreateRefTraceLog().
+
+Arguments:
+
+    Log - The ref count trace log buffer to destroy.
+
+Return Value:
+
+    None.
+
+--*/
+{
+
+    DestroyTraceLog( Log );
+
+}   // DestroyRefTraceLog
+
+
+//
+// N.B. For RtlCaptureBacktrace() to work properly, the calling function
+// *must* be __cdecl, and must have a "normal" stack frame. So, we decorate
+// WriteRefTraceLog[Ex]() with the __cdecl modifier and disable the frame
+// pointer omission (FPO) optimization.
+//
+
+//#pragma optimize( "y", off )    // disable frame pointer omission (FPO)
+#pragma optimize( "", off )    // disable frame pointer omission (FPO)
+
+LONG
+__cdecl
+WriteRefTraceLog(
+    IN PTRACE_LOG Log,
+    IN LONG NewRefCount,
+    IN CONST VOID * Context
+    )
+/*++
+
+Routine Description:
+
+    Writes a new entry to the specified ref count trace log. The entry
+    written contains the updated reference count and a stack backtrace
+    leading up to the current caller.
+
+Arguments:
+
+    Log - The log to write to.
+
+    NewRefCount - The updated reference count.
+
+    Context - An uninterpreted context to associate with the log entry.
+
+Return Value:
+
+    Index of entry in log.
+
+--*/
+{
+
+    return WriteRefTraceLogEx(
+        Log,
+        NewRefCount,
+        Context,
+        REF_TRACE_EMPTY_CONTEXT, // suppress use of optional extra contexts
+        REF_TRACE_EMPTY_CONTEXT,
+        REF_TRACE_EMPTY_CONTEXT
+        );
+
+}   // WriteRefTraceLog
+
+
+
+
+LONG
+__cdecl
+WriteRefTraceLogEx(
+    IN PTRACE_LOG Log,
+    IN LONG NewRefCount,
+    IN CONST VOID * Context,
+    IN CONST VOID * Context1, // optional extra context
+    IN CONST VOID * Context2, // optional extra context
+    IN CONST VOID * Context3  // optional extra context
+    )
+/*++
+
+Routine Description:
+
+    Writes a new "extended" entry to the specified ref count trace log.
+    The entry written contains the updated reference count, stack backtrace
+    leading up to the current caller and extra context information.
+
+Arguments:
+
+    Log - The log to write to.
+
+    NewRefCount - The updated reference count.
+
+    Context  - An uninterpreted context to associate with the log entry.
+    Context1 - An uninterpreted context to associate with the log entry.
+    Context2 - An uninterpreted context to associate with the log entry.
+    Context3 - An uninterpreted context to associate with the log entry.
+
+    NOTE Context1/2/3 are "optional" in that the caller may suppress
+    debug display of these values by passing REF_TRACE_EMPTY_CONTEXT
+    for each of them.
+
+Return Value:
+
+    Index of entry in log.
+
+--*/
+{
+
+    REF_TRACE_LOG_ENTRY entry;
+    ULONG hash;
+    DWORD cStackFramesSkipped;
+
+    //
+    // Initialize the entry.
+    //
+
+    RtlZeroMemory(
+        &entry,
+        sizeof(entry)
+        );
+
+    //
+    //  Set log entry members.
+    //
+
+    entry.NewRefCount = NewRefCount;
+    entry.Context = Context;
+    entry.Thread = GetCurrentThreadId();
+    entry.Context1 = Context1;
+    entry.Context2 = Context2;
+    entry.Context3 = Context3;
+
+    //
+    // Capture the stack backtrace. Normally, we skip two stack frames:
+    // one for this routine, and one for RtlCaptureBacktrace() itself.
+    // For non-Ex callers who come in via WriteRefTraceLog,
+    // we skip three stack frames.
+    //
+
+    if (    entry.Context1 == REF_TRACE_EMPTY_CONTEXT
+         && entry.Context2 == REF_TRACE_EMPTY_CONTEXT
+         && entry.Context3 == REF_TRACE_EMPTY_CONTEXT
+         ) {
+
+         cStackFramesSkipped = 2;
+
+    } else {
+
+         cStackFramesSkipped = 1;
+
+    }
+
+    RtlCaptureStackBackTrace(
+        cStackFramesSkipped,
+        REF_TRACE_LOG_STACK_DEPTH,
+        entry.Stack,
+        &hash
+        );
+
+    //
+    // Write it to the log.
+    //
+
+    return WriteTraceLog(
+        Log,
+        &entry
+        );
+
+}   // WriteRefTraceLogEx
+
+#pragma optimize( "", on )      // restore frame pointer omission (FPO)
+
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/IISLib/reftrace.h b/src/IISIntegration/src/AspNetCoreModuleV2/IISLib/reftrace.h
new file mode 100644
index 0000000000000000000000000000000000000000..e90ca0444a719b2830eb3b2a1be825e3e63072f1
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/IISLib/reftrace.h
@@ -0,0 +1,87 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#ifndef _REFTRACE_H_
+#define _REFTRACE_H_
+
+
+#if defined(__cplusplus)
+extern "C" {
+#endif  // __cplusplus
+
+#include <Windows.h>
+#include "tracelog.h"
+
+//
+// This is the number of stack backtrace values captured in each
+// trace log entry. This value is chosen to make the log entry
+// exactly twelve dwords long, making it a bit easier to interpret
+// from within the debugger without the debugger extension.
+//
+
+#define REF_TRACE_LOG_STACK_DEPTH   9
+
+// No-op value for the Context1,2,3 parameters of WriteRefTraceLogEx
+//#define REF_TRACE_EMPTY_CONTEXT ((PVOID) -1)
+#define REF_TRACE_EMPTY_CONTEXT NULL
+
+
+//
+// This defines the entry written to the trace log.
+//
+
+typedef struct _REF_TRACE_LOG_ENTRY {
+
+    LONG NewRefCount;
+    CONST VOID * Context;
+    CONST VOID * Context1;
+    CONST VOID * Context2;
+    CONST VOID * Context3;
+    DWORD Thread;
+    PVOID Stack[REF_TRACE_LOG_STACK_DEPTH];
+
+} REF_TRACE_LOG_ENTRY, *PREF_TRACE_LOG_ENTRY;
+
+
+//
+// Manipulators.
+//
+
+PTRACE_LOG
+CreateRefTraceLog(
+    IN LONG LogSize,
+    IN LONG ExtraBytesInHeader
+    );
+
+VOID
+DestroyRefTraceLog(
+    IN PTRACE_LOG Log
+    );
+
+LONG
+__cdecl
+WriteRefTraceLog(
+    IN PTRACE_LOG Log,
+    IN LONG NewRefCount,
+    IN CONST VOID * Context
+    );
+
+LONG
+__cdecl
+WriteRefTraceLogEx(
+    IN PTRACE_LOG Log,
+    IN LONG NewRefCount,
+    IN CONST VOID * Context,
+    IN CONST VOID * Context1,
+    IN CONST VOID * Context2,
+    IN CONST VOID * Context3
+    );
+
+
+#if defined(__cplusplus)
+}   // extern "C"
+#endif  // __cplusplus
+
+
+#endif  // _REFTRACE_H_
+
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/IISLib/rwlock.h b/src/IISIntegration/src/AspNetCoreModuleV2/IISLib/rwlock.h
new file mode 100644
index 0000000000000000000000000000000000000000..dc7ccf834bef129bb7eae8c8a4f36eaf34dd5ccd
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/IISLib/rwlock.h
@@ -0,0 +1,193 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#pragma once
+
+#if (_WIN32_WINNT < 0x600)
+
+//
+// XP implementation.
+//
+class CWSDRWLock
+{
+public:
+
+    CWSDRWLock()
+        : m_bInited(FALSE)
+    {
+    }
+
+    ~CWSDRWLock()
+    {
+        if (m_bInited)
+        {
+            DeleteCriticalSection(&m_rwLock.critsec);
+            CloseHandle(m_rwLock.ReadersDoneEvent);
+        }
+    }
+
+    BOOL QueryInited() const
+    {
+        return m_bInited;
+    }
+
+    HRESULT Init()
+    {
+        HRESULT hr = S_OK;
+    
+        if (FALSE == m_bInited)
+        {
+            m_rwLock.fWriterWaiting = FALSE;
+            m_rwLock.LockCount = 0;
+            if ( !InitializeCriticalSectionAndSpinCount( &m_rwLock.critsec, 0 )) 
+            {
+                DWORD dwError  = GetLastError();
+                hr = HRESULT_FROM_WIN32(dwError);
+                return hr;
+            }
+
+            m_rwLock.ReadersDoneEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+            if( NULL == m_rwLock.ReadersDoneEvent ) 
+            {
+                DWORD dwError  = GetLastError();
+                hr = HRESULT_FROM_WIN32(dwError);
+                DeleteCriticalSection(&m_rwLock.critsec);
+                return hr;
+            }
+            m_bInited = TRUE;
+        }
+
+        return hr;
+    }
+    
+    void SharedAcquire()
+    {
+        EnterCriticalSection(&m_rwLock.critsec);
+        InterlockedIncrement(&m_rwLock.LockCount);
+        LeaveCriticalSection(&m_rwLock.critsec);
+    }
+    
+    void SharedRelease()
+    {
+        ReleaseRWLock();
+    }
+    
+    void ExclusiveAcquire()
+    {
+        EnterCriticalSection( &m_rwLock.critsec );
+    
+        m_rwLock.fWriterWaiting = TRUE;
+    
+        // check if there are any readers active
+        if ( InterlockedExchangeAdd( &m_rwLock.LockCount, 0 ) > 0 ) 
+        {
+            //
+            // Wait for all the readers to get done..
+            //
+            WaitForSingleObject( m_rwLock.ReadersDoneEvent, INFINITE );
+        }
+        m_rwLock.LockCount = -1;
+    }
+    
+    void ExclusiveRelease()
+    {
+        ReleaseRWLock();
+    }
+
+private:
+
+    BOOL m_bInited;
+
+    typedef struct _RW_LOCK 
+    {
+        BOOL  fWriterWaiting; // Is a writer waiting on the lock?
+        LONG LockCount;
+        CRITICAL_SECTION critsec;
+        HANDLE ReadersDoneEvent;
+    } RW_LOCK, *PRW_LOCK;
+
+    RW_LOCK m_rwLock;
+
+private:
+
+    void ReleaseRWLock()
+    {
+        LONG Count = InterlockedDecrement( &m_rwLock.LockCount );
+    
+        if ( 0 <= Count )
+        {
+            // releasing a read lock
+            if (( m_rwLock.fWriterWaiting ) && ( 0 == Count ))
+            {
+                SetEvent( m_rwLock.ReadersDoneEvent );
+            }
+        }
+        else 
+        {
+            // Releasing a write lock
+            m_rwLock.LockCount = 0;
+            m_rwLock.fWriterWaiting = FALSE;
+            LeaveCriticalSection(&m_rwLock.critsec);
+        }
+    }
+};
+
+#else
+
+//
+// Implementation for Windows Vista or greater.
+//
+class CWSDRWLock
+{
+public:
+
+    CWSDRWLock()
+    {
+        InitializeSRWLock(&m_rwLock);
+    }
+
+    BOOL QueryInited()
+    {
+        return TRUE;
+    }
+
+
+    HRESULT Init()
+    {
+        //
+        // Method defined to keep compatibility with CWSDRWLock class for XP.
+        //
+        return S_OK;
+    }
+
+    void SharedAcquire()
+    {
+        AcquireSRWLockShared(&m_rwLock);
+    }
+    
+    void SharedRelease()
+    {
+        ReleaseSRWLockShared(&m_rwLock);
+    }
+
+    void ExclusiveAcquire()
+    {
+        AcquireSRWLockExclusive(&m_rwLock);
+    }
+    
+    void ExclusiveRelease()
+    {
+        ReleaseSRWLockExclusive(&m_rwLock);
+    }
+
+private:
+
+    SRWLOCK m_rwLock;
+};
+
+#endif
+
+//
+// Rename the lock class to a more clear name.
+//
+typedef CWSDRWLock READ_WRITE_LOCK;
\ No newline at end of file
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/IISLib/stringa.cpp b/src/IISIntegration/src/AspNetCoreModuleV2/IISLib/stringa.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..29da773bcab8b01aafc175387da78bd70995125a
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/IISLib/stringa.cpp
@@ -0,0 +1,1767 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#include "precomp.h"
+
+STRA::STRA(
+    VOID
+) : m_cchLen( 0 )
+{
+    *( QueryStr() ) = '\0';
+}
+
+STRA::STRA(
+    __inout_ecount(cchInit) CHAR* pbInit,
+    __in DWORD cchInit
+) : m_Buff( pbInit, cchInit * sizeof( CHAR ) ),
+    m_cchLen(0)
+/*++
+    Description:
+
+        Used by STACK_STRA. Initially populates underlying buffer with pbInit.
+
+        pbInit is not freed.
+
+    Arguments:
+
+        pbInit - initial memory to use
+        cchInit - count, in characters, of pbInit
+
+    Returns:
+
+        None.
+
+--*/
+{
+    _ASSERTE( NULL != pbInit );
+    _ASSERTE( cchInit > 0 );
+    _ASSERTE( pbInit[0] == '\0' );
+}
+
+BOOL
+STRA::IsEmpty(
+    VOID
+) const
+{
+    return ( m_cchLen == 0 );
+}
+
+BOOL
+STRA::Equals(
+    __in PCSTR  pszRhs,
+    __in BOOL   fIgnoreCase /*= FALSE*/
+) const
+{
+    _ASSERTE( NULL != pszRhs );
+
+    if( fIgnoreCase )
+    {
+        return ( 0 == _stricmp( QueryStr(), pszRhs ) );
+    }
+
+    return ( 0 == strcmp( QueryStr(), pszRhs ) );
+}
+
+BOOL
+STRA::Equals(
+    __in const STRA *   pstrRhs,
+    __in BOOL           fIgnoreCase /*= FALSE*/
+) const
+{
+    _ASSERTE( NULL != pstrRhs );
+    return Equals( pstrRhs->QueryStr(), fIgnoreCase );
+}
+
+BOOL
+STRA::Equals(
+    __in const STRA &  strRhs,
+    __in BOOL           fIgnoreCase /*= FALSE*/
+) const
+{
+    return Equals( strRhs.QueryStr(), fIgnoreCase );
+}
+
+DWORD
+STRA::QueryCB(
+    VOID
+) const
+//
+// Returns the number of bytes in the string excluding the terminating NULL
+//
+{
+    return m_cchLen * sizeof( CHAR );
+}
+
+DWORD
+STRA::QueryCCH(
+    VOID
+) const
+//
+//  Returns the number of characters in the string excluding the terminating NULL
+//
+{
+    return m_cchLen;
+}
+
+DWORD
+STRA::QuerySizeCCH(
+    VOID
+) const
+//
+// Returns size of the underlying storage buffer, in characters
+//
+{
+    return m_Buff.QuerySize() / sizeof( CHAR );
+}
+
+DWORD
+STRA::QuerySize(
+    VOID
+) const
+//
+//  Returns the size of the storage buffer in bytes
+//
+{
+    return m_Buff.QuerySize();
+}
+
+__nullterminated
+__bcount(this->m_cchLen)
+CHAR *
+STRA::QueryStr(
+    VOID
+) const
+//
+//  Return the string buffer
+//
+{
+    return m_Buff.QueryPtr();
+}
+
+VOID
+STRA::Reset(
+    VOID
+)
+//
+// Resets the internal string to be NULL string. Buffer remains cached.
+//
+{
+    _ASSERTE( QueryStr() != NULL );
+    *(QueryStr()) = '\0';
+    m_cchLen = 0;
+}
+
+HRESULT
+STRA::Resize(
+    __in DWORD cchSize
+)
+{
+    if( !m_Buff.Resize( cchSize * sizeof( CHAR ) ) )
+    {
+        return E_OUTOFMEMORY;
+    }
+
+    return S_OK;
+}
+
+HRESULT
+STRA::SyncWithBuffer(
+    VOID
+)
+//
+// Recalculate the length of the string, etc. because we've modified
+// the buffer directly.
+//
+{
+    HRESULT hr;
+    size_t size;
+    hr = StringCchLengthA( QueryStr(),
+                           QuerySizeCCH(),
+                           &size );
+    if ( SUCCEEDED( hr ) )
+    {
+        m_cchLen = static_cast<DWORD>(size);
+    }
+    return hr;
+}
+
+HRESULT
+STRA::Copy(
+    __in PCSTR   pszCopy
+)
+{
+    HRESULT     hr;
+    size_t      cbLen;
+    hr = StringCbLengthA( pszCopy,
+                          STRSAFE_MAX_CCH,
+                          &cbLen );
+    if ( FAILED( hr ) )
+    {
+        return hr;
+    }
+    return Copy( pszCopy, cbLen );
+}
+
+
+HRESULT
+STRA::Copy(
+    __in_ecount(cchLen)
+    PCSTR           pszCopy,
+    __in SIZE_T     cbLen
+)
+//
+// Copy the contents of another string to this one
+//
+{
+    _ASSERTE( cbLen <= MAXDWORD );
+
+    return AuxAppend(
+        pszCopy,
+        static_cast<DWORD>(cbLen),
+        0
+    );
+}
+
+HRESULT
+STRA::Copy(
+    __in const STRA * pstrRhs
+)
+{
+    _ASSERTE( pstrRhs != NULL );
+    return Copy( pstrRhs->QueryStr(), pstrRhs->QueryCCH() );
+}
+
+HRESULT
+STRA::Copy(
+    __in const STRA & strRhs
+)
+{
+    return Copy( strRhs.QueryStr(), strRhs.QueryCCH() );
+}
+
+HRESULT
+STRA::CopyW(
+    __in PCWSTR  pszCopyW
+)
+{
+    HRESULT     hr;
+    size_t      cchLen;
+    hr = StringCchLengthW( pszCopyW,
+                           STRSAFE_MAX_CCH,
+                           &cchLen );
+    if ( FAILED( hr ) )
+    {
+        return hr;
+    }
+    return CopyW( pszCopyW, cchLen );
+}
+
+HRESULT
+STRA::CopyWTruncate(
+    __in PCWSTR pszCopyWTruncate
+)
+{
+    HRESULT     hr;
+    size_t      cchLen;
+    hr = StringCchLengthW( pszCopyWTruncate,
+                           STRSAFE_MAX_CCH,
+                           &cchLen );
+    if ( FAILED( hr ) )
+    {
+        return hr;
+    }
+    return CopyWTruncate( pszCopyWTruncate, cchLen );
+}
+
+HRESULT
+STRA::CopyWTruncate(
+    __in_ecount(cchLen)
+    PCWSTR          pszCopyWTruncate,
+    __in SIZE_T     cchLen
+)
+//
+// The "Truncate" methods do not do proper conversion. They do a (CHAR) caste
+//
+{
+    _ASSERTE( cchLen <= MAXDWORD );
+
+    return AuxAppendWTruncate(
+        pszCopyWTruncate,
+        static_cast<DWORD>(cchLen),
+        0
+    );
+}
+
+HRESULT
+STRA::Append(
+    __in PCSTR pszAppend
+)
+{
+    HRESULT     hr;
+    size_t      cbLen;
+    hr = StringCbLengthA( pszAppend,
+                          STRSAFE_MAX_CCH,
+                          &cbLen );
+    if ( FAILED( hr ) )
+    {
+        return hr;
+    }
+    return Append( pszAppend, cbLen );
+}
+
+HRESULT
+STRA::Append(
+    __in_ecount(cchLen)
+    PCSTR       pszAppend,
+    __in SIZE_T cbLen
+)
+{
+    _ASSERTE( cbLen <= MAXDWORD );
+    if ( cbLen == 0 )
+    {
+        return S_OK;
+    }
+    return AuxAppend(
+        pszAppend,
+        static_cast<DWORD>(cbLen),
+        QueryCB()
+    );
+}
+
+HRESULT
+STRA::Append(
+    __in const STRA * pstrRhs
+)
+{
+    _ASSERTE( pstrRhs != NULL );
+    return Append( pstrRhs->QueryStr(), pstrRhs->QueryCCH() );
+}
+
+HRESULT
+STRA::Append(
+    __in const STRA & strRhs
+)
+{
+    return Append( strRhs.QueryStr(), strRhs.QueryCCH() );
+}
+
+HRESULT
+STRA::AppendWTruncate(
+    __in PCWSTR pszAppendWTruncate
+)
+{
+    HRESULT     hr;
+    size_t      cchLen;
+    hr = StringCchLengthW( pszAppendWTruncate,
+                           STRSAFE_MAX_CCH,
+                           &cchLen );
+    if ( FAILED( hr ) )
+    {
+        return hr;
+    }
+    return AppendWTruncate( pszAppendWTruncate, cchLen );
+}
+
+HRESULT
+STRA::AppendWTruncate(
+    __in_ecount(cchLen)
+    PCWSTR          pszAppendWTruncate,
+    __in SIZE_T     cchLen
+)
+//
+// The "Truncate" methods do not do proper conversion. They do a (CHAR) caste
+//
+{
+    _ASSERTE( cchLen <= MAXDWORD );
+    if ( cchLen == 0 )
+    {
+        return S_OK;
+    }
+    return AuxAppendWTruncate(
+        pszAppendWTruncate,
+        static_cast<DWORD>(cchLen),
+        QueryCB()
+    );
+}
+
+HRESULT
+STRA::CopyToBuffer(
+    __out_bcount(*pcb) CHAR*    pszBuffer,
+    __inout DWORD *             pcb
+) const
+//
+// Makes a copy of the stored string into the given buffer
+//
+{
+    _ASSERTE( NULL != pszBuffer );
+    _ASSERTE( NULL != pcb );
+
+    HRESULT hr          = S_OK;
+    DWORD   cbNeeded    = QueryCB() + sizeof( CHAR );
+
+    if( *pcb < cbNeeded )
+    {
+        hr = HRESULT_FROM_WIN32( ERROR_INSUFFICIENT_BUFFER );
+        goto Finished;
+    }
+
+    memcpy( pszBuffer, QueryStr(), cbNeeded );
+
+Finished:
+
+    *pcb = cbNeeded;
+
+    return hr;
+}
+
+HRESULT
+STRA::SetLen(
+    __in DWORD cchLen
+)
+/*++
+ *
+Routine Description:
+
+    Set the length of the string and null terminate, if there
+    is sufficient buffer already allocated. Will not reallocate.
+
+Arguments:
+
+    cchLen - The number of characters in the new string.
+
+Return Value:
+
+    HRESULT
+
+--*/
+{
+    if( cchLen >= QuerySizeCCH() )
+    {
+        return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
+    }
+
+    *( QueryStr() + cchLen ) = '\0';
+    m_cchLen = cchLen;
+
+    return S_OK;
+}
+
+
+HRESULT
+STRA::SafeSnprintf(
+    __in __format_string
+    PCSTR       pszFormatString,
+    ...
+)
+/*++
+
+Routine Description:
+
+    Writes to a STRA, growing it as needed. It arbitrarily caps growth at 64k chars.
+
+Arguments:
+
+    pszFormatString    - printf format
+    ...                - printf args
+
+Return Value:
+
+    HRESULT
+
+--*/
+{
+    HRESULT     hr          = S_OK;
+    va_list     argsList;
+    va_start(   argsList, pszFormatString );
+
+    hr = SafeVsnprintf(pszFormatString, argsList);
+
+    va_end( argsList );
+    return hr;
+}
+
+HRESULT
+STRA::SafeVsnprintf(
+    __in __format_string
+    PCSTR       pszFormatString,
+    va_list     argsList
+)
+/*++
+
+Routine Description:
+
+    Writes to a STRA, growing it as needed. It arbitrarily caps growth at 64k chars.
+
+Arguments:
+
+    pszFormatString    - printf format
+    argsList           - printf va_list
+
+Return Value:
+
+    HRESULT
+
+--*/
+{
+    HRESULT     hr          = S_OK;
+    int         cchOutput;
+    int         cchNeeded;
+
+    //
+    // Format the incoming message using vsnprintf()
+    // so that the overflows are captured
+    //
+    cchOutput = _vsnprintf_s(
+            QueryStr(),
+            QuerySizeCCH(),
+            QuerySizeCCH() - 1,
+            pszFormatString,
+            argsList
+        );
+
+    if( cchOutput == -1 )
+    {
+        //
+        // Couldn't fit this in the original STRU size.
+        //
+        cchNeeded = _vscprintf( pszFormatString, argsList );
+        if( cchNeeded > 64 * 1024 )
+        {
+            //
+            // If we're trying to produce a string > 64k chars, then
+            // there is probably a problem
+            //
+            hr = HRESULT_FROM_WIN32( ERROR_INVALID_DATA );
+            goto Finished;
+        }
+
+        //
+        // _vscprintf doesn't include terminating null character
+        //
+        cchNeeded++;
+
+        hr = Resize( cchNeeded );
+        if( FAILED( hr ) )
+        {
+            goto Finished;
+        }
+
+        cchOutput = _vsnprintf_s(
+            QueryStr(),
+            QuerySizeCCH(),
+            QuerySizeCCH() - 1,
+            pszFormatString,
+            argsList
+        );
+        if( -1 == cchOutput )
+        {
+            //
+            // This should never happen, cause we should already have correctly sized memory
+            //
+            _ASSERTE( FALSE );
+
+            hr = HRESULT_FROM_WIN32( ERROR_INVALID_DATA );
+            goto Finished;
+        }
+    }
+
+    //
+    // always null terminate at the last WCHAR
+    //
+    QueryStr()[ QuerySizeCCH() - 1 ] = L'\0';
+
+    //
+    // we directly touched the buffer - therefore:
+    //
+    hr = SyncWithBuffer();
+    if( FAILED( hr ) )
+    {
+        goto Finished;
+    }
+
+Finished:
+
+    if( FAILED( hr ) )
+    {
+        Reset();
+    }
+
+    return hr;
+}
+
+bool
+FShouldEscapeUtf8(
+    BYTE ch
+    )
+{
+    if ( ( ch >= 128 ) )
+    {
+        return true;
+    }
+
+    return false;
+}
+
+bool
+FShouldEscapeUrl(
+    BYTE ch
+    )
+{
+    if ( ( ch >= 128   ||
+           ch <= 32    ||
+           ch == '<'   ||
+           ch == '>'   ||
+           ch == '%'   ||
+           ch == '?'   ||
+           ch == '#' ) &&
+         !( ch == '\n' || ch == '\r' ) )
+    {
+        return true;
+    }
+
+    return false;
+}
+
+HRESULT
+STRA::Escape(
+    VOID
+)
+/*++
+
+Routine Description:
+
+    Escapes a STRA
+
+Arguments:
+
+    None
+
+Return Value:
+
+    None
+
+--*/
+{
+    return EscapeInternal( FShouldEscapeUrl );
+}
+
+HRESULT
+STRA::EscapeUtf8(
+    VOID
+)
+/*++
+
+Routine Description:
+
+    Escapes the high-bit chars in a STRA.  LWS, CR, LF & controls are untouched.
+
+Arguments:
+
+    None
+
+Return Value:
+
+    None
+
+--*/
+{
+    return EscapeInternal( FShouldEscapeUtf8 );
+}
+
+
+HRESULT
+STRA::EscapeInternal(
+    PFN_F_SHOULD_ESCAPE pfnFShouldEscape
+)
+/*++
+
+Routine Description:
+
+    Escapes a STRA according to the predicate function passed in
+
+Arguments:
+
+    None
+
+Return Value:
+
+    None
+
+--*/
+{
+    LPCSTR  pch     = QueryStr();
+    __analysis_assume( pch != NULL );
+    int     i      = 0;
+    BYTE    ch;
+    HRESULT hr      = S_OK;
+    BOOL    fRet    = FALSE;
+    SIZE_T  NewSize = 0;
+
+    // Set to true if any % escaping occurs
+    BOOL fEscapingDone = FALSE;
+
+    //
+    // If there are any characters that need to be escaped we copy the entire string
+    // character by character into straTemp, escaping as we go, then at the end
+    // copy all of straTemp over. Don't modify InlineBuffer directly.
+    //
+    CHAR InlineBuffer[512];
+    InlineBuffer[0] = '\0';
+    STRA straTemp(InlineBuffer, sizeof(InlineBuffer)/sizeof(*InlineBuffer));
+
+    _ASSERTE( pch );
+
+    while (ch = pch[i])
+    {
+        //
+        //  Escape characters that are in the non-printable range
+        //  but ignore CR and LF
+        //
+
+        if ( pfnFShouldEscape( ch ) )
+        {
+            if (FALSE == fEscapingDone)
+            {
+                // first character in the string that needed escaping
+                fEscapingDone = TRUE;
+
+                // guess that the size needs to be larger than
+                // what we used to have times two
+                NewSize = QueryCCH() * 2;
+                if ( NewSize > MAXDWORD )
+                {
+                    hr = HRESULT_FROM_WIN32( ERROR_ARITHMETIC_OVERFLOW );
+                    return hr;
+                }
+
+                hr = straTemp.Resize( static_cast<DWORD>(NewSize) );
+
+                if (FAILED(hr))
+                {
+                    return hr;
+                }
+
+                // Copy all of the previous buffer into buffTemp, only if it is not the first character:
+
+                if ( i > 0)
+                {
+                    hr = straTemp.Copy(QueryStr(),
+                                       i * sizeof(CHAR));
+                    if (FAILED(hr))
+                    {
+                        return hr;
+                    }
+                }
+            }
+
+            // resize the temporary (if needed) with the slop of the entire buffer length
+            // this fixes constant reallocation if the entire string needs to be escaped
+            NewSize = QueryCCH() + 2 * sizeof(CHAR) + 1 * sizeof(CHAR);
+            if ( NewSize > MAXDWORD )
+            {
+                hr = HRESULT_FROM_WIN32( ERROR_ARITHMETIC_OVERFLOW );
+                return hr;
+            }
+
+            fRet = straTemp.m_Buff.Resize( NewSize );
+            if ( !fRet )
+            {
+                hr = HRESULT_FROM_WIN32(GetLastError());
+                return hr;
+            }
+
+            //
+            //  Create the string to append for the current character
+            //
+
+            CHAR chHex[3];
+            chHex[0] = '%';
+
+            //
+            //  Convert the low then the high character to hex
+            //
+
+            UINT nLowDigit = (UINT)(ch % 16);
+            chHex[2] = TODIGIT( nLowDigit );
+
+            ch /= 16;
+
+            UINT nHighDigit = (UINT)(ch % 16);
+
+            chHex[1] = TODIGIT( nHighDigit );
+
+            //
+            // Actually append the converted character to the end of the temporary
+            //
+            hr = straTemp.Append(chHex, 3);
+            if (FAILED(hr))
+            {
+                return hr;
+            }
+        }
+        else
+        {
+            // if no escaping done, no need to copy
+            if (fEscapingDone)
+            {
+                // if ANY escaping done, copy current character into new buffer
+                straTemp.Append(&pch[i], 1);
+            }
+        }
+
+        // inspect the next character in the string
+        i++;
+    }
+
+    if (fEscapingDone)
+    {
+        // the escaped string is now in straTemp
+        hr = Copy(straTemp);
+    }
+
+    return hr;
+
+} // EscapeInternal()
+
+VOID
+STRA::Unescape(
+    VOID
+)
+/*++
+
+Routine Description:
+
+    Unescapes a STRA
+
+    Supported escape sequences are:
+      %uxxxx unescapes Unicode character xxxx into system codepage
+      %xx    unescapes character xx
+      %      without following hex digits is ignored
+
+Arguments:
+
+    None
+
+Return Value:
+
+    None
+
+--*/
+{
+    CHAR   *pScan;
+    CHAR   *pDest;
+    CHAR   *pNextScan;
+    WCHAR   wch;
+    DWORD   dwLen;
+    BOOL    fChanged = FALSE;
+
+    //
+    // Now take care of any escape characters
+    //
+    pDest = pScan = strchr(QueryStr(), '%');
+
+    while (pScan)
+    {
+        if ((pScan[1] == 'u' || pScan[1] == 'U') &&
+            SAFEIsXDigit(pScan[2]) &&
+            SAFEIsXDigit(pScan[3]) &&
+            SAFEIsXDigit(pScan[4]) &&
+            SAFEIsXDigit(pScan[5]))
+        {
+            wch = TOHEX(pScan[2]) * 4096 + TOHEX(pScan[3]) * 256
+                + TOHEX(pScan[4]) * 16 + TOHEX(pScan[5]);
+
+            dwLen = WideCharToMultiByte(CP_ACP,
+                                        WC_NO_BEST_FIT_CHARS,
+                                        &wch,
+                                        1,
+                                        (LPSTR) pDest,
+                                        6,
+                                        NULL,
+                                        NULL);
+
+            pDest += dwLen;
+            pScan += 6;
+            fChanged = TRUE;
+        }
+        else if (SAFEIsXDigit(pScan[1]) && SAFEIsXDigit(pScan[2]))
+        {
+            *pDest = TOHEX(pScan[1]) * 16 + TOHEX(pScan[2]);
+
+            pDest ++;
+            pScan += 3;
+            fChanged = TRUE;
+        }
+        else   // Not an escaped char, just a '%'
+        {
+            if (fChanged)
+            {
+                *pDest = *pScan;
+            }
+
+            pDest++;
+            pScan++;
+        }
+
+        //
+        // Copy all the information between this and the next escaped char
+        //
+        pNextScan = strchr(pScan, '%');
+
+        if (fChanged)   // pScan!=pDest, so we have to copy the char's
+        {
+            if (!pNextScan)   // That was the last '%' in the string
+            {
+                memmove(pDest,
+                        pScan,
+                        QueryCCH() - DIFF(pScan - QueryStr()) + 1);
+            }
+            else
+            {
+                // There is another '%', move intermediate chars
+                if ((dwLen = (DWORD)DIFF(pNextScan - pScan)) != 0)
+                {
+                    memmove(pDest,
+                            pScan,
+                            dwLen);
+                    pDest += dwLen;
+                }
+            }
+        }
+
+        pScan = pNextScan;
+    }
+
+    if (fChanged)
+    {
+        m_cchLen = (DWORD)strlen(QueryStr());  // for safety recalc the length
+    }
+
+    return;
+}
+
+HRESULT
+STRA::CopyWToUTF8Unescaped(
+    __in LPCWSTR cpchStr
+)
+{
+    return STRA::CopyWToUTF8Unescaped(cpchStr, (DWORD) wcslen(cpchStr));
+}
+
+HRESULT
+STRA::CopyWToUTF8Unescaped(
+    __in_ecount(cch)
+    LPCWSTR         cpchStr,
+    __in DWORD      cch
+)
+{
+    HRESULT hr = S_OK;
+    int iRet;
+
+    if (cch == 0)
+    {
+        Reset();
+        return S_OK;
+    }
+
+    iRet = ConvertUnicodeToUTF8(cpchStr,
+                                &m_Buff,
+                                cch);
+    if (-1 == iRet)
+    {
+        // could not convert
+        hr = HRESULT_FROM_WIN32(GetLastError());
+        goto Finished;
+    }
+
+    m_cchLen = iRet;
+
+    _ASSERTE(strlen(m_Buff.QueryPtr()) == m_cchLen);
+Finished:
+    return hr;
+}
+
+HRESULT
+STRA::CopyWToUTF8Escaped(
+    __in LPCWSTR cpchStr
+)
+{
+    return STRA::CopyWToUTF8Escaped(cpchStr, (DWORD) wcslen(cpchStr));
+}
+
+HRESULT
+STRA::CopyWToUTF8Escaped(
+    __in_ecount(cch)
+    LPCWSTR         cpchStr,
+    __in DWORD      cch
+)
+{
+    HRESULT hr = S_OK;
+
+    hr = CopyWToUTF8Unescaped(cpchStr, cch);
+    if (FAILED(hr))
+    {
+        goto Finished;
+    }
+
+    hr = Escape();
+    if (FAILED(hr))
+    {
+        goto Finished;
+    }
+
+    hr = S_OK;
+Finished:
+    return hr;
+}
+
+HRESULT
+STRA::AuxAppend(
+    __in_ecount(cbLen)
+    LPCSTR          pStr,
+    __in DWORD      cbLen,
+    __in DWORD      cbOffset
+)
+{
+    _ASSERTE( NULL != pStr );
+    _ASSERTE( cbOffset <= QueryCB() );
+
+    ULONGLONG cb64NewSize = (ULONGLONG)cbOffset + cbLen + sizeof( CHAR );
+    if( cb64NewSize > MAXDWORD )
+    {
+        return HRESULT_FROM_WIN32( ERROR_ARITHMETIC_OVERFLOW );
+    }
+
+    if( m_Buff.QuerySize() < cb64NewSize )
+    {
+        if( !m_Buff.Resize( static_cast<SIZE_T>(cb64NewSize) ) )
+        {
+            return E_OUTOFMEMORY;
+        }
+    }
+
+    memcpy( reinterpret_cast<BYTE*>(m_Buff.QueryPtr()) + cbOffset, pStr, cbLen );
+
+    m_cchLen = cbLen + cbOffset;
+
+    *( QueryStr() + m_cchLen ) = '\0';
+
+    return S_OK;
+}
+
+HRESULT
+STRA::AuxAppendW(
+    __in_ecount(cchAppendW)
+    PCWSTR          pszAppendW,
+    __in DWORD      cchAppendW,
+    __in DWORD      cbOffset,
+    __in UINT       CodePage,
+    __in BOOL       fFailIfNoTranslation,
+    __in DWORD      dwFlags
+)
+{
+    HRESULT hr          = S_OK;
+    DWORD   cbAvailable = 0;
+    DWORD   cbRet       = 0;
+
+    //
+    // There are only two expect places to append
+    //
+    _ASSERTE( 0 == cbOffset || QueryCB() == cbOffset );
+
+    if ( cchAppendW == 0 )
+    {
+        goto Finished;
+    }
+
+    //
+    // start by assuming 1 char to 1 char will be enough space
+    //
+    if( !m_Buff.Resize( cbOffset + cchAppendW + sizeof( CHAR ) ) )
+    {
+        hr = E_OUTOFMEMORY;
+        goto Finished;
+    }
+
+    cbAvailable = m_Buff.QuerySize() - cbOffset;
+
+    cbRet = WideCharToMultiByte(
+        CodePage,
+        dwFlags,
+        pszAppendW,
+        cchAppendW,
+        QueryStr() + cbOffset,
+        cbAvailable,
+        NULL,
+        NULL
+    );
+    if( 0 != cbRet )
+    {
+        if(!m_Buff.Resize(cbOffset + cbRet + 1))
+        {
+            hr = E_OUTOFMEMORY;
+        }
+
+        //
+        // not zero --> success, so we're done
+        //
+        goto Finished;
+    }
+
+    //
+    // We only know how to handle ERROR_INSUFFICIENT_BUFFER
+    //
+    hr = HRESULT_FROM_WIN32( GetLastError() );
+    if( hr != HRESULT_FROM_WIN32( ERROR_INSUFFICIENT_BUFFER ) )
+    {
+        goto Finished;
+    }
+
+    //
+    // Reset HResult because we need to get the number of bytes needed
+    //
+    hr = S_OK;
+    cbRet = WideCharToMultiByte(
+        CodePage,
+        dwFlags,
+        pszAppendW,
+        cchAppendW,
+        NULL,
+        0,
+        NULL,
+        NULL
+    );
+    if( 0 == cbRet )
+    {
+        //
+        // no idea how we could ever reach here
+        //
+        hr = HRESULT_FROM_WIN32( GetLastError() );
+        goto Finished;
+    }
+
+    if( !m_Buff.Resize( cbOffset + cbRet + 1) )
+    {
+        hr = E_OUTOFMEMORY;
+        goto Finished;
+    }
+
+    cbAvailable = m_Buff.QuerySize() - cbOffset;
+
+    cbRet = WideCharToMultiByte(
+        CodePage,
+        dwFlags,
+        pszAppendW,
+        cchAppendW,
+        QueryStr() + cbOffset,
+        cbAvailable,
+        NULL,
+        NULL
+    );
+    if( 0 == cbRet )
+    {
+        hr = HRESULT_FROM_WIN32( GetLastError() );
+        goto Finished;
+    }
+
+Finished:
+
+    if( SUCCEEDED( hr ) && 0 != cbRet )
+    {
+        m_cchLen = cbRet + cbOffset;
+    }
+
+    //
+    // ensure we're still NULL terminated in the right spot
+    // (regardless of success or failure)
+    //
+    QueryStr()[m_cchLen] = '\0';
+
+    return hr;
+}
+
+HRESULT
+STRA::AuxAppendWTruncate(
+    __in_ecount(cchAppendW)
+    __in PCWSTR     pszAppendW,
+    __in DWORD      cchAppendW,
+    __in DWORD      cbOffset
+)
+//
+// Cheesey WCHAR --> CHAR conversion
+//
+{
+    HRESULT hr = S_OK;
+    CHAR*   pszBuffer;
+
+    _ASSERTE( NULL != pszAppendW );
+    _ASSERTE( 0 == cbOffset || cbOffset == QueryCB() );
+
+    if( !pszAppendW )
+    {
+        hr = HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
+        goto Finished;
+    }
+
+    ULONGLONG cbNeeded = (ULONGLONG)cbOffset + cchAppendW + sizeof( CHAR );
+    if( cbNeeded > MAXDWORD )
+    {
+        hr = HRESULT_FROM_WIN32( ERROR_ARITHMETIC_OVERFLOW );
+        goto Finished;
+    }
+
+    if( !m_Buff.Resize( static_cast<SIZE_T>(cbNeeded) ) )
+    {
+        hr = E_OUTOFMEMORY;
+        goto Finished;
+    }
+
+    //
+    // Copy/convert the UNICODE string over (by making two bytes into one)
+    //
+    pszBuffer = QueryStr() + cbOffset;
+    for( DWORD i = 0; i < cchAppendW; i++ )
+    {
+        pszBuffer[i] = static_cast<CHAR>(pszAppendW[i]);
+    }
+
+    m_cchLen = cchAppendW + cbOffset;
+    *( QueryStr() + m_cchLen ) = '\0';
+
+Finished:
+
+    return hr;
+}
+
+// static
+int
+STRA::ConvertUnicodeToCodePage(
+    __in_ecount(dwStringLen)
+    LPCWSTR                     pszSrcUnicodeString,
+    __inout BUFFER_T<CHAR,1> *  pbufDstAnsiString,
+    __in DWORD                  dwStringLen,
+    __in UINT                   uCodePage
+)
+{
+    _ASSERTE(NULL != pszSrcUnicodeString);
+    _ASSERTE(NULL != pbufDstAnsiString);
+
+    BOOL bTemp;
+    int iStrLen = 0;
+    DWORD dwFlags;
+
+    if (uCodePage == CP_ACP)
+    {
+        dwFlags = WC_NO_BEST_FIT_CHARS;
+    }
+    else
+    {
+        dwFlags = 0;
+    }
+
+    iStrLen = WideCharToMultiByte(uCodePage,
+                                  dwFlags,
+                                  pszSrcUnicodeString,
+                                  dwStringLen,
+                                  (LPSTR)pbufDstAnsiString->QueryPtr(),
+                                  (int)pbufDstAnsiString->QuerySize(),
+                                  NULL,
+                                  NULL);
+    if ((iStrLen == 0) && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
+        iStrLen = WideCharToMultiByte(uCodePage,
+                                      dwFlags,
+                                      pszSrcUnicodeString,
+                                      dwStringLen,
+                                      NULL,
+                                      0,
+                                      NULL,
+                                      NULL);
+        if (iStrLen != 0) {
+            // add one just for the extra NULL
+            bTemp = pbufDstAnsiString->Resize(iStrLen + 1);
+            if (!bTemp)
+            {
+                iStrLen = 0;
+            }
+            else
+            {
+                iStrLen = WideCharToMultiByte(uCodePage,
+                                              dwFlags,
+                                              pszSrcUnicodeString,
+                                              dwStringLen,
+                                              (LPSTR)pbufDstAnsiString->QueryPtr(),
+                                              (int)pbufDstAnsiString->QuerySize(),
+                                              NULL,
+                                              NULL);
+            }
+
+        }
+    }
+
+    if (0 != iStrLen &&
+        pbufDstAnsiString->Resize(iStrLen + 1))
+    {
+        // insert a terminating NULL into buffer for the dwStringLen+1 in the case that the dwStringLen+1 was not a NULL.
+        ((CHAR*)pbufDstAnsiString->QueryPtr())[iStrLen] = '\0';
+    }
+    else
+    {
+        iStrLen = -1;
+    }
+
+    return iStrLen;
+}
+
+// static
+HRESULT
+STRA::ConvertUnicodeToMultiByte(
+    __in_ecount(dwStringLen)
+    LPCWSTR                     pszSrcUnicodeString,
+    __in BUFFER_T<CHAR,1> *     pbufDstAnsiString,
+    __in DWORD                  dwStringLen
+)
+{
+    return ConvertUnicodeToCodePage( pszSrcUnicodeString,
+                                      pbufDstAnsiString,
+                                      dwStringLen,
+                                      CP_ACP );
+}
+
+// static
+HRESULT
+STRA::ConvertUnicodeToUTF8(
+    __in_ecount(dwStringLen)
+    LPCWSTR                     pszSrcUnicodeString,
+    __in BUFFER_T<CHAR,1> *     pbufDstAnsiString,
+    __in DWORD                  dwStringLen
+)
+{
+    return ConvertUnicodeToCodePage( pszSrcUnicodeString,
+                                      pbufDstAnsiString,
+                                      dwStringLen,
+                                      CP_UTF8 );
+}
+
+/*++
+
+Routine Description:
+
+    Removes leading and trailing whitespace
+
+--*/
+
+VOID
+STRA::Trim()
+{
+    PSTR    pszString               = QueryStr();
+    DWORD   cchNewLength            = m_cchLen;
+    DWORD   cchLeadingWhitespace    = 0;
+    DWORD   cchTempLength           = 0;
+
+    for (LONG ixString = m_cchLen - 1; ixString >= 0; ixString--)
+    {
+        if (isspace((unsigned char) pszString[ixString]) != 0)
+        {
+            pszString[ixString] = '\0';
+            cchNewLength--;
+        }
+        else
+        {
+            break;
+        }
+    }
+
+    cchTempLength = cchNewLength;
+    for (DWORD ixString = 0; ixString < cchTempLength; ixString++)
+    {
+        if (isspace((unsigned char) pszString[ixString]) != 0)
+        {
+            cchLeadingWhitespace++;
+            cchNewLength--;
+        }
+        else
+        {
+            break;
+        }
+    }
+
+    if (cchNewLength == 0)
+    {
+
+        Reset();
+    }
+    else if (cchLeadingWhitespace > 0)
+    {
+        memmove(pszString, pszString + cchLeadingWhitespace, cchNewLength * sizeof(CHAR));
+        pszString[cchNewLength] = '\0';
+    }
+
+    SyncWithBuffer();
+}
+
+/*++
+
+Routine Description:
+
+    Compares the string to the provided prefix to check for equality
+
+Arguments:
+
+    pStraPrefix - string to compare with
+    fIgnoreCase - indicates whether the string comparison should be case-sensitive
+
+Return Value:
+
+    TRUE if prefix string matches with internal string, FALSE otherwise
+
+--*/
+BOOL
+STRA::StartsWith(
+    __in const STRA *   pStraPrefix,
+    __in bool           fIgnoreCase) const
+{
+    _ASSERTE( pStraPrefix != NULL );
+    return StartsWith(pStraPrefix->QueryStr(), fIgnoreCase);
+}
+
+/*++
+
+Routine Description:
+
+    Compares the string to the provided prefix to check for equality
+
+Arguments:
+
+    straPrefix  - string to compare with
+    fIgnoreCase - indicates whether the string comparison should be case-sensitive
+
+Return Value:
+
+    TRUE if prefix string matches with internal string, FALSE otherwise
+
+--*/
+BOOL
+STRA::StartsWith(
+    __in const STRA &   straPrefix,
+    __in bool           fIgnoreCase) const
+{
+    return StartsWith(straPrefix.QueryStr(), fIgnoreCase);
+}
+
+/*++
+
+Routine Description:
+
+    Compares the string to the provided prefix to check for equality
+
+Arguments:
+
+    pszPrefix   - string to compare with
+    fIgnoreCase - indicates whether the string comparison should be case-sensitive
+
+Return Value:
+
+    TRUE if prefix string matches with internal string, FALSE otherwise
+
+--*/
+BOOL
+STRA::StartsWith(
+    __in PCSTR          pszPrefix,
+    __in bool           fIgnoreCase) const
+{
+    HRESULT hr          = S_OK;
+    BOOL    fMatch      = FALSE;
+    size_t  cchPrefix   = 0;
+
+    if (pszPrefix == NULL)
+    {
+        goto Finished;
+    }
+
+    hr = StringCchLengthA( pszPrefix,
+                           STRSAFE_MAX_CCH,
+                           &cchPrefix );
+    if (FAILED(hr))
+    {
+        goto Finished;
+    }
+
+    _ASSERTE( cchPrefix <= MAXDWORD );
+
+    if (cchPrefix > m_cchLen)
+    {
+        goto Finished;
+    }
+
+    if( fIgnoreCase )
+    {
+        fMatch = ( 0 == _strnicmp( QueryStr(), pszPrefix, cchPrefix ) );
+    }
+    else
+    {
+        fMatch = ( 0 == strncmp( QueryStr(), pszPrefix, cchPrefix ) );
+    }
+
+
+Finished:
+
+    return fMatch;
+}
+
+/*++
+
+Routine Description:
+
+    Compares the string to the provided suffix to check for equality
+
+Arguments:
+
+    pStraSuffix - string to compare with
+    fIgnoreCase - indicates whether the string comparison should be case-sensitive
+
+Return Value:
+
+    TRUE if suffix string matches with internal string, FALSE otherwise
+
+--*/
+BOOL
+STRA::EndsWith(
+    __in const STRA *   pStraSuffix,
+    __in bool           fIgnoreCase) const
+{
+    _ASSERTE( pStraSuffix != NULL );
+    return EndsWith(pStraSuffix->QueryStr(), fIgnoreCase);
+}
+
+
+/*++
+
+Routine Description:
+
+    Compares the string to the provided suffix to check for equality
+
+Arguments:
+
+    straSuffix  - string to compare with
+    fIgnoreCase - indicates whether the string comparison should be case-sensitive
+
+Return Value:
+
+    TRUE if suffix string matches with internal string, FALSE otherwise
+
+--*/
+BOOL
+STRA::EndsWith(
+    __in const STRA &   straSuffix,
+    __in bool           fIgnoreCase) const
+{
+    return EndsWith(straSuffix.QueryStr(), fIgnoreCase);
+}
+
+
+/*++
+
+Routine Description:
+
+    Compares the string to the provided suffix to check for equality
+
+Arguments:
+
+    pszSuffix   - string to compare with
+    fIgnoreCase - indicates whether the string comparison should be case-sensitive
+
+Return Value:
+
+    TRUE if suffix string matches with internal string, FALSE otherwise
+
+--*/
+BOOL
+STRA::EndsWith(
+    __in PCSTR          pszSuffix,
+    __in bool           fIgnoreCase) const
+{
+    HRESULT   hr          = S_OK;
+    PSTR      pszString   = QueryStr();
+    BOOL      fMatch      = FALSE;
+    size_t    cchSuffix   = 0;
+    ptrdiff_t ixOffset    = 0;
+
+    if (pszSuffix == NULL)
+    {
+        goto Finished;
+    }
+
+    hr = StringCchLengthA( pszSuffix,
+                           STRSAFE_MAX_CCH,
+                           &cchSuffix );
+    if (FAILED(hr))
+    {
+        goto Finished;
+    }
+
+    _ASSERTE( cchSuffix <= MAXDWORD );
+
+    if (cchSuffix > m_cchLen)
+    {
+        goto Finished;
+    }
+
+    ixOffset = m_cchLen - cchSuffix;
+    _ASSERTE(ixOffset >= 0 && ixOffset <= MAXDWORD);
+
+    if( fIgnoreCase )
+    {
+        fMatch = ( 0 == _strnicmp( pszString + ixOffset, pszSuffix, cchSuffix ) );
+    }
+    else
+    {
+        fMatch = ( 0 == strncmp( pszString + ixOffset, pszSuffix, cchSuffix ) );
+    }
+
+Finished:
+
+    return fMatch;
+}
+
+
+/*++
+
+Routine Description:
+
+    Searches the string for the first occurrence of the specified character.
+
+Arguments:
+
+    charValue       - character to find
+    dwStartIndex    - the initial index.
+
+Return Value:
+
+    The index for the first character occurence in the string.
+
+    -1 if not found.
+
+--*/
+INT
+STRA::IndexOf(
+    __in CHAR           charValue,
+    __in DWORD          dwStartIndex
+    ) const
+{
+    INT nIndex = -1;
+
+    // Make sure that there are no buffer overruns.
+    if( dwStartIndex >= QueryCCH() )
+    {
+        goto Finished;
+    }
+
+    const CHAR* pChar = strchr( QueryStr() + dwStartIndex, charValue );
+
+    // Determine the index if found
+    if( pChar )
+    {
+        // nIndex will be set to -1 on failure.
+        (VOID)SizeTToInt( pChar - QueryStr(), &nIndex );
+    }
+
+Finished:
+
+    return nIndex;
+}
+
+
+/*++
+
+Routine Description:
+
+    Searches the string for the first occurrence of the specified substring.
+
+Arguments:
+
+    pszValue        - substring to find
+    dwStartIndex    - initial index.
+
+Return Value:
+
+    The index for the first character occurence in the string.
+
+    -1 if not found.
+
+--*/
+INT
+STRA::IndexOf(
+    __in PCSTR          pszValue,
+    __in DWORD          dwStartIndex
+    ) const
+{
+    HRESULT hr = S_OK;
+    INT nIndex = -1;
+    SIZE_T cchValue = 0;
+
+    // Validate input parameters
+    if( dwStartIndex >= QueryCCH() || !pszValue )
+    {
+        goto Finished;
+    }
+
+    const CHAR* pChar = strstr( QueryStr() + dwStartIndex, pszValue );
+
+    // Determine the index if found
+    if( pChar )
+    {
+        // nIndex will be set to -1 on failure.
+        (VOID)SizeTToInt( pChar - QueryStr(), &nIndex );
+    }
+
+Finished:
+
+    return nIndex;
+}
+
+
+/*++
+
+Routine Description:
+
+    Searches the string for the last occurrence of the specified character.
+
+Arguments:
+
+    charValue       - character to find
+    dwStartIndex    - initial index.
+
+Return Value:
+
+    The index for the last character occurence in the string.
+
+    -1 if not found.
+
+--*/
+INT
+STRA::LastIndexOf(
+    __in CHAR           charValue,
+    __in DWORD          dwStartIndex
+    ) const
+{
+    INT nIndex = -1;
+
+    // Make sure that there are no buffer overruns.
+    if( dwStartIndex >= QueryCCH() )
+    {
+        goto Finished;
+    }
+
+    const CHAR* pChar = strrchr( QueryStr() + dwStartIndex, charValue );
+
+    // Determine the index if found
+    if( pChar )
+    {
+        // nIndex will be set to -1 on failure.
+        (VOID)SizeTToInt( pChar - QueryStr(), &nIndex );
+    }
+
+Finished:
+
+    return nIndex;
+}
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/IISLib/stringa.h b/src/IISIntegration/src/AspNetCoreModuleV2/IISLib/stringa.h
new file mode 100644
index 0000000000000000000000000000000000000000..39737f4a69d8ce5bc7f2ae6938a96bb6166cd50f
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/IISLib/stringa.h
@@ -0,0 +1,515 @@
+// 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 "buffer.h"
+#include "macros.h"
+#include <strsafe.h>
+
+class STRA
+{
+
+public:
+
+    STRA(
+        VOID
+    );
+
+    STRA(
+        __inout_ecount(cchInit) CHAR* pbInit,
+        __in DWORD cchInit
+    );
+
+    BOOL
+    IsEmpty(
+        VOID
+    ) const;
+
+    BOOL
+    Equals(
+        __in PCSTR  pszRhs,
+        __in BOOL   fIgnoreCase = FALSE
+    ) const;
+
+    BOOL
+    Equals(
+        __in const STRA *   pstrRhs,
+        __in BOOL           fIgnoreCase = FALSE
+    ) const;
+
+    BOOL
+    Equals(
+        __in const STRA &  strRhs,
+        __in BOOL           fIgnoreCase = FALSE
+    ) const;
+
+    static
+    BOOL
+    Equals(
+        __in PCSTR          pszLhs,
+        __in PCSTR          pszRhs,
+        __in bool           fIgnoreCase = false
+    )
+    {
+        // Return FALSE if either or both strings are NULL.
+        if (!pszLhs || !pszRhs) return FALSE;
+
+        if( fIgnoreCase )
+        {
+            return ( 0 == _stricmp( pszLhs, pszRhs ) );
+        }
+
+        return ( 0 == strcmp( pszLhs, pszRhs ) );
+    }
+
+    VOID
+    Trim();
+
+    BOOL
+    StartsWith(
+        __in const STRA *   pStraPrefix,
+        __in bool           fIgnoreCase = FALSE
+    ) const;
+
+    BOOL
+    StartsWith(
+        __in const STRA &   straPrefix,
+        __in bool           fIgnoreCase = FALSE
+    ) const;
+
+    BOOL
+    StartsWith(
+        __in PCSTR          pszPrefix,
+        __in bool           fIgnoreCase = FALSE
+    ) const;
+
+    BOOL
+    EndsWith(
+        __in const STRA *   pStraSuffix,
+        __in bool           fIgnoreCase = FALSE
+    ) const;
+
+    BOOL
+    EndsWith(
+        __in const STRA &   straSuffix,
+        __in bool           fIgnoreCase = FALSE
+    ) const;
+
+    BOOL
+    EndsWith(
+        __in PCSTR          pszSuffix,
+        __in bool           fIgnoreCase = FALSE
+    ) const;
+
+    INT
+    IndexOf(
+        __in CHAR           charValue,
+        __in DWORD          dwStartIndex = 0
+    ) const;
+
+    INT
+    IndexOf(
+        __in PCSTR          pszValue,
+        __in DWORD          dwStartIndex = 0
+    ) const;
+
+    INT
+    LastIndexOf(
+        __in CHAR           charValue,
+        __in DWORD          dwStartIndex = 0
+    ) const;
+
+    DWORD
+    QueryCB(
+        VOID
+    ) const;
+
+    DWORD
+    QueryCCH(
+        VOID
+    ) const;
+
+    DWORD
+    QuerySizeCCH(
+        VOID
+    ) const;
+
+    DWORD
+    QuerySize(
+        VOID
+    ) const;
+
+    __nullterminated
+    __bcount(this->m_cchLen)
+    CHAR *
+    QueryStr(
+        VOID
+    ) const;
+
+    VOID
+    Reset(
+        VOID
+    );
+
+    HRESULT
+    Resize(
+        __in DWORD cchSize
+    );
+
+    HRESULT
+    SyncWithBuffer(
+        VOID
+    );
+
+    HRESULT
+    Copy(
+        __in PCSTR   pszCopy
+    );
+
+    HRESULT
+    Copy(
+        __in_ecount(cbLen)
+        PCSTR           pszCopy,
+        __in SIZE_T     cbLen
+    );
+
+    HRESULT
+    Copy(
+        __in const STRA * pstrRhs
+    );
+
+    HRESULT
+    Copy(
+        __in const STRA & strRhs
+    );
+
+    HRESULT
+    CopyW(
+        __in PCWSTR  pszCopyW
+    );
+
+    HRESULT
+    CopyW(
+        __in_ecount(cchLen)
+        PCWSTR          pszCopyW,
+        __in SIZE_T     cchLen,
+        __in UINT       CodePage = CP_UTF8,
+        __in BOOL       fFailIfNoTranslation = FALSE
+    )
+    {
+        _ASSERTE( cchLen <= MAXDWORD );
+
+        return AuxAppendW(
+            pszCopyW,
+            static_cast<DWORD>(cchLen),
+            0,
+            CodePage,
+            fFailIfNoTranslation
+        );
+    }
+
+    HRESULT
+    CopyWTruncate(
+        __in PCWSTR pszCopyWTruncate
+    );
+
+    HRESULT
+    CopyWTruncate(
+        __in_ecount(cchLen)
+        PCWSTR          pszCopyWTruncate,
+        __in SIZE_T     cchLen
+    );
+
+    HRESULT
+    Append(
+        __in PCSTR pszAppend
+    );
+
+    HRESULT
+    Append(
+        __in_ecount(cbLen)
+        PCSTR       pszAppend,
+        __in SIZE_T cbLen
+    );
+
+    HRESULT
+    Append(
+        __in const STRA * pstrRhs
+    );
+
+    HRESULT
+    Append(
+        __in const STRA & strRhs
+    );
+
+    HRESULT
+    AppendW(
+        __in PCWSTR  pszAppendW
+    )
+    {
+        HRESULT     hr;
+        size_t      cchLen;
+        hr = StringCchLengthW( pszAppendW,
+                               STRSAFE_MAX_CCH,
+                               &cchLen );
+        if ( FAILED( hr ) )
+        {
+            return hr;
+        }
+        return AppendW( pszAppendW, cchLen );
+    }
+
+    HRESULT
+    AppendW(
+        __in_ecount(cchLen)
+        PCWSTR          pszAppendW,
+        __in SIZE_T     cchLen,
+        __in UINT       CodePage = CP_UTF8,
+        __in BOOL       fFailIfNoTranslation = FALSE
+    )
+    {
+        _ASSERTE( cchLen <= MAXDWORD );
+        if ( cchLen == 0 )
+        {
+            return S_OK;
+        }
+        return AuxAppendW(
+            pszAppendW,
+            static_cast<DWORD>(cchLen),
+            QueryCB(),
+            CodePage,
+            fFailIfNoTranslation
+        );
+    }
+
+    HRESULT
+    AppendWTruncate(
+        __in PCWSTR pszAppendWTruncate
+    );
+
+    HRESULT
+    AppendWTruncate(
+        __in_ecount(cchLen)
+        PCWSTR          pszAppendWTruncate,
+        __in SIZE_T     cchLen
+    );
+
+    HRESULT
+    CopyToBuffer(
+        __out_bcount(*pcb) CHAR*    pszBuffer,
+        __inout DWORD *             pcb
+    ) const;
+
+    HRESULT
+    SetLen(
+        __in DWORD cchLen
+    );
+
+    HRESULT
+    SafeSnprintf(
+        __in __format_string
+        PCSTR       pszFormatString,
+        ...
+    );
+
+    HRESULT
+    SafeVsnprintf(
+        __in __format_string
+        PCSTR       pszFormatString,
+        va_list     argsList
+    );
+
+    HRESULT
+    Escape(
+        VOID
+    );
+
+    HRESULT
+    EscapeUtf8(
+        VOID
+    );
+
+    VOID
+    Unescape(
+        VOID
+    );
+
+    HRESULT
+    CopyWToUTF8Unescaped(
+        __in LPCWSTR cpchStr
+    );
+
+    HRESULT
+    CopyWToUTF8Unescaped(
+        __in_ecount(cch)
+        LPCWSTR         cpchStr,
+        __in DWORD      cch
+    );
+
+    HRESULT
+    CopyWToUTF8Escaped(
+        __in LPCWSTR cpchStr
+    );
+
+    HRESULT
+    CopyWToUTF8Escaped(
+        __in_ecount(cch)
+        LPCWSTR         cpchStr,
+        __in DWORD      cch
+    );
+
+private:
+
+    //
+    // Avoid C++ errors. This object should never go through a copy
+    // constructor, unintended cast or assignment.
+    //
+    STRA( const STRA &);
+    STRA & operator = (const STRA &);
+
+    HRESULT
+    AuxAppend(
+        __in_ecount(cbLen)
+        LPCSTR          pStr,
+        __in DWORD      cbLen,
+        __in DWORD      cbOffset
+    );
+
+    HRESULT
+    AuxAppendW(
+        __in_ecount(cchAppendW)
+        PCWSTR          pszAppendW,
+        __in DWORD      cchAppendW,
+        __in DWORD      cbOffset,
+        __in UINT       CodePage,
+        __in BOOL       fFailIfNoTranslation
+    )
+    {
+        DWORD dwFlags = 0;
+
+        if( CP_ACP == CodePage )
+        {
+            dwFlags = WC_NO_BEST_FIT_CHARS;
+        }
+        else if( fFailIfNoTranslation && CodePage == CP_UTF8 )
+        {
+            //
+            // WC_ERR_INVALID_CHARS is only supported in Longhorn or greater.
+            //
+#if defined( NTDDI_VERSION ) && NTDDI_VERSION >= NTDDI_LONGHORN
+            dwFlags |= WC_ERR_INVALID_CHARS;
+#else
+            UNREFERENCED_PARAMETER(fFailIfNoTranslation);
+#endif
+        }
+
+        return AuxAppendW( pszAppendW,
+                            cchAppendW,
+                            cbOffset,
+                            CodePage,
+                            fFailIfNoTranslation,
+                            dwFlags );
+    }
+
+    HRESULT
+    AuxAppendW(
+        __in_ecount(cchAppendW)
+        PCWSTR          pszAppendW,
+        __in DWORD      cchAppendW,
+        __in DWORD      cbOffset,
+        __in UINT       CodePage,
+        __in BOOL       fFailIfNoTranslation,
+        __in DWORD      dwFlags
+    );
+
+    HRESULT
+    AuxAppendWTruncate(
+        __in_ecount(cchAppendW)
+        __in PCWSTR     pszAppendW,
+        __in DWORD      cchAppendW,
+        __in DWORD      cbOffset
+    );
+
+    static
+    int
+    ConvertUnicodeToCodePage(
+        __in_ecount(dwStringLen)
+        LPCWSTR                     pszSrcUnicodeString,
+        __inout BUFFER_T<CHAR,1> *  pbufDstAnsiString,
+        __in DWORD                  dwStringLen,
+        __in UINT                   uCodePage
+    );
+
+    static
+    HRESULT
+    ConvertUnicodeToMultiByte(
+        __in_ecount(dwStringLen)
+        LPCWSTR                     pszSrcUnicodeString,
+        __in BUFFER_T<CHAR,1> *     pbufDstAnsiString,
+        __in DWORD                  dwStringLen
+    );
+
+    static
+    HRESULT
+    ConvertUnicodeToUTF8(
+        __in_ecount(dwStringLen)
+        LPCWSTR                     pszSrcUnicodeString,
+        __in BUFFER_T<CHAR,1> *     pbufDstAnsiString,
+        __in DWORD                  dwStringLen
+    );
+
+    typedef bool (* PFN_F_SHOULD_ESCAPE)(BYTE ch);
+
+    HRESULT
+    EscapeInternal(
+        PFN_F_SHOULD_ESCAPE pfnFShouldEscape
+    );
+
+    //
+    // Buffer with an inline buffer of 1,
+    // enough to hold null-terminating character.
+    //
+    BUFFER_T<CHAR,1>    m_Buff;
+    DWORD               m_cchLen;
+};
+
+inline
+HRESULT
+AppendToString(
+    ULONGLONG Number,
+    STRA & String
+)
+{
+    // prefast complains Append requires input
+    // to be null terminated, so zero initialize
+    // and pass the size of the buffer minus one
+    // to _ui64toa_s
+    CHAR chNumber[32] = {0};
+    if (_ui64toa_s(Number,
+                   chNumber,
+                   sizeof(chNumber) - sizeof(CHAR),
+                   10) != 0)
+    {
+        return E_INVALIDARG;
+    }
+    return String.Append(chNumber);
+}
+
+template<DWORD size>
+CHAR* InitHelper(__out CHAR (&psz)[size])
+{
+    psz[0] = '\0';
+    return psz;
+}
+
+//
+// Heap operation reduction macros
+//
+#define STACK_STRA(name, size)  CHAR __ach##name[size];\
+                                STRA  name(InitHelper(__ach##name), sizeof(__ach##name))
+
+#define INLINE_STRA(name, size) CHAR __ach##name[size];\
+                                STRA  name;
+
+#define INLINE_STRA_INIT(name) name(InitHelper(__ach##name), sizeof(__ach##name))
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/IISLib/stringu.cpp b/src/IISIntegration/src/AspNetCoreModuleV2/IISLib/stringu.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..15da79a7fe1dc5bef14520dd48225d2b6b5cb6a8
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/IISLib/stringu.cpp
@@ -0,0 +1,1271 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#pragma warning (disable : 4267)
+
+#include "precomp.h"
+
+STRU::STRU(
+    VOID
+) : m_cchLen( 0 )
+{
+    *(QueryStr()) = L'\0';
+}
+
+STRU::STRU(
+    __inout_ecount(cchInit) WCHAR* pbInit,
+    __in DWORD cchInit
+) : m_Buff( pbInit, cchInit * sizeof( WCHAR ) ),
+    m_cchLen( 0 )
+/*++
+    Description:
+
+        Used by STACK_STRU. Initially populates underlying buffer with pbInit.
+
+        pbInit is not freed.
+
+    Arguments:
+
+        pbInit - initial memory to use
+        cchInit - count, in characters, of pbInit
+
+    Returns:
+
+        None.
+
+--*/
+{
+    _ASSERTE( cchInit <= (MAXDWORD / sizeof( WCHAR )) );
+    _ASSERTE( NULL != pbInit );
+    _ASSERTE(cchInit > 0 );
+    _ASSERTE(pbInit[0] == L'\0');
+}
+
+BOOL
+STRU::IsEmpty(
+    VOID
+) const
+{
+    return ( m_cchLen == 0 );
+}
+
+DWORD
+STRU::QueryCB(
+    VOID
+) const
+//
+// Returns the number of bytes in the string excluding the terminating NULL
+//
+{
+    return m_cchLen * sizeof( WCHAR );
+}
+
+DWORD
+STRU::QueryCCH(
+    VOID
+) const
+//
+//  Returns the number of characters in the string excluding the terminating NULL
+//
+{
+    return m_cchLen;
+}
+
+DWORD
+STRU::QuerySizeCCH(
+    VOID
+) const
+//
+// Returns size of the underlying storage buffer, in characters
+//
+{
+    return m_Buff.QuerySize() / sizeof( WCHAR );
+}
+
+__nullterminated
+__ecount(this->m_cchLen)
+WCHAR*
+STRU::QueryStr(
+    VOID
+) const
+//
+//  Return the string buffer
+//
+{
+    return m_Buff.QueryPtr();
+}
+
+VOID
+STRU::Reset(
+    VOID
+)
+//
+// Resets the internal string to be NULL string. Buffer remains cached.
+//
+{
+    _ASSERTE( QueryStr() != NULL );
+    *(QueryStr()) = L'\0';
+    m_cchLen = 0;
+}
+
+HRESULT
+STRU::Resize(
+    DWORD cchSize
+)
+{
+    SIZE_T cbSize = cchSize * sizeof( WCHAR );
+    if ( cbSize > MAXDWORD )
+    {
+        return HRESULT_FROM_WIN32( ERROR_ARITHMETIC_OVERFLOW );
+    }
+    if( !m_Buff.Resize( cbSize ) )
+    {
+        return E_OUTOFMEMORY;
+    }
+
+    return S_OK;
+}
+
+HRESULT
+STRU::SyncWithBuffer(
+    VOID
+)
+//
+// Recalculate the length of the string, etc. because we've modified
+// the buffer directly.
+//
+{
+    HRESULT hr;
+    size_t size;
+    hr = StringCchLengthW( QueryStr(),
+                           QuerySizeCCH(),
+                           &size );
+    if ( SUCCEEDED( hr ) )
+    {
+        m_cchLen = static_cast<DWORD>(size);
+    }
+    return hr;
+}
+
+HRESULT
+STRU::Copy(
+    __in PCWSTR pszCopy
+)
+{
+    HRESULT hr;
+    size_t  cbStr;
+
+    hr = StringCchLengthW( pszCopy,
+                          STRSAFE_MAX_CCH,
+                          &cbStr );
+    if ( FAILED( hr ) )
+    {
+        return hr;
+    }
+
+    _ASSERTE( cbStr <= MAXDWORD );
+    return Copy( pszCopy,
+                 cbStr );
+}
+
+HRESULT
+STRU::Copy(
+    __in_ecount(cchLen)
+    PCWSTR  pszCopy,
+    SIZE_T  cchLen
+)
+//
+// Copy the contents of another string to this one
+//
+{
+    return AuxAppend( pszCopy,
+                      cchLen * sizeof(WCHAR),
+                      0);
+}
+
+HRESULT
+STRU::Copy(
+    __in const STRU * pstrRhs
+)
+{
+    _ASSERTE( NULL != pstrRhs );
+    return Copy( pstrRhs->QueryStr(), pstrRhs->QueryCCH() );
+}
+
+HRESULT
+STRU::Copy(
+    __in const STRU & str
+)
+{
+    return Copy( str.QueryStr(), str.QueryCCH() );
+}
+
+HRESULT
+STRU::CopyAndExpandEnvironmentStrings(
+    __in PCWSTR     pszSource
+)
+{
+    HRESULT hr = S_OK;
+    DWORD   cchDestReqBuff = 0;
+
+    Reset();
+
+    cchDestReqBuff = ExpandEnvironmentStringsW( pszSource,
+                                                QueryStr(),
+                                                QuerySizeCCH() );
+    if ( cchDestReqBuff == 0 )
+    {
+        hr = HRESULT_FROM_WIN32( GetLastError() );
+        goto Finished;
+    }
+    else if ( cchDestReqBuff > QuerySizeCCH() )
+    {
+        hr = Resize( cchDestReqBuff );
+        if ( FAILED( hr ) )
+        {
+            goto Finished;
+        }
+
+        cchDestReqBuff = ExpandEnvironmentStringsW( pszSource,
+                                                    QueryStr(),
+                                                    QuerySizeCCH() );
+
+        if ( cchDestReqBuff == 0 || cchDestReqBuff > QuerySizeCCH() )
+        {
+            _ASSERTE( FALSE );
+            hr = HRESULT_FROM_WIN32( GetLastError() );
+            goto Finished;
+        }
+    }
+
+    hr = SyncWithBuffer();
+    if ( FAILED( hr ) )
+    {
+        goto Finished;
+    }
+
+Finished:
+
+    return hr;
+
+}
+
+HRESULT
+STRU::CopyA(
+    __in PCSTR  pszCopyA
+)
+{
+    HRESULT hr;
+    size_t  cbStr;
+
+    hr = StringCbLengthA( pszCopyA,
+                          STRSAFE_MAX_CCH,
+                          &cbStr );
+    if ( FAILED( hr ) )
+    {
+        return hr;
+    }
+
+    _ASSERTE( cbStr <= MAXDWORD );
+    return CopyA( pszCopyA,
+                  cbStr );
+}
+
+HRESULT
+STRU::CopyA(
+    __in_bcount(cchLen)
+    PCSTR   pszCopyA,
+    SIZE_T  cchLen,
+    UINT    CodePage /*= CP_UTF8*/
+)
+{
+    return AuxAppendA(
+        pszCopyA,
+        cchLen,
+        0,
+        CodePage
+    );
+}
+
+HRESULT
+STRU::Append(
+    __in PCWSTR  pszAppend
+)
+{
+    HRESULT hr;
+    size_t  cbStr;
+
+    hr = StringCchLengthW( pszAppend,
+                           STRSAFE_MAX_CCH,
+                           &cbStr );
+    if ( FAILED( hr ) )
+    {
+        return hr;
+    }
+
+    _ASSERTE( cbStr <= MAXDWORD );
+    return Append( pszAppend,
+                   cbStr );
+}
+
+HRESULT
+STRU::Append(
+    __in_ecount(cchLen)
+    PCWSTR  pszAppend,
+    SIZE_T  cchLen
+)
+//
+// Append something to the end of the string
+//
+{
+    if ( cchLen == 0 )
+    {
+        return S_OK;
+    }
+    return AuxAppend( pszAppend,
+                      cchLen * sizeof(WCHAR),
+                      QueryCB() );
+}
+
+HRESULT
+STRU::Append(
+    __in const STRU * pstrRhs
+)
+{
+    _ASSERTE( NULL != pstrRhs );
+    return Append( pstrRhs->QueryStr(), pstrRhs->QueryCCH() );
+}
+
+HRESULT
+STRU::Append(
+    __in const STRU & strRhs
+)
+{
+    return Append( strRhs.QueryStr(), strRhs.QueryCCH() );
+}
+
+HRESULT
+STRU::AppendA(
+    __in PCSTR  pszAppendA
+)
+{
+    HRESULT hr;
+    size_t  cbStr;
+
+    hr = StringCbLengthA( pszAppendA,
+                          STRSAFE_MAX_CCH,
+                          &cbStr );
+    if ( FAILED( hr ) )
+    {
+        return hr;
+    }
+
+    _ASSERTE( cbStr <= MAXDWORD );
+    return AppendA( pszAppendA,
+                    cbStr );
+}
+
+HRESULT
+STRU::AppendA(
+    __in_bcount(cchLen)
+    PCSTR   pszAppendA,
+    SIZE_T  cchLen,
+    UINT    CodePage /*= CP_UTF8*/
+)
+{
+    if ( cchLen == 0 )
+    {
+        return S_OK;
+    }
+    return AuxAppendA(
+        pszAppendA,
+        cchLen,
+        QueryCB(),
+        CodePage
+    );
+}
+
+HRESULT
+STRU::CopyToBuffer(
+    __out_bcount(*pcb) WCHAR*   pszBuffer,
+    PDWORD                      pcb
+) const
+//
+// Makes a copy of the stored string into the given buffer
+//
+{
+    _ASSERTE( NULL != pszBuffer );
+    _ASSERTE( NULL != pcb );
+
+    HRESULT hr          = S_OK;
+    DWORD   cbNeeded    = QueryCB() + sizeof( WCHAR );
+
+    if( *pcb < cbNeeded )
+    {
+        hr = HRESULT_FROM_WIN32( ERROR_INSUFFICIENT_BUFFER );
+        goto Finished;
+    }
+
+    //
+    // BUGBUG: StringCchCopy?
+    //
+    memcpy( pszBuffer, QueryStr(), cbNeeded );
+
+Finished:
+
+    *pcb = cbNeeded;
+
+    return hr;
+}
+
+HRESULT
+STRU::SetLen(
+    __in DWORD cchLen
+)
+/*++
+ *
+Routine Description:
+
+    Set the length of the string and null terminate, if there
+    is sufficient buffer already allocated. Will not reallocate.
+
+Arguments:
+
+    cchLen - The number of characters in the new string.
+
+Return Value:
+
+    HRESULT
+
+--*/
+{
+    if( cchLen >= QuerySizeCCH() )
+    {
+        return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
+    }
+
+    *( QueryStr() + cchLen ) = L'\0';
+    m_cchLen = cchLen;
+
+    return S_OK;
+}
+
+HRESULT
+STRU::SafeSnwprintf(
+    __in PCWSTR pwszFormatString,
+    ...
+)
+/*++
+
+Routine Description:
+
+    Writes to a STRU, growing it as needed. It arbitrarily caps growth at 64k chars.
+
+Arguments:
+
+    pwszFormatString    - printf format
+    ...                 - printf args
+
+Return Value:
+
+    HRESULT
+
+--*/
+{
+    HRESULT     hr = S_OK;
+    va_list     argsList;
+    va_start(   argsList, pwszFormatString );
+
+    hr = SafeVsnwprintf(pwszFormatString, argsList);
+
+    va_end( argsList );
+    return hr;
+}
+
+HRESULT
+STRU::SafeVsnwprintf(
+    __in PCWSTR pwszFormatString,
+    va_list     argsList
+)
+/*++
+
+Routine Description:
+
+    Writes to a STRU, growing it as needed. It arbitrarily caps growth at 64k chars.
+
+Arguments:
+
+    pwszFormatString    - printf format
+    argsList            - printf va_list
+
+Return Value:
+
+    HRESULT
+
+--*/
+{
+    HRESULT     hr = S_OK;
+    int         cchOutput;
+    int         cchNeeded;
+
+    //
+    // Format the incoming message using vsnprintf()
+    // so that the overflows are captured
+    //
+    cchOutput = _vsnwprintf_s(
+            QueryStr(),
+            QuerySizeCCH(),
+            QuerySizeCCH() - 1,
+            pwszFormatString,
+            argsList
+        );
+
+    if( cchOutput == -1 )
+    {
+        //
+        // Couldn't fit this in the original STRU size.
+        //
+        cchNeeded = _vscwprintf( pwszFormatString, argsList );
+        if( cchNeeded > 64 * 1024 )
+        {
+            //
+            // If we're trying to produce a string > 64k chars, then
+            // there is probably a problem
+            //
+            hr = HRESULT_FROM_WIN32( ERROR_INVALID_DATA );
+            goto Finished;
+        }
+
+        //
+        // _vscprintf doesn't include terminating null character
+        //
+        cchNeeded++;
+
+        hr = Resize( cchNeeded );
+        if( FAILED( hr ) )
+        {
+            goto Finished;
+        }
+
+        cchOutput = _vsnwprintf_s(
+            QueryStr(),
+            QuerySizeCCH(),
+            QuerySizeCCH() - 1,
+            pwszFormatString,
+            argsList
+        );
+        if( -1 == cchOutput )
+        {
+            //
+            // This should never happen, cause we should already have correctly sized memory
+            //
+            _ASSERTE( FALSE );
+
+            hr = HRESULT_FROM_WIN32( ERROR_INVALID_DATA );
+            goto Finished;
+        }
+    }
+
+    //
+    // always null terminate at the last WCHAR
+    //
+    QueryStr()[ QuerySizeCCH() - 1 ] = L'\0';
+
+    //
+    // we directly touched the buffer - therefore:
+    //
+    hr = SyncWithBuffer();
+    if ( FAILED( hr ) )
+    {
+        goto Finished;
+    }
+
+Finished:
+
+    if( FAILED( hr ) )
+    {
+        Reset();
+    }
+
+    return hr;
+}
+
+HRESULT
+STRU::AuxAppend(
+    __in_ecount(cNumStrings)
+    PCWSTR const    rgpszStrings[],
+    SIZE_T          cNumStrings
+)
+/*++
+
+Routine Description:
+
+    Appends an array of strings of length cNumStrings
+
+Arguments:
+
+    rgStrings   - The array of strings to be appened
+    cNumStrings - The count of String
+
+Return Value:
+
+    HRESULT
+
+--*/
+{
+    HRESULT         hr = S_OK;
+    size_t          cbStringsTotal = sizeof( WCHAR ); // Account for null-terminator
+
+    //
+    //  Compute total size of the string.
+    //  Resize internal buffer
+    //  Copy each array element one by one to backing buffer
+    //  Update backing buffer string length
+    //
+    for ( SIZE_T i = 0; i < cNumStrings; i++ )
+    {
+        _ASSERTE( rgpszStrings[ i ] != NULL );
+        if ( NULL == rgpszStrings[ i ] )
+        {
+            return E_INVALIDARG;
+        }
+
+        size_t      cbString = 0;
+
+        hr = StringCbLengthW( rgpszStrings[ i ],
+                             STRSAFE_MAX_CCH * sizeof( WCHAR ),
+                             &cbString );
+        if ( FAILED( hr ) )
+        {
+            return hr;
+        }
+
+        cbStringsTotal += cbString;
+
+        if ( cbStringsTotal > MAXDWORD )
+        {
+            return HRESULT_FROM_WIN32( ERROR_ARITHMETIC_OVERFLOW );
+        }
+    }
+
+    size_t cbBufSizeRequired = QueryCB() + cbStringsTotal;
+    if ( cbBufSizeRequired > MAXDWORD )
+    {
+        return HRESULT_FROM_WIN32( ERROR_ARITHMETIC_OVERFLOW );
+    }
+
+    if( m_Buff.QuerySize() < cbBufSizeRequired )
+    {
+        if( !m_Buff.Resize( cbBufSizeRequired ) )
+        {
+            return E_OUTOFMEMORY;
+        }
+    }
+
+    STRSAFE_LPWSTR pszStringEnd = QueryStr() + QueryCCH();
+    size_t cchRemaining = QuerySizeCCH() - QueryCCH();
+    for ( SIZE_T i = 0; i < cNumStrings; i++ )
+    {
+        hr = StringCchCopyExW( pszStringEnd,        //  pszDest
+                               cchRemaining,        //  cchDest
+                               rgpszStrings[ i ],   //  pszSrc
+                               &pszStringEnd,       //  ppszDestEnd
+                               &cchRemaining,       //  pcchRemaining
+                               0 );                 //  dwFlags
+        if ( FAILED( hr ) )
+        {
+            _ASSERTE( FALSE );
+            HRESULT hr2 = SyncWithBuffer();
+            if ( FAILED( hr2 ) )
+            {
+                return hr2;
+            }
+            return hr;
+        }
+    }
+
+    m_cchLen = static_cast< DWORD >( cbBufSizeRequired ) / sizeof( WCHAR ) - 1;
+
+    return S_OK;
+}
+
+HRESULT
+STRU::AuxAppend(
+    __in_bcount(cbStr)
+    const WCHAR*    pStr,
+    SIZE_T          cbStr,
+    DWORD           cbOffset
+)
+/*++
+
+Routine Description:
+
+    Appends to the string starting at the (byte) offset cbOffset.
+
+Arguments:
+
+    pStr     - A unicode string to be appended
+    cbStr    - Length, in bytes, of pStr
+    cbOffset - Offset, in bytes, at which to begin the append
+
+Return Value:
+
+    HRESULT
+
+--*/
+{
+    _ASSERTE( NULL != pStr );
+    _ASSERTE( 0 == cbStr % sizeof( WCHAR ) );
+    _ASSERTE( cbOffset <= QueryCB() );
+    _ASSERTE( 0 == cbOffset % sizeof( WCHAR ) );
+
+    ULONGLONG cb64NewSize = (ULONGLONG)cbOffset + cbStr + sizeof( WCHAR );
+    if( cb64NewSize > MAXDWORD )
+    {
+        return HRESULT_FROM_WIN32( ERROR_ARITHMETIC_OVERFLOW );
+    }
+
+    if( m_Buff.QuerySize() < cb64NewSize )
+    {
+        if( !m_Buff.Resize( static_cast<SIZE_T>(cb64NewSize) ) )
+        {
+            return E_OUTOFMEMORY;
+        }
+    }
+
+    memcpy( reinterpret_cast<BYTE*>(m_Buff.QueryPtr()) + cbOffset, pStr, cbStr );
+
+    m_cchLen = (static_cast<DWORD>(cbStr) + cbOffset) / sizeof(WCHAR);
+
+    *( QueryStr() + m_cchLen ) = L'\0';
+
+    return S_OK;
+}
+
+HRESULT
+STRU::AuxAppendA(
+    __in_bcount(cbStr)
+    const CHAR*     pStr,
+    SIZE_T          cbStr,
+    DWORD           cbOffset,
+    UINT            CodePage
+)
+/*++
+
+Routine Description:
+
+    Convert and append an ANSI string to the string starting at
+    the (byte) offset cbOffset
+
+Arguments:
+
+    pStr     - An ANSI string to be appended
+    cbStr    - Length, in bytes, of pStr
+    cbOffset - Offset, in bytes, at which to begin the append
+    CodePage - code page to use for conversion
+
+Return Value:
+
+    HRESULT
+
+--*/
+{
+    WCHAR*  pszBuffer;
+    DWORD   cchBuffer;
+    DWORD   cchCharsCopied = 0;
+
+    _ASSERTE( NULL != pStr );
+    _ASSERTE( cbOffset <= QueryCB() );
+    _ASSERTE( 0 == cbOffset % sizeof( WCHAR ) );
+
+    if ( NULL == pStr )
+    {
+        return E_INVALIDARG;
+    }
+
+    if( 0 == cbStr )
+    {
+        return S_OK;
+    }
+
+    //
+    //  Only resize when we have to.  When we do resize, we tack on
+    //  some extra space to avoid extra reallocations.
+    //
+    if( m_Buff.QuerySize() < (ULONGLONG)cbOffset + (cbStr * sizeof( WCHAR )) + sizeof(WCHAR) )
+    {
+        ULONGLONG cb64NewSize = (ULONGLONG)( cbOffset + cbStr * sizeof(WCHAR) + sizeof( WCHAR ) );
+
+        //
+        // Check for the arithmetic overflow
+        //
+        if( cb64NewSize > MAXDWORD )
+        {
+            return HRESULT_FROM_WIN32( ERROR_ARITHMETIC_OVERFLOW );
+        }
+
+        if( !m_Buff.Resize( static_cast<SIZE_T>(cb64NewSize) ) )
+        {
+            return E_OUTOFMEMORY;
+        }
+    }
+
+    pszBuffer = reinterpret_cast<WCHAR*>(reinterpret_cast<BYTE*>(m_Buff.QueryPtr()) + cbOffset);
+    cchBuffer = ( m_Buff.QuerySize() - cbOffset - sizeof( WCHAR ) ) / sizeof( WCHAR );
+
+    cchCharsCopied = MultiByteToWideChar(
+        CodePage,
+        MB_ERR_INVALID_CHARS,
+        pStr,
+        static_cast<int>(cbStr),
+        pszBuffer,
+        cchBuffer
+    );
+    if( 0 == cchCharsCopied )
+    {
+        return HRESULT_FROM_WIN32( GetLastError() );
+    }
+
+    //
+    // set the new length
+    //
+    m_cchLen = cchCharsCopied + cbOffset/sizeof(WCHAR);
+
+    //
+    // Must be less than, cause still need to add NULL
+    //
+    _ASSERTE( m_cchLen < QuerySizeCCH() );
+
+    //
+    // append NULL character
+    //
+    *(QueryStr() + m_cchLen) = L'\0';
+
+    return S_OK;
+}
+
+
+/*++
+
+Routine Description:
+
+    Removes leading and trailing whitespace
+
+--*/
+
+VOID
+STRU::Trim()
+{
+    PWSTR               pwszString              = QueryStr();
+    DWORD               cchNewLength            = m_cchLen;
+    DWORD               cchLeadingWhitespace    = 0;
+    DWORD               cchTempLength           = 0;
+
+    for (LONG ixString = m_cchLen - 1; ixString >= 0; ixString--)
+    {
+        if (iswspace(pwszString[ixString]) != 0)
+        {
+            pwszString[ixString] = L'\0';
+            cchNewLength--;
+        }
+        else
+        {
+            break;
+        }
+    }
+
+    cchTempLength = cchNewLength;
+    for (DWORD ixString = 0; ixString < cchTempLength; ixString++)
+    {
+        if (iswspace(pwszString[ixString]) != 0)
+        {
+            cchLeadingWhitespace++;
+            cchNewLength--;
+        }
+        else
+        {
+            break;
+        }
+    }
+
+    if (cchNewLength == 0)
+    {
+
+        Reset();
+    }
+    else if (cchLeadingWhitespace > 0)
+    {
+        memmove(pwszString, pwszString + cchLeadingWhitespace, cchNewLength * sizeof(WCHAR));
+        pwszString[cchNewLength] = L'\0';
+    }
+
+    SyncWithBuffer();
+}
+
+/*++
+
+Routine Description:
+
+    Compares the string to the provided prefix to check for equality
+
+Arguments:
+
+    pwszPrefix  - wide char string to compare with
+    fIgnoreCase - indicates whether the string comparison should be case-sensitive
+
+Return Value:
+
+    TRUE if prefix string matches with internal string, FALSE otherwise
+
+--*/
+
+BOOL
+STRU::StartsWith(
+    __in PCWSTR         pwszPrefix,
+    __in bool           fIgnoreCase) const
+{
+    HRESULT hr          = S_OK;
+    BOOL    fMatch      = FALSE;
+    size_t  cchPrefix   = 0;
+
+    if (pwszPrefix == NULL)
+    {
+        goto Finished;
+    }
+
+    hr = StringCchLengthW( pwszPrefix,
+                           STRSAFE_MAX_CCH,
+                           &cchPrefix );
+    if (FAILED(hr))
+    {
+        goto Finished;
+    }
+
+    _ASSERTE( cchPrefix <= MAXDWORD );
+
+    if (cchPrefix > m_cchLen)
+    {
+        goto Finished;
+    }
+
+    #if defined( NTDDI_VERSION ) && NTDDI_VERSION >= NTDDI_LONGHORN
+
+        fMatch = ( CSTR_EQUAL == CompareStringOrdinal( QueryStr(),
+                                                       cchPrefix,
+                                                       pwszPrefix,
+                                                       cchPrefix,
+                                                       fIgnoreCase ) );
+    #else
+
+        if( fIgnoreCase )
+        {
+            fMatch = ( 0 == _wcsnicmp( QueryStr(), pwszPrefix, cchPrefix ) );
+        }
+        else
+        {
+            fMatch = ( 0 == wcsncmp( QueryStr(), pwszPrefix, cchPrefix ) );
+        }
+
+    #endif
+
+Finished:
+
+    return fMatch;
+}
+
+/*++
+
+Routine Description:
+
+    Compares the string to the provided suffix to check for equality
+
+Arguments:
+
+    pwszSuffix  - wide char string to compare with
+    fIgnoreCase - indicates whether the string comparison should be case-sensitive
+
+Return Value:
+
+    TRUE if suffix string matches with internal string, FALSE otherwise
+
+--*/
+
+
+BOOL
+STRU::EndsWith(
+    __in PCWSTR         pwszSuffix,
+    __in bool           fIgnoreCase) const
+{
+    HRESULT     hr          = S_OK;
+    PWSTR       pwszString  = QueryStr();
+    BOOL        fMatch      = FALSE;
+    size_t      cchSuffix   = 0;
+    ptrdiff_t   ixOffset    = 0;
+
+    if (pwszSuffix == NULL)
+    {
+        goto Finished;
+    }
+
+    hr = StringCchLengthW( pwszSuffix,
+                           STRSAFE_MAX_CCH,
+                           &cchSuffix );
+    if (FAILED(hr))
+    {
+        goto Finished;
+    }
+
+    _ASSERTE( cchSuffix <= MAXDWORD );
+
+    if (cchSuffix > m_cchLen)
+    {
+        goto Finished;
+    }
+
+    ixOffset = m_cchLen - cchSuffix;
+    _ASSERTE(ixOffset >= 0 && ixOffset <= MAXDWORD);
+
+    #if defined( NTDDI_VERSION ) && NTDDI_VERSION >= NTDDI_LONGHORN
+
+        fMatch = ( CSTR_EQUAL == CompareStringOrdinal( pwszString + ixOffset,
+                                                       cchSuffix,
+                                                       pwszSuffix,
+                                                       cchSuffix,
+                                                       fIgnoreCase ) );
+    #else
+
+        if( fIgnoreCase )
+        {
+            fMatch = ( 0 == _wcsnicmp( pwszString + ixOffset, pwszSuffix, cchSuffix ) );
+        }
+        else
+        {
+            fMatch = ( 0 == wcsncmp( pwszString + ixOffset, pwszSuffix, cchSuffix ) );
+        }
+
+    #endif
+
+Finished:
+
+    return fMatch;
+}
+
+/*++
+
+Routine Description:
+
+    Searches the string for the first occurrence of the specified character.
+
+Arguments:
+
+    charValue       - character to find
+    dwStartIndex    - the initial index.
+
+Return Value:
+
+    The index for the first character occurence in the string.
+
+    -1 if not found.
+
+--*/
+INT
+STRU::IndexOf(
+    __in WCHAR          charValue,
+    __in DWORD          dwStartIndex
+    ) const
+{
+    INT nIndex = -1;
+
+    // Make sure that there are no buffer overruns.
+    if( dwStartIndex >= QueryCCH() )
+    {
+        goto Finished;
+    }
+
+    const WCHAR* pwChar = wcschr( QueryStr() + dwStartIndex, charValue );
+
+    // Determine the index if found
+    if( pwChar )
+    {
+        // nIndex will be set to -1 on failure.
+        (VOID)SizeTToInt( pwChar - QueryStr(), &nIndex );
+    }
+
+Finished:
+
+    return nIndex;
+}
+
+
+/*++
+
+Routine Description:
+
+    Searches the string for the first occurrence of the specified substring.
+
+Arguments:
+
+    pwszValue       - substring to find
+    dwStartIndex    - initial index.
+
+Return Value:
+
+    The index for the first character occurence in the string.
+
+    -1 if not found.
+
+--*/
+INT
+STRU::IndexOf(
+    __in PCWSTR         pwszValue,
+    __in DWORD          dwStartIndex
+    ) const
+{
+    HRESULT hr = S_OK;
+    INT nIndex = -1;
+    SIZE_T cchValue = 0;
+
+    // Validate input parameters
+    if( dwStartIndex >= QueryCCH() || !pwszValue )
+    {
+        goto Finished;
+    }
+
+    const WCHAR* pwChar = wcsstr( QueryStr() + dwStartIndex, pwszValue );
+
+    // Determine the index if found
+    if( pwChar )
+    {
+        // nIndex will be set to -1 on failure.
+        (VOID)SizeTToInt( pwChar - QueryStr(), &nIndex );
+    }
+
+Finished:
+
+    return nIndex;
+}
+
+
+/*++
+
+Routine Description:
+
+    Searches the string for the last occurrence of the specified character.
+
+Arguments:
+
+    charValue       - character to find
+    dwStartIndex    - initial index.
+
+Return Value:
+
+    The index for the last character occurence in the string.
+
+    -1 if not found.
+
+--*/
+INT
+STRU::LastIndexOf(
+    __in WCHAR          charValue,
+    __in DWORD          dwStartIndex
+    ) const
+{
+    INT nIndex = -1;
+
+    // Make sure that there are no buffer overruns.
+    if( dwStartIndex >= QueryCCH() )
+    {
+        goto Finished;
+    }
+
+    const WCHAR* pwChar = wcsrchr( QueryStr() + dwStartIndex, charValue );
+
+    // Determine the index if found
+    if( pwChar )
+    {
+        // nIndex will be set to -1 on failure.
+        (VOID)SizeTToInt( pwChar - QueryStr(), &nIndex );
+    }
+
+Finished:
+
+    return nIndex;
+}
+
+//static
+HRESULT
+STRU::ExpandEnvironmentVariables(
+    __in  PCWSTR                  pszString,
+    __out STRU *                  pstrExpandedString
+    )
+/*++
+
+Routine Description:
+
+    Expand the environment variables in a string
+
+Arguments:
+
+    pszString - String with environment variables to expand
+    pstrExpandedString - Receives expanded string on success
+
+Return Value:
+
+    HRESULT
+
+--*/
+{
+    HRESULT                 hr              = S_OK;
+    DWORD                   cchNewSize      = 0;
+
+    if ( pszString == NULL ||
+         pstrExpandedString == NULL )
+    {
+        DBG_ASSERT( FALSE );
+        hr = HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
+        goto Exit;
+    }
+
+    cchNewSize = ExpandEnvironmentStrings( pszString,
+                                           pstrExpandedString->QueryStr(),
+                                           pstrExpandedString->QuerySizeCCH() );
+    if ( cchNewSize == 0 )
+    {
+        hr = HRESULT_FROM_WIN32( GetLastError() );
+        goto Exit;
+    }
+
+    if ( cchNewSize > pstrExpandedString->QuerySizeCCH() )
+    {
+        hr = pstrExpandedString->Resize(
+            ( cchNewSize + 1 ) * sizeof( WCHAR )
+            );
+        if ( FAILED( hr ) )
+        {
+            goto Exit;
+        }
+
+        cchNewSize = ExpandEnvironmentStrings(
+            pszString,
+            pstrExpandedString->QueryStr(),
+            pstrExpandedString->QuerySizeCCH()
+            );
+
+        if ( cchNewSize == 0 ||
+             cchNewSize > pstrExpandedString->QuerySizeCCH() )
+        {
+            hr = HRESULT_FROM_WIN32( GetLastError() );
+            goto Exit;
+        }
+    }
+
+    pstrExpandedString->SyncWithBuffer();
+
+    hr = S_OK;
+
+Exit:
+
+    return hr;
+}
+
+#pragma warning(default:4267)
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/IISLib/stringu.h b/src/IISIntegration/src/AspNetCoreModuleV2/IISLib/stringu.h
new file mode 100644
index 0000000000000000000000000000000000000000..6f27c5421dc5b72bdc70ea434d51e86d1f8620b7
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/IISLib/stringu.h
@@ -0,0 +1,427 @@
+// 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 "buffer.h"
+#include <strsafe.h>
+
+class STRU
+{
+
+public:
+
+    STRU(
+        VOID
+    );
+
+    STRU(
+        __inout_ecount(cchInit) WCHAR* pbInit,
+        __in DWORD cchInit
+    );
+
+    BOOL
+    IsEmpty(
+        VOID
+    ) const;
+
+    BOOL
+    Equals(
+        __in const STRU *  pstrRhs,
+        __in BOOL           fIgnoreCase = FALSE
+    ) const
+    {
+        _ASSERTE( pstrRhs != NULL );
+        return Equals( pstrRhs->QueryStr(), fIgnoreCase );
+    }
+
+    BOOL
+    Equals(
+        __in const STRU &  strRhs,
+        __in BOOL           fIgnoreCase = FALSE
+    ) const
+    {
+        return Equals( strRhs.QueryStr(), fIgnoreCase );
+    }
+
+    BOOL
+    Equals(
+        __in PCWSTR pszRhs,
+        __in BOOL   fIgnoreCase = FALSE
+    ) const
+    {
+        _ASSERTE( NULL != pszRhs );
+        if ( NULL == pszRhs )
+        {
+            return FALSE;
+        }
+
+    #if defined( NTDDI_VERSION ) && NTDDI_VERSION >= NTDDI_LONGHORN
+
+        return ( CSTR_EQUAL == CompareStringOrdinal( QueryStr(),
+                                                     QueryCCH(),
+                                                     pszRhs,
+                                                     -1,
+                                                     fIgnoreCase ) );
+    #else
+
+        if( fIgnoreCase )
+        {
+            return ( 0 == _wcsicmp( QueryStr(), pszRhs ) );
+        }
+        return ( 0 == wcscmp( QueryStr(), pszRhs ) );
+
+    #endif
+    }
+
+
+    static
+    BOOL
+    Equals(
+        __in PCWSTR pwszLhs,
+        __in PCWSTR pwszRhs,
+        __in bool   fIgnoreCase = false
+    )
+    {
+        // Return FALSE if either or both strings are NULL.
+        if (!pwszLhs || !pwszRhs) return FALSE;
+
+    //
+    // This method performs a ordinal string comparison when OS is Vista or
+    // greater and a culture sensitive comparison if not (XP). This is
+    // consistent with the existing Equals implementation (see above).
+    //
+#if defined( NTDDI_VERSION ) && NTDDI_VERSION >= NTDDI_LONGHORN
+
+        return ( CSTR_EQUAL == CompareStringOrdinal( pwszLhs,
+                                                     -1,
+                                                     pwszRhs,
+                                                     -1,
+                                                     fIgnoreCase ) );
+#else
+
+        if( fIgnoreCase )
+        {
+            return ( 0 == _wcsicmp( pwszLhs, pwszRhs ) );
+        }
+        else
+        {
+            return ( 0 == wcscmp( pwszLhs, pwszRhs ) );
+        }
+
+#endif
+    }
+
+    VOID
+    Trim();
+
+    BOOL
+    StartsWith(
+        __in const STRU *   pStruPrefix,
+        __in bool           fIgnoreCase = FALSE
+    ) const
+    {
+        _ASSERTE( pStruPrefix != NULL );
+        return StartsWith( pStruPrefix->QueryStr(), fIgnoreCase );
+    }
+
+    BOOL
+    StartsWith(
+        __in const STRU &   struPrefix,
+        __in bool           fIgnoreCase = FALSE
+    ) const
+    {
+        return StartsWith( struPrefix.QueryStr(), fIgnoreCase );
+    }
+
+    BOOL
+    StartsWith(
+        __in PCWSTR         pwszPrefix,
+        __in bool           fIgnoreCase = FALSE
+    ) const;
+
+    BOOL
+    EndsWith(
+        __in const STRU *   pStruSuffix,
+        __in bool           fIgnoreCase = FALSE
+    ) const
+    {
+        _ASSERTE( pStruSuffix != NULL );
+        return EndsWith( pStruSuffix->QueryStr(), fIgnoreCase );
+    }
+
+    BOOL
+    EndsWith(
+        __in const STRU &   struSuffix,
+        __in bool           fIgnoreCase = FALSE
+    ) const
+    {
+        return EndsWith( struSuffix.QueryStr(), fIgnoreCase );
+    }
+
+    BOOL
+    EndsWith(
+        __in PCWSTR         pwszSuffix,
+        __in bool           fIgnoreCase = FALSE
+    ) const;
+
+    INT
+    IndexOf(
+        __in WCHAR          charValue,
+        __in DWORD          dwStartIndex = 0
+    ) const;
+
+    INT
+    IndexOf(
+        __in PCWSTR         pwszValue,
+        __in DWORD          dwStartIndex = 0
+    ) const;
+
+    INT
+    LastIndexOf(
+        __in WCHAR          charValue,
+        __in DWORD          dwStartIndex = 0
+    ) const;
+
+    DWORD
+    QueryCB(
+        VOID
+    ) const;
+
+    DWORD
+    QueryCCH(
+        VOID
+    ) const;
+
+    DWORD
+    QuerySizeCCH(
+        VOID
+    ) const;
+
+    __nullterminated
+    __ecount(this->m_cchLen)
+    WCHAR*
+    QueryStr(
+        VOID
+    ) const;
+
+    VOID
+    Reset(
+        VOID
+    );
+
+    HRESULT
+    Resize(
+        DWORD cchSize
+    );
+
+    HRESULT
+    SyncWithBuffer(
+        VOID
+    );
+
+    template<size_t size>
+    HRESULT
+    Copy(
+        __in PCWSTR const (&rgpszStrings)[size]
+    )
+    //
+    // Copies an array of strings declared as stack array. For example:
+    //
+    // LPCWSTR rgExample[] { L"one", L"two" };
+    // hr = str.Copy( rgExample );
+    //
+    {
+        Reset();
+
+        return AuxAppend( rgpszStrings, _countof( rgpszStrings ) );
+    }
+
+    HRESULT
+    Copy(
+        __in PCWSTR pszCopy
+    );
+
+    HRESULT
+    Copy(
+        __in_ecount(cchLen)
+        PCWSTR  pszCopy,
+        SIZE_T  cchLen
+    );
+
+    HRESULT
+    Copy(
+        __in const STRU * pstrRhs
+    );
+
+    HRESULT
+    Copy(
+        __in const STRU & str
+    );
+
+    HRESULT
+    CopyAndExpandEnvironmentStrings(
+        __in PCWSTR     pszSource
+    );
+
+    HRESULT
+    CopyA(
+        __in PCSTR  pszCopyA
+    );
+
+    HRESULT
+    CopyA(
+        __in_bcount(cchLen)
+        PCSTR   pszCopyA,
+        SIZE_T  cchLen,
+        UINT    CodePage = CP_UTF8
+    );
+
+    template<size_t size>
+    HRESULT
+    Append(
+        __in PCWSTR const (&rgpszStrings)[size]
+    )
+    //
+    // Appends an array of strings declared as stack array. For example:
+    //
+    // LPCWSTR rgExample[] { L"one", L"two" };
+    // hr = str.Append( rgExample );
+    //
+    {
+        return AuxAppend( rgpszStrings, _countof( rgpszStrings ) );
+    }
+
+    HRESULT
+    Append(
+        __in PCWSTR  pszAppend
+    );
+
+    HRESULT
+    Append(
+        __in_ecount(cchLen)
+        PCWSTR  pszAppend,
+        SIZE_T  cchLen
+    );
+
+    HRESULT
+    Append(
+        __in const STRU * pstrRhs
+    );
+
+    HRESULT
+    Append(
+        __in const STRU & strRhs
+    );
+
+    HRESULT
+    AppendA(
+        __in PCSTR  pszAppendA
+    );
+
+    HRESULT
+    AppendA(
+        __in_bcount(cchLen)
+        PCSTR   pszAppendA,
+        SIZE_T  cchLen,
+        UINT    CodePage = CP_UTF8
+    );
+
+    HRESULT
+    CopyToBuffer(
+        __out_bcount(*pcb) WCHAR*   pszBuffer,
+        PDWORD                      pcb
+    ) const;
+
+    HRESULT
+    SetLen(
+        __in DWORD cchLen
+    );
+
+    HRESULT
+    SafeSnwprintf(
+        __in PCWSTR pwszFormatString,
+        ...
+    );
+
+    HRESULT
+    SafeVsnwprintf(
+        __in PCWSTR pwszFormatString,
+        va_list     argsList
+    );
+
+    static
+    HRESULT  ExpandEnvironmentVariables(
+        __in PCWSTR                  pszString,
+        __out STRU *                 pstrExpandedString
+    );
+
+private:
+
+    //
+    // Avoid C++ errors. This object should never go through a copy
+    // constructor, unintended cast or assignment.
+    //
+    STRU( const STRU & );
+    STRU & operator = ( const STRU & );
+
+    HRESULT
+    AuxAppend(
+        __in_ecount(cNumStrings)
+        PCWSTR const    rgpszStrings[],
+        SIZE_T          cNumStrings
+    );
+
+    HRESULT
+    AuxAppend(
+        __in_bcount(cbStr)
+        const WCHAR*    pStr,
+        SIZE_T          cbStr,
+        DWORD           cbOffset
+    );
+
+    HRESULT
+    AuxAppendA(
+        __in_bcount(cbStr)
+        const CHAR*     pStr,
+        SIZE_T          cbStr,
+        DWORD           cbOffset,
+        UINT            CodePage
+    );
+
+    //
+    // Buffer with an inline buffer of 1,
+    // enough to hold null-terminating character.
+    //
+    BUFFER_T<WCHAR,1>   m_Buff;
+    DWORD               m_cchLen;
+};
+
+//
+// Helps to initialize an external buffer before
+// constructing the STRU object.
+//
+template<DWORD size>
+WCHAR* InitHelper(__out WCHAR (&psz)[size])
+{
+    psz[0] = L'\0';
+    return psz;
+}
+
+//
+// Heap operation reduction macros
+//
+#define STACK_STRU(name, size)  WCHAR __ach##name[size];\
+                                STRU name(InitHelper(__ach##name), sizeof(__ach##name)/sizeof(*__ach##name))
+
+#define INLINE_STRU(name, size) WCHAR  __ach##name[size];\
+                                STRU  name;
+
+#define INLINE_STRU_INIT(name) name(InitHelper(__ach##name), sizeof(__ach##name)/sizeof(*__ach##name))
+
+
+HRESULT
+MakePathCanonicalizationProof(
+    IN PCWSTR               pszName,
+    OUT STRU *              pstrPath
+);
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/IISLib/tracelog.c b/src/IISIntegration/src/AspNetCoreModuleV2/IISLib/tracelog.c
new file mode 100644
index 0000000000000000000000000000000000000000..f7b2da5e43574214d09916042f79f483e462e5a3
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/IISLib/tracelog.c
@@ -0,0 +1,235 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#include <windows.h>
+#include "pudebug.h"
+#include "tracelog.h"
+#include <intsafe.h>
+
+
+#define ALLOC_MEM(cb) (PVOID)LocalAlloc( LPTR, (cb) )
+#define FREE_MEM(ptr) (VOID)LocalFree( (HLOCAL)(ptr) )
+
+
+
+PTRACE_LOG
+CreateTraceLog(
+    IN LONG LogSize,
+    IN LONG ExtraBytesInHeader,
+    IN LONG EntrySize
+    )
+/*++
+
+Routine Description:
+
+    Creates a new (empty) trace log buffer.
+
+Arguments:
+
+    LogSize - The number of entries in the log.
+
+    ExtraBytesInHeader - The number of extra bytes to include in the
+        log header. This is useful for adding application-specific
+        data to the log.
+
+    EntrySize - The size (in bytes) of each entry.
+
+Return Value:
+
+    PTRACE_LOG - Pointer to the newly created log if successful,
+        NULL otherwise.
+
+--*/
+{
+
+    ULONG ulTotalSize = 0;
+    ULONG ulLogSize = 0;
+    ULONG ulEntrySize = 0;
+    ULONG ulTmpResult = 0;
+    ULONG ulExtraBytesInHeader = 0;
+    PTRACE_LOG log = NULL;
+    HRESULT hr = S_OK;
+
+    //
+    // Sanity check the parameters.
+    //
+
+    //DBG_ASSERT( LogSize > 0 );
+    //DBG_ASSERT( EntrySize > 0 );
+    //DBG_ASSERT( ExtraBytesInHeader >= 0 );
+    //DBG_ASSERT( ( EntrySize & 3 ) == 0 );
+
+    //
+    // converting to unsigned long. Since all these values are positive
+    // so its safe to cast them to their unsigned equivalent directly.
+    //
+    ulLogSize            = (ULONG) LogSize;
+    ulEntrySize          = (ULONG) EntrySize;
+    ulExtraBytesInHeader = (ULONG) ExtraBytesInHeader;
+
+    //
+    // Check if the multiplication operation will overflow a LONG 
+    // ulTotalSize = LogSize * EntrySize;
+    //
+    hr = ULongMult( ulLogSize, ulEntrySize, &ulTotalSize );
+    if ( FAILED(hr) )
+    { 
+        SetLastError( ERROR_ARITHMETIC_OVERFLOW );
+        return NULL;
+    }
+
+    //
+    // check for overflow in addition operation.
+    // ulTmpResult = sizeof(TRACE_LOG) + ulExtraBytesInHeader
+    //
+    hr = ULongAdd( (ULONG) sizeof(TRACE_LOG), ulExtraBytesInHeader, &ulTmpResult );
+    if ( FAILED(hr) )
+    { 
+        SetLastError( ERROR_ARITHMETIC_OVERFLOW );
+        return NULL;
+    }
+  
+    //
+    // check for overflow in addition operation.
+    // ulTotalSize = ulTotalSize + ulTmpResult;
+    //
+    hr = ULongAdd( ulTmpResult, ulTotalSize, &ulTotalSize );
+    if ( FAILED(hr) )
+    { 
+        SetLastError( ERROR_ARITHMETIC_OVERFLOW );
+        return NULL;
+    }
+
+    if ( ulTotalSize > (ULONG) 0x7FFFFFFF )
+    { 
+        SetLastError( ERROR_ARITHMETIC_OVERFLOW );
+        return NULL;
+    }
+
+    //
+    // Allocate & initialize the log structure.
+    //
+
+    log = (PTRACE_LOG)ALLOC_MEM( ulTotalSize );
+
+    //
+    // Initialize it.
+    //
+
+    if( log != NULL ) {
+
+        RtlZeroMemory( log, ulTotalSize );
+
+        log->Signature = TRACE_LOG_SIGNATURE;
+        log->LogSize = LogSize;
+        log->NextEntry = -1;
+        log->EntrySize = EntrySize;
+        log->LogBuffer = (PUCHAR)( log + 1 ) + ExtraBytesInHeader;
+    }
+
+    return log;
+
+}   // CreateTraceLog
+
+
+VOID
+DestroyTraceLog(
+    IN PTRACE_LOG Log
+    )
+/*++
+
+Routine Description:
+
+    Destroys a trace log buffer created with CreateTraceLog().
+
+Arguments:
+
+    Log - The trace log buffer to destroy.
+
+Return Value:
+
+    None.
+
+--*/
+{
+        if ( Log != NULL ) {
+        //DBG_ASSERT( Log->Signature == TRACE_LOG_SIGNATURE );
+
+        Log->Signature = TRACE_LOG_SIGNATURE_X;
+        FREE_MEM( Log );
+    }
+
+}   // DestroyTraceLog
+
+
+LONG
+WriteTraceLog(
+    IN PTRACE_LOG Log,
+    IN PVOID Entry
+    )
+/*++
+
+Routine Description:
+
+    Writes a new entry to the specified trace log.
+
+Arguments:
+
+    Log - The log to write to.
+
+    Entry - Pointer to the data to write. This buffer is assumed to be
+        Log->EntrySize bytes long.
+
+Return Value:
+
+    Index of entry in log.  This is useful for correlating the output
+    of !inetdbg.ref to a particular point in the output debug stream
+
+--*/
+{
+
+    PUCHAR target;
+    ULONG index;
+
+    //DBG_ASSERT( Log != NULL );
+    //DBG_ASSERT( Log->Signature == TRACE_LOG_SIGNATURE );
+    //DBG_ASSERT( Entry != NULL );
+
+    //
+    // Find the next slot, copy the entry to the slot.
+    //
+
+    index = ( (ULONG) InterlockedIncrement( &Log->NextEntry ) ) % (ULONG) Log->LogSize;
+
+    //DBG_ASSERT( index < (ULONG) Log->LogSize );
+
+    target = Log->LogBuffer + ( index * Log->EntrySize );
+
+    RtlCopyMemory(
+        target,
+        Entry,
+        Log->EntrySize
+        );
+
+    return index;
+}   // WriteTraceLog
+
+
+VOID
+ResetTraceLog(
+    IN PTRACE_LOG Log
+    )
+{
+
+    //DBG_ASSERT( Log != NULL );
+    //DBG_ASSERT( Log->Signature == TRACE_LOG_SIGNATURE );
+
+    RtlZeroMemory(
+        ( Log + 1 ),
+        Log->LogSize * Log->EntrySize
+        );
+
+    Log->NextEntry = -1;
+
+}   // ResetTraceLog
+
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/IISLib/tracelog.h b/src/IISIntegration/src/AspNetCoreModuleV2/IISLib/tracelog.h
new file mode 100644
index 0000000000000000000000000000000000000000..ed34bcffc90b52ca8bf464f8fdfd248ebb83554d
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/IISLib/tracelog.h
@@ -0,0 +1,105 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#ifndef _TRACELOG_H_
+#define _TRACELOG_H_
+
+
+#if defined(__cplusplus)
+extern "C" {
+#endif  // __cplusplus
+
+
+typedef struct _TRACE_LOG {
+
+    //
+    // Signature.
+    //
+
+    LONG Signature;
+
+    //
+    // The total number of entries available in the log.
+    //
+
+    LONG LogSize;
+
+    //
+    // The index of the next entry to use.
+    //
+
+    LONG NextEntry;
+
+    //
+    // The byte size of each entry.
+    //
+
+    LONG EntrySize;
+
+    //
+    // Pointer to the start of the circular buffer.
+    //
+
+    PUCHAR LogBuffer;
+
+    //
+    // The extra header bytes and actual log entries go here.
+    //
+    // BYTE ExtraHeaderBytes[ExtraBytesInHeader];
+    // BYTE Entries[LogSize][EntrySize];
+    //
+
+} TRACE_LOG, *PTRACE_LOG;
+
+
+//
+// Log header signature.
+//
+
+#define TRACE_LOG_SIGNATURE   ((DWORD)'gOlT')
+#define TRACE_LOG_SIGNATURE_X ((DWORD)'golX')
+
+
+//
+// This macro maps a TRACE_LOG pointer to a pointer to the 'extra'
+// data associated with the log.
+//
+
+#define TRACE_LOG_TO_EXTRA_DATA(log)    (PVOID)( (log) + 1 )
+
+
+//
+// Manipulators.
+//
+
+PTRACE_LOG
+CreateTraceLog(
+    IN LONG LogSize,
+    IN LONG ExtraBytesInHeader,
+    IN LONG EntrySize
+    );
+
+VOID
+DestroyTraceLog(
+    IN PTRACE_LOG Log
+    );
+
+LONG
+WriteTraceLog(
+    IN PTRACE_LOG Log,
+    IN PVOID Entry
+    );
+
+VOID
+ResetTraceLog(
+    IN PTRACE_LOG Log
+    );
+
+
+#if defined(__cplusplus)
+}   // extern "C"
+#endif  // __cplusplus
+
+
+#endif  // _TRACELOG_H_
+
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/IISLib/treehash.h b/src/IISIntegration/src/AspNetCoreModuleV2/IISLib/treehash.h
new file mode 100644
index 0000000000000000000000000000000000000000..baa50726ce61d2cf3bd5fee79da78d583cc86bc6
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/IISLib/treehash.h
@@ -0,0 +1,850 @@
+// 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 <crtdbg.h>
+#include "rwlock.h"
+#include "prime.h"
+
+template <class _Record>
+class TREE_HASH_NODE
+{
+    template <class _Record>
+    friend class TREE_HASH_TABLE;
+
+ private:
+    // Next node in the hash table look-aside
+    TREE_HASH_NODE<_Record> *_pNext;
+
+    // links in the tree structure
+    TREE_HASH_NODE *    _pParentNode;
+    TREE_HASH_NODE *    _pFirstChild;
+    TREE_HASH_NODE *    _pNextSibling;
+
+    // actual record
+    _Record *           _pRecord;
+
+    // hash value
+    PCWSTR              _pszPath;
+    DWORD               _dwHash;
+};
+
+template <class _Record>
+class TREE_HASH_TABLE
+{
+protected:
+    typedef BOOL
+    (PFN_DELETE_IF)(
+        _Record *           pRecord,
+        PVOID               pvContext
+    );
+
+    typedef VOID
+    (PFN_APPLY)(
+        _Record *           pRecord,
+        PVOID               pvContext
+    );
+
+public:
+    TREE_HASH_TABLE(
+        BOOL    fCaseSensitive
+    ) : _ppBuckets( NULL ),
+        _nBuckets( 0 ),
+        _nItems( 0 ),
+        _fCaseSensitive( fCaseSensitive )
+    {
+    }
+
+    virtual
+    ~TREE_HASH_TABLE();
+
+    virtual
+    VOID
+    ReferenceRecord(
+        _Record *   pRecord
+    ) = 0;
+
+    virtual
+    VOID
+    DereferenceRecord(
+        _Record *   pRecord
+    ) = 0;
+
+    virtual
+    PCWSTR
+    GetKey(
+        _Record *   pRecord
+    ) = 0;
+
+    DWORD
+    Count()
+    {
+        return _nItems;
+    }
+
+    virtual
+    VOID
+    Clear();
+
+    HRESULT
+    Initialize(
+        DWORD           nBucketSize
+    );
+
+    DWORD
+    CalcHash(
+        PCWSTR      pszKey
+    )
+    {
+        return _fCaseSensitive ? HashString(pszKey) : HashStringNoCase(pszKey);
+    }
+
+    virtual
+    VOID
+    FindKey(
+        PCWSTR      pszKey,
+        _Record **  ppRecord
+    );
+
+    virtual
+    HRESULT
+    InsertRecord(
+        _Record *   pRecord
+    );
+
+    virtual
+    VOID
+    DeleteKey(
+        PCWSTR      pszKey
+    );
+
+    virtual
+    VOID
+    DeleteIf(
+        PFN_DELETE_IF       pfnDeleteIf,
+        PVOID               pvContext
+    );
+
+    VOID
+    Apply(
+        PFN_APPLY           pfnApply,
+        PVOID               pvContext
+    );
+
+private:
+
+    BOOL
+    FindNodeInternal(
+        PCWSTR                      pszKey,
+        DWORD                       dwHash,
+        TREE_HASH_NODE<_Record> **  ppNode,
+        TREE_HASH_NODE<_Record> *** pppPreviousNodeNextPointer = NULL
+    );
+
+    HRESULT
+    AddNodeInternal(
+        PCWSTR                      pszPath,
+        DWORD                       dwHash,
+        _Record *                   pRecord,
+        TREE_HASH_NODE<_Record> *   pParentNode,
+        TREE_HASH_NODE<_Record> **  ppNewNode
+    );
+
+    HRESULT
+    AllocateNode(
+        PCWSTR                      pszPath,
+        DWORD                       dwHash,
+        _Record *                   pRecord,
+        TREE_HASH_NODE<_Record> *   pParentNode,
+        TREE_HASH_NODE<_Record> **  ppNewNode
+    );
+
+    VOID
+    DeleteNode(
+        TREE_HASH_NODE<_Record> *   pNode
+    )
+    {
+        if (pNode->_pRecord != NULL)
+        {
+            DereferenceRecord(pNode->_pRecord);
+            pNode->_pRecord = NULL;
+        }
+
+        HeapFree(GetProcessHeap(),
+                 0,
+                 pNode);
+    }
+
+    VOID
+    DeleteNodeInternal(
+        TREE_HASH_NODE<_Record> **  ppPreviousNodeNextPointer,
+        TREE_HASH_NODE<_Record> *   pNode
+    );
+
+    VOID
+    RehashTableIfNeeded(
+        VOID
+    );
+
+    TREE_HASH_NODE<_Record> **  _ppBuckets;
+    DWORD                       _nBuckets;
+    DWORD                       _nItems;
+    BOOL                        _fCaseSensitive;
+    CWSDRWLock                  _tableLock;
+};
+
+template <class _Record>
+HRESULT
+TREE_HASH_TABLE<_Record>::AllocateNode(
+    PCWSTR                      pszPath,
+    DWORD                       dwHash,
+    _Record *                   pRecord,
+    TREE_HASH_NODE<_Record> *   pParentNode,
+    TREE_HASH_NODE<_Record> **  ppNewNode
+)
+{
+    //
+    // Allocate enough extra space for pszPath
+    //
+    DWORD cchPath = (DWORD) wcslen(pszPath);
+    if (cchPath >= ((0xffffffff - sizeof(TREE_HASH_NODE<_Record>))/sizeof(WCHAR) - 1))
+    {
+        return HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
+    }
+    TREE_HASH_NODE<_Record> *pNode = (TREE_HASH_NODE<_Record> *)HeapAlloc(
+            GetProcessHeap(),
+            HEAP_ZERO_MEMORY,
+            sizeof(TREE_HASH_NODE<_Record>) + (cchPath+1)*sizeof(WCHAR));
+    if (pNode == NULL)
+    {
+        return HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
+    }
+
+    memcpy(pNode+1, pszPath, (cchPath+1)*sizeof(WCHAR));
+    pNode->_pszPath = (PCWSTR)(pNode+1);
+    pNode->_dwHash = dwHash;
+    pNode->_pNext = pNode->_pNextSibling = pNode->_pFirstChild = NULL;
+    pNode->_pParentNode = pParentNode;
+    pNode->_pRecord = pRecord;
+
+    *ppNewNode = pNode;
+    return S_OK;
+}
+
+template <class _Record>
+HRESULT
+TREE_HASH_TABLE<_Record>::Initialize(
+    DWORD   nBuckets
+)
+{
+    HRESULT hr = S_OK;
+
+    if ( nBuckets == 0 )
+    {
+        hr = E_INVALIDARG;
+        goto Failed;
+    }
+
+    hr = _tableLock.Init();
+    if ( FAILED( hr ) )
+    {
+        goto Failed;
+    }
+
+    if (nBuckets >= 0xffffffff/sizeof(TREE_HASH_NODE<_Record> *))
+    {
+        hr = E_INVALIDARG;
+        goto Failed;
+    }
+
+    _ppBuckets = (TREE_HASH_NODE<_Record> **)HeapAlloc(
+                            GetProcessHeap(),
+                            HEAP_ZERO_MEMORY,
+                            nBuckets*sizeof(TREE_HASH_NODE<_Record> *));
+    if (_ppBuckets == NULL)
+    {
+        hr = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
+        goto Failed;
+    }
+    _nBuckets = nBuckets;
+
+    return S_OK;
+
+Failed:
+
+    if (_ppBuckets)
+    {
+        HeapFree(GetProcessHeap(),
+                 0,
+                 _ppBuckets);
+        _ppBuckets = NULL;
+    }
+
+    return hr;
+}
+
+
+template <class _Record>
+TREE_HASH_TABLE<_Record>::~TREE_HASH_TABLE()
+{
+    if (_ppBuckets == NULL)
+    {
+        return;
+    }
+
+    _ASSERTE(_nItems == 0);
+
+    HeapFree(GetProcessHeap(),
+             0,
+             _ppBuckets);
+    _ppBuckets = NULL;
+    _nBuckets = 0;
+}
+
+template <class _Record>
+VOID
+TREE_HASH_TABLE<_Record>::Clear()
+{
+    TREE_HASH_NODE<_Record> *pCurrent;
+    TREE_HASH_NODE<_Record> *pNext;
+
+    _tableLock.ExclusiveAcquire();
+
+    for (DWORD i=0; i<_nBuckets; i++)
+    {
+        pCurrent = _ppBuckets[i];
+        _ppBuckets[i] = NULL;
+        while (pCurrent != NULL)
+        {
+            pNext = pCurrent->_pNext;
+            DeleteNode(pCurrent);
+            pCurrent = pNext;
+        }
+    }
+
+    _nItems = 0;
+    _tableLock.ExclusiveRelease();
+}
+
+template <class _Record>
+BOOL
+TREE_HASH_TABLE<_Record>::FindNodeInternal(
+    PCWSTR                  pszKey,
+    DWORD                   dwHash,
+    TREE_HASH_NODE<_Record> **   ppNode,
+    TREE_HASH_NODE<_Record> ***  pppPreviousNodeNextPointer
+)
+/*++
+  Return value indicates whether the item is found
+  key, dwHash - key and hash for the node to find
+  ppNode - on successful return, the node found, on failed return, the first
+  node with hash value greater than the node to be found
+  pppPreviousNodeNextPointer - the pointer to previous node's _pNext
+
+  This routine may be called under either read or write lock
+--*/
+{
+    TREE_HASH_NODE<_Record> **ppPreviousNodeNextPointer;
+    TREE_HASH_NODE<_Record> *pNode;
+    BOOL fFound = FALSE;
+
+    ppPreviousNodeNextPointer = _ppBuckets + (dwHash % _nBuckets);
+    pNode = *ppPreviousNodeNextPointer;
+    while (pNode != NULL)
+    {
+        if (pNode->_dwHash == dwHash)
+        {
+            if (CompareStringOrdinal(pszKey,
+                                     -1,
+                                     pNode->_pszPath,
+                                     -1,
+                                     !_fCaseSensitive) == CSTR_EQUAL)
+            {
+                fFound = TRUE;
+                break;
+            }
+        }
+        else if (pNode->_dwHash > dwHash)
+        {
+            break;
+        }
+
+        ppPreviousNodeNextPointer = &(pNode->_pNext);
+        pNode = *ppPreviousNodeNextPointer;
+    }
+
+    *ppNode = pNode;
+    if (pppPreviousNodeNextPointer != NULL)
+    {
+        *pppPreviousNodeNextPointer = ppPreviousNodeNextPointer;
+    }
+    return fFound;
+}
+
+template <class _Record>
+VOID
+TREE_HASH_TABLE<_Record>::FindKey(
+    PCWSTR              pszKey,
+    _Record **          ppRecord
+)
+{
+    TREE_HASH_NODE<_Record> *pNode;
+
+    *ppRecord = NULL;
+
+    DWORD dwHash = CalcHash(pszKey);
+
+    _tableLock.SharedAcquire();
+
+    if (FindNodeInternal(pszKey, dwHash, &pNode) &&
+        pNode->_pRecord != NULL)
+    {
+        ReferenceRecord(pNode->_pRecord);
+        *ppRecord = pNode->_pRecord;
+    }
+
+    _tableLock.SharedRelease();
+}
+
+template <class _Record>
+HRESULT
+TREE_HASH_TABLE<_Record>::AddNodeInternal(
+    PCWSTR                      pszPath,
+    DWORD                       dwHash,
+    _Record *                   pRecord,
+    TREE_HASH_NODE<_Record> *   pParentNode,
+    TREE_HASH_NODE<_Record> **  ppNewNode
+)
+/*++
+  Return value is HRESULT indicating sucess or failure
+  pszPath, dwHash, pRecord - path, hash value and record to be inserted
+  pParentNode - this will be the parent of the node being inserted
+  ppNewNode - on successful return, the new node created and inserted
+
+  This function may be called under a read or write lock
+--*/
+{
+    TREE_HASH_NODE<_Record> *pNewNode;
+    TREE_HASH_NODE<_Record> *pNextNode;
+    TREE_HASH_NODE<_Record> **ppNextPointer;
+    HRESULT hr;
+
+    //
+    // Ownership of pRecord is not transferred to pNewNode yet, so remember
+    // to either set it to null before deleting pNewNode or add an extra
+    // reference later - this is to make sure we do not do an extra ref/deref
+    // which users may view as getting flushed out of the hash-table
+    //
+    hr = AllocateNode(pszPath,
+                      dwHash,
+                      pRecord,
+                      pParentNode,
+                      &pNewNode);
+    if (FAILED(hr))
+    {
+        return hr;
+    }
+
+    do
+    {
+        //
+        // Find the right place to add this node
+        //
+
+        if (FindNodeInternal(pszPath, dwHash, &pNextNode, &ppNextPointer))
+        {
+            //
+            // If node already there, record may still need updating
+            //
+            if (pRecord != NULL &&
+                InterlockedCompareExchangePointer((PVOID *)&pNextNode->_pRecord,
+                                                  pRecord,
+                                                  NULL) == NULL)
+            {
+                ReferenceRecord(pRecord);
+                hr = S_OK;
+            }
+            else
+            {
+                hr = HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS);
+            }
+
+            // ownership of pRecord has either passed to existing record or
+            // not to anyone at all
+            pNewNode->_pRecord = NULL;
+            DeleteNode(pNewNode);
+            *ppNewNode = pNextNode;
+            return hr;
+        }
+
+        //
+        // If another node got inserted in betwen, we will have to retry
+        //
+        pNewNode->_pNext = pNextNode;
+    } while (InterlockedCompareExchangePointer((PVOID *)ppNextPointer,
+                                               pNewNode,
+                                               pNextNode) != pNextNode);
+    // pass ownership of pRecord now
+    if (pRecord != NULL)
+    {
+        ReferenceRecord(pRecord);
+        pRecord = NULL;
+    }
+    InterlockedIncrement((LONG *)&_nItems);
+
+    //
+    // update the parent
+    //
+    if (pParentNode != NULL)
+    {
+        ppNextPointer = &pParentNode->_pFirstChild;
+        do
+        {
+            pNextNode = *ppNextPointer;
+            pNewNode->_pNextSibling = pNextNode;
+        } while (InterlockedCompareExchangePointer((PVOID *)ppNextPointer,
+                                                   pNewNode,
+                                                   pNextNode) != pNextNode);
+    }
+
+    *ppNewNode = pNewNode;
+    return S_OK;
+}
+
+template <class _Record>
+HRESULT
+TREE_HASH_TABLE<_Record>::InsertRecord(
+    _Record *           pRecord
+)
+/*++
+  This method inserts a node for this record and also empty nodes for paths
+  in the heirarchy leading upto this path
+
+  The insert is done under only a read-lock - this is possible by keeping
+  the hashes in a bucket in increasing order and using interlocked operations
+  to actually insert the item in the hash-bucket lookaside list and the parent
+  children list
+
+  Returns HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS) if the record already exists.
+  Never leak this error to the end user because "*file* already exists" may be confusing.
+--*/
+{
+    PCWSTR pszKey = GetKey(pRecord);
+    STACK_STRU( strPartialPath, 256);
+    PWSTR pszPartialPath;
+    DWORD dwHash;
+    DWORD cchEnd;
+    HRESULT hr;
+    TREE_HASH_NODE<_Record> *pParentNode = NULL;
+
+    hr = strPartialPath.Copy(pszKey);
+    if (FAILED(hr))
+    {
+        goto Finished;
+    }
+    pszPartialPath = strPartialPath.QueryStr();
+
+    _tableLock.SharedAcquire();
+
+    //
+    // First find the lowest parent node present
+    //
+    for (cchEnd = strPartialPath.QueryCCH() - 1; cchEnd > 0; cchEnd--)
+    {
+        if (pszPartialPath[cchEnd] == L'/' || pszPartialPath[cchEnd] == L'\\')
+        {
+            pszPartialPath[cchEnd] = L'\0';
+
+            dwHash = CalcHash(pszPartialPath);
+            if (FindNodeInternal(pszPartialPath, dwHash, &pParentNode))
+            {
+                pszPartialPath[cchEnd] = pszKey[cchEnd];
+                break;
+            }
+            pParentNode = NULL;
+        }
+    }
+
+    //
+    // Now go ahead and add the rest of the tree (including our record)
+    //
+    for (; cchEnd <= strPartialPath.QueryCCH(); cchEnd++)
+    {
+        if (pszPartialPath[cchEnd] == L'\0')
+        {
+            dwHash = CalcHash(pszPartialPath);
+            hr = AddNodeInternal(
+                    pszPartialPath,
+                    dwHash,
+                    (cchEnd == strPartialPath.QueryCCH()) ? pRecord : NULL,
+                    pParentNode,
+                    &pParentNode);
+            if (FAILED(hr) &&
+                hr != HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS))
+            {
+                goto Finished;
+            }
+
+            pszPartialPath[cchEnd] = pszKey[cchEnd];
+        }
+    }
+
+Finished:
+    _tableLock.SharedRelease();
+
+    if (SUCCEEDED(hr))
+    {
+        RehashTableIfNeeded();
+    }
+
+    return hr;
+}
+
+template <class _Record>
+VOID
+TREE_HASH_TABLE<_Record>::DeleteNodeInternal(
+    TREE_HASH_NODE<_Record> **  ppNextPointer,
+    TREE_HASH_NODE<_Record> *   pNode
+)
+/*++
+  pNode is the node to be deleted
+  ppNextPointer is the pointer to the previous node's next pointer pointing
+  to this node
+
+  This function should be called under write-lock
+--*/
+{
+    //
+    // First remove this node from hash table
+    //
+    *ppNextPointer = pNode->_pNext;
+
+    //
+    // Now fixup parent
+    //
+    if (pNode->_pParentNode != NULL)
+    {
+        ppNextPointer = &pNode->_pParentNode->_pFirstChild;
+        while (*ppNextPointer != pNode)
+        {
+            ppNextPointer = &(*ppNextPointer)->_pNextSibling;
+        }
+        *ppNextPointer = pNode->_pNextSibling;
+    }
+
+    //
+    // Now remove all children recursively
+    //
+    TREE_HASH_NODE<_Record> *pChild = pNode->_pFirstChild;
+    TREE_HASH_NODE<_Record> *pNextChild;
+    while (pChild != NULL)
+    {
+        pNextChild = pChild->_pNextSibling;
+
+        ppNextPointer = _ppBuckets + (pChild->_dwHash % _nBuckets);
+        while (*ppNextPointer != pChild)
+        {
+            ppNextPointer = &(*ppNextPointer)->_pNext;
+        }
+        pChild->_pParentNode = NULL;
+        DeleteNodeInternal(ppNextPointer, pChild);
+
+        pChild = pNextChild;
+    }
+
+    DeleteNode(pNode);
+    _nItems--;
+}
+
+template <class _Record>
+VOID
+TREE_HASH_TABLE<_Record>::DeleteKey(
+    PCWSTR      pszKey
+)
+{
+    TREE_HASH_NODE<_Record> *pNode;
+    TREE_HASH_NODE<_Record> **ppPreviousNodeNextPointer;
+
+    DWORD dwHash = CalcHash(pszKey);
+
+    _tableLock.ExclusiveAcquire();
+
+    if (FindNodeInternal(pszKey, dwHash, &pNode, &ppPreviousNodeNextPointer))
+    {
+        DeleteNodeInternal(ppPreviousNodeNextPointer, pNode);
+    }
+
+    _tableLock.ExclusiveRelease();
+}
+
+template <class _Record>
+VOID
+TREE_HASH_TABLE<_Record>::DeleteIf(
+    PFN_DELETE_IF               pfnDeleteIf,
+    PVOID                       pvContext
+)
+{
+    TREE_HASH_NODE<_Record> *pNode;
+    TREE_HASH_NODE<_Record> **ppPreviousNodeNextPointer;
+    BOOL fDelete;
+
+    _tableLock.ExclusiveAcquire();
+
+    for (DWORD i=0; i<_nBuckets; i++)
+    {
+        ppPreviousNodeNextPointer = _ppBuckets + i;
+        pNode = *ppPreviousNodeNextPointer;
+        while (pNode != NULL)
+        {
+            //
+            // Non empty nodes deleted based on DeleteIf, empty nodes deleted
+            // if they have no children
+            //
+            fDelete = FALSE;
+            if (pNode->_pRecord != NULL)
+            {
+                if (pfnDeleteIf(pNode->_pRecord, pvContext))
+                {
+                    fDelete = TRUE;
+                }
+            }
+            else if (pNode->_pFirstChild == NULL)
+            {
+                fDelete =  TRUE;
+            }
+
+            if (fDelete)
+            {
+                if (pNode->_pFirstChild == NULL)
+                {
+                    DeleteNodeInternal(ppPreviousNodeNextPointer, pNode);
+                }
+                else
+                {
+                    DereferenceRecord(pNode->_pRecord);
+                    pNode->_pRecord = NULL;
+                }
+            }
+            else
+            {
+                ppPreviousNodeNextPointer = &pNode->_pNext;
+            }
+
+            pNode = *ppPreviousNodeNextPointer;
+        }
+    }
+
+    _tableLock.ExclusiveRelease();
+}
+
+template <class _Record>
+VOID
+TREE_HASH_TABLE<_Record>::Apply(
+    PFN_APPLY                   pfnApply,
+    PVOID                       pvContext
+)
+{
+    TREE_HASH_NODE<_Record> *pNode;
+
+    _tableLock.SharedAcquire();
+
+    for (DWORD i=0; i<_nBuckets; i++)
+    {
+        pNode = _ppBuckets[i];
+        while (pNode != NULL)
+        {
+            if (pNode->_pRecord != NULL)
+            {
+                pfnApply(pNode->_pRecord, pvContext);
+            }
+
+            pNode = pNode->_pNext;
+        }
+    }
+
+    _tableLock.SharedRelease();
+}
+
+template <class _Record>
+VOID
+TREE_HASH_TABLE<_Record>::RehashTableIfNeeded(
+    VOID
+)
+{
+    TREE_HASH_NODE<_Record> **ppBuckets;
+    DWORD nBuckets;
+    TREE_HASH_NODE<_Record> *pNode;
+    TREE_HASH_NODE<_Record> *pNextNode;
+    TREE_HASH_NODE<_Record> **ppNextPointer;
+    TREE_HASH_NODE<_Record> *pNewNextNode;
+    DWORD               nNewBuckets;
+
+    //
+    // If number of items has become too many, we will double the hash table
+    // size (we never reduce it however)
+    //
+    if (_nItems <= PRIME::GetPrime(2*_nBuckets))
+    {
+        return;
+    }
+
+    _tableLock.ExclusiveAcquire();
+
+    nNewBuckets = PRIME::GetPrime(2*_nBuckets);
+
+    if (_nItems <= nNewBuckets)
+    {
+        goto Finished;
+    }
+
+    nBuckets = nNewBuckets;
+    if (nBuckets >= 0xffffffff/sizeof(TREE_HASH_NODE<_Record> *))
+    {
+        goto Finished;
+    }
+    ppBuckets = (TREE_HASH_NODE<_Record> **)HeapAlloc(
+                        GetProcessHeap(),
+                        HEAP_ZERO_MEMORY,
+                        nBuckets*sizeof(TREE_HASH_NODE<_Record> *));
+    if (ppBuckets == NULL)
+    {
+        goto Finished;
+    }
+
+    //
+    // Take out nodes from the old hash table and insert in the new one, make
+    // sure to keep the hashes in increasing order
+    //
+    for (DWORD i=0; i<_nBuckets; i++)
+    {
+        pNode = _ppBuckets[i];
+        while (pNode != NULL)
+        {
+            pNextNode = pNode->_pNext;
+
+            ppNextPointer = ppBuckets + (pNode->_dwHash % nBuckets);
+            pNewNextNode = *ppNextPointer;
+            while (pNewNextNode != NULL &&
+                   pNewNextNode->_dwHash <= pNode->_dwHash)
+            {
+                ppNextPointer = &pNewNextNode->_pNext;
+                pNewNextNode = pNewNextNode->_pNext;
+            }
+            pNode->_pNext = pNewNextNode;
+            *ppNextPointer = pNode;
+
+            pNode = pNextNode;
+        }
+    }
+
+    HeapFree(GetProcessHeap(), 0, _ppBuckets);
+    _ppBuckets = ppBuckets;
+    _nBuckets = nBuckets;
+    ppBuckets = NULL;
+
+Finished:
+
+    _tableLock.ExclusiveRelease();
+}
+
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/IISLib/util.cxx b/src/IISIntegration/src/AspNetCoreModuleV2/IISLib/util.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..214ee65abfe40757bd1946555a83a0ca404bf42c
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/IISLib/util.cxx
@@ -0,0 +1,78 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#include "precomp.h"
+
+HRESULT
+MakePathCanonicalizationProof(
+    IN PCWSTR               pszName,
+    OUT STRU *              pstrPath
+)
+/*++
+
+Routine Description:
+
+    This functions adds a prefix
+    to the string, which is "\\?\UNC\" for a UNC path, and "\\?\" for
+    other paths.  This prefix tells Windows not to parse the path.
+
+Arguments:
+
+    IN  pszName     - The path to be converted
+    OUT pstrPath    - Output path created
+
+Return Values:
+
+    HRESULT
+
+--*/
+{
+    HRESULT hr;
+
+    if (pszName[0] == L'\\' && pszName[1] == L'\\')
+    {
+        //
+        // If the path is already canonicalized, just return
+        //
+
+        if ((pszName[2] == '?' || pszName[2] == '.') &&
+            pszName[3] == '\\')
+        {
+            hr = pstrPath->Copy(pszName);
+
+            if (SUCCEEDED(hr))
+            {
+                //
+                // If the path was in DOS form ("\\.\"),
+                // we need to change it to Win32 from ("\\?\")
+                //
+
+                pstrPath->QueryStr()[2] = L'?';
+            }
+
+            return hr;
+        }
+
+        pszName += 2;
+
+
+        if (FAILED(hr = pstrPath->Copy(L"\\\\?\\UNC\\")))
+        {
+            return hr;
+        }
+    }
+    else if (wcslen(pszName) > MAX_PATH)
+    {
+        if (FAILED(hr = pstrPath->Copy(L"\\\\?\\")))
+        {
+            return hr;
+        }
+    }
+    else
+    {
+        pstrPath->Reset();
+    }  
+
+    return pstrPath->Append(pszName);
+}
+
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/RequestHandler/RequestHandler.vcxproj b/src/IISIntegration/src/AspNetCoreModuleV2/RequestHandler/RequestHandler.vcxproj
new file mode 100644
index 0000000000000000000000000000000000000000..955839f2b9352816f6f938b913bafae745256598
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/RequestHandler/RequestHandler.vcxproj
@@ -0,0 +1,259 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="..\..\..\Build\Build.Settings" />
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|Win32">
+      <Configuration>Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Debug|x64">
+      <Configuration>Debug</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|x64">
+      <Configuration>Release</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <VCProjectVersion>15.0</VCProjectVersion>
+    <ProjectGuid>{D57EA297-6DC2-4BC0-8C91-334863327863}</ProjectGuid>
+    <Keyword>Win32Proj</Keyword>
+    <RootNamespace>RequestHandler</RootNamespace>
+    <WindowsTargetPlatformVersion>10.0.15063.0</WindowsTargetPlatformVersion>
+    <ProjectName>RequestHandler</ProjectName>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+    <ConfigurationType>DynamicLibrary</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <PlatformToolset>v141</PlatformToolset>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+    <ConfigurationType>DynamicLibrary</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <PlatformToolset>v141</PlatformToolset>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+    <ConfigurationType>DynamicLibrary</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <PlatformToolset>v141</PlatformToolset>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+    <ConfigurationType>DynamicLibrary</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <PlatformToolset>v141</PlatformToolset>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Label="Shared">
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup>
+    <TargetName>aspnetcorerh</TargetName>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <LinkIncremental>false</LinkIncremental>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <LinkIncremental>false</LinkIncremental>
+  </PropertyGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level4</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_DEBUG;REQUESTHANDLER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <PrecompiledHeaderFile>precomp.hxx</PrecompiledHeaderFile>
+      <PrecompiledHeaderOutputFile>$(IntDir)$(TargetName).pch</PrecompiledHeaderOutputFile>
+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+      <AdditionalIncludeDirectories>..\IISLib;..\CommonLib;.\Inc</AdditionalIncludeDirectories>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <SDLCheck>true</SDLCheck>
+      <WholeProgramOptimization>true</WholeProgramOptimization>
+      <PreprocessKeepComments>false</PreprocessKeepComments>
+      <ExceptionHandling>SyncCThrow</ExceptionHandling>
+      <StructMemberAlignment>8Bytes</StructMemberAlignment>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <RuntimeTypeInfo>false</RuntimeTypeInfo>
+      <OmitDefaultLibName>true</OmitDefaultLibName>
+      <CompileAs>CompileAsCpp</CompileAs>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <AdditionalDependencies>kernel32.lib;user32.lib;advapi32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;ahadmin.lib;rpcrt4.lib;winhttp.lib;pdh.lib;ws2_32.lib;wbemuuid.lib;iphlpapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
+      <ModuleDefinitionFile>Source.def</ModuleDefinitionFile>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level4</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_DEBUG;REQUESTHANDLER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <PrecompiledHeaderFile>precomp.hxx</PrecompiledHeaderFile>
+      <PrecompiledHeaderOutputFile>$(IntDir)$(TargetName).pch</PrecompiledHeaderOutputFile>
+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+      <AdditionalIncludeDirectories>..\IISLib;..\CommonLib;.\Inc</AdditionalIncludeDirectories>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <SDLCheck>true</SDLCheck>
+      <WholeProgramOptimization>true</WholeProgramOptimization>
+      <PreprocessKeepComments>false</PreprocessKeepComments>
+      <ExceptionHandling>SyncCThrow</ExceptionHandling>
+      <StructMemberAlignment>8Bytes</StructMemberAlignment>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <RuntimeTypeInfo>false</RuntimeTypeInfo>
+      <OmitDefaultLibName>true</OmitDefaultLibName>
+      <CompileAs>CompileAsCpp</CompileAs>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <AdditionalDependencies>kernel32.lib;user32.lib;advapi32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;ahadmin.lib;rpcrt4.lib;winhttp.lib;pdh.lib;ws2_32.lib;wbemuuid.lib;iphlpapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
+      <ModuleDefinitionFile>Source.def</ModuleDefinitionFile>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <ClCompile>
+      <WarningLevel>Level4</WarningLevel>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <Optimization>MaxSpeed</Optimization>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;REQUESTHANDLER_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <PrecompiledHeaderFile>precomp.hxx</PrecompiledHeaderFile>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+      <AdditionalIncludeDirectories>..\IISLib;..\CommonLib;.\Inc</AdditionalIncludeDirectories>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <SDLCheck>true</SDLCheck>
+      <WholeProgramOptimization>true</WholeProgramOptimization>
+      <PreprocessKeepComments>false</PreprocessKeepComments>
+      <ExceptionHandling>SyncCThrow</ExceptionHandling>
+      <StructMemberAlignment>8Bytes</StructMemberAlignment>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <RuntimeTypeInfo>false</RuntimeTypeInfo>
+      <OmitDefaultLibName>true</OmitDefaultLibName>
+      <CompileAs>CompileAsCpp</CompileAs>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation>false</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+      <ModuleDefinitionFile>Source.def</ModuleDefinitionFile>
+      <AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;ahadmin.lib;winhttp.lib;odbc32.lib;ws2_32.lib;odbccp32.lib;wbemuuid.lib;iphlpapi.lib;pdh.lib;rpcrt4.lib;%(AdditionalDependencies)</AdditionalDependencies>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <ClCompile>
+      <WarningLevel>Level4</WarningLevel>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <Optimization>MaxSpeed</Optimization>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <PreprocessorDefinitions>NDEBUG;REQUESTHANDLER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <PrecompiledHeaderFile>precomp.hxx</PrecompiledHeaderFile>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+      <AdditionalIncludeDirectories>..\IISLib;..\CommonLib;.\Inc</AdditionalIncludeDirectories>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <SDLCheck>true</SDLCheck>
+      <WholeProgramOptimization>true</WholeProgramOptimization>
+      <PreprocessKeepComments>false</PreprocessKeepComments>
+      <ExceptionHandling>SyncCThrow</ExceptionHandling>
+      <StructMemberAlignment>8Bytes</StructMemberAlignment>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <RuntimeTypeInfo>false</RuntimeTypeInfo>
+      <OmitDefaultLibName>true</OmitDefaultLibName>
+      <CompileAs>CompileAsCpp</CompileAs>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation>false</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+      <ModuleDefinitionFile>Source.def</ModuleDefinitionFile>
+      <AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;ahadmin.lib;rpcrt4.lib;winhttp.lib;pdh.lib;ws2_32.lib;wbemuuid.lib;iphlpapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
+    </Link>
+  </ItemDefinitionGroup>
+  <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" />
+    <ClInclude Include="outofprocess\protocolconfig.h" />
+    <ClInclude Include="outofprocess\responseheaderhash.h" />
+    <ClInclude Include="outofprocess\serverprocess.h" />
+    <ClInclude Include="outofprocess\websockethandler.h" />
+    <ClInclude Include="outofprocess\winhttphelper.h" />
+    <ClInclude Include="precomp.hxx" />
+    <ClInclude Include=".\inprocess\inprocessapplication.h" />
+    <ClInclude Include=".\inprocess\inprocesshandler.h" />
+    <ClInclude Include=".\outofprocess\forwardinghandler.h" />
+    <ClInclude Include=".\outofprocess\outprocessapplication.h" />
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="dllmain.cxx" />
+    <ClCompile Include=".\inprocess\inprocessapplication.cpp" />
+    <ClCompile Include=".\inprocess\inprocesshandler.cpp" />
+    <ClCompile Include=".\outofprocess\forwardinghandler.cpp" />
+    <ClCompile Include=".\outofprocess\outprocessapplication.cpp" />
+    <ClCompile Include="managedexports.cxx" />
+    <ClCompile Include="outofprocess\forwarderconnection.cxx" />
+    <ClCompile Include="outofprocess\processmanager.cxx" />
+    <ClCompile Include="outofprocess\protocolconfig.cxx" />
+    <ClCompile Include="outofprocess\responseheaderhash.cxx" />
+    <ClCompile Include="outofprocess\serverprocess.cxx" />
+    <ClCompile Include="outofprocess\websockethandler.cxx" />
+    <ClCompile Include="outofprocess\winhttphelper.cxx" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\CommonLib\CommonLib.vcxproj">
+      <Project>{55494e58-e061-4c4c-a0a8-837008e72f85}</Project>
+    </ProjectReference>
+    <ProjectReference Include="..\IISLib\IISLib.vcxproj">
+      <Project>{4787a64f-9a3e-4867-a55a-70cb4b2b2ffe}</Project>
+    </ProjectReference>
+  </ItemGroup>
+  <ItemGroup>
+    <ResourceCompile Include="requesthandler.rc" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="Source.def" />
+  </ItemGroup>
+  <Import Project="..\..\..\build\native.targets" />
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  </ImportGroup>
+</Project>
\ No newline at end of file
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/RequestHandler/Source.def b/src/IISIntegration/src/AspNetCoreModuleV2/RequestHandler/Source.def
new file mode 100644
index 0000000000000000000000000000000000000000..889bd1a39b88ad8c3717597ebc0008cea44149b0
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/RequestHandler/Source.def
@@ -0,0 +1,6 @@
+LIBRARY aspnetcorerh
+
+EXPORTS
+    CreateApplication
+    CreateRequestHandler
+
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/RequestHandler/aspnetcore_event.h b/src/IISIntegration/src/AspNetCoreModuleV2/RequestHandler/aspnetcore_event.h
new file mode 100644
index 0000000000000000000000000000000000000000..2c13d20d1e0deac7dbb75a5c7a257ab98348bf55
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/RequestHandler/aspnetcore_event.h
@@ -0,0 +1,550 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#ifndef __ASPNETCOREEVENT_H__
+#define __ASPNETCOREEVENT_H__
+/*++
+
+    Module Name:
+
+        aspnetcore_event.h
+
+    Abstract:
+
+        Header file has been generated from mof file containing 
+        IIS trace event descriptions
+
+--*/
+
+//
+// Start of the new provider class WWWServerTraceProvider,
+// GUID: {3a2a4e84-4c21-4981-ae10-3fda0d9b0f83}
+// Description: IIS: WWW Server
+//
+
+class WWWServerTraceProvider
+{
+public:
+    static
+    LPCGUID
+    GetProviderGuid( VOID )
+    // return GUID for the current event class
+    {
+        static const GUID ProviderGuid = 
+          {0x3a2a4e84,0x4c21,0x4981,{0xae,0x10,0x3f,0xda,0x0d,0x9b,0x0f,0x83}};
+        return &ProviderGuid;
+    };
+    enum enumAreaFlags
+    {
+        // AspNetCore module events
+        ANCM = 0x10000
+    };
+    static
+    LPCWSTR
+    TranslateEnumAreaFlagsToString( enum enumAreaFlags EnumValue)
+    {
+        switch( (DWORD) EnumValue )
+        {
+        case 0x10000: return L"ANCM";
+        }
+        return NULL;
+    };
+
+    static
+    BOOL
+    CheckTracingEnabled(
+        IHttpTraceContext * pHttpTraceContext,
+        enumAreaFlags       AreaFlags,
+        DWORD               dwVerbosity )
+    {
+        HRESULT                  hr;
+        HTTP_TRACE_CONFIGURATION TraceConfig;
+        TraceConfig.pProviderGuid = GetProviderGuid();
+        hr = pHttpTraceContext->GetTraceConfiguration( &TraceConfig );
+        if ( FAILED( hr )  || !TraceConfig.fProviderEnabled )
+        {
+            return FALSE;
+        }
+        if ( TraceConfig.dwVerbosity >= dwVerbosity && 
+             (  TraceConfig.dwAreas == (DWORD) AreaFlags || 
+               ( TraceConfig.dwAreas & (DWORD)AreaFlags ) == (DWORD)AreaFlags ) ) 
+        { 
+            return TRUE;
+        } 
+        return FALSE;
+    };
+};
+
+//
+// Start of the new event class ANCMEvents,
+// GUID: {82ADEAD7-12B2-4781-BDCA-5A4B6C757191}
+// Description: ANCM runtime events
+//
+
+class ANCMEvents
+{
+public:
+    static
+    LPCGUID
+    GetAreaGuid( VOID )
+    // return GUID for the current event class
+    {
+        static const GUID AreaGuid = 
+          {0x82adead7,0x12b2,0x4781,{0xbd,0xca,0x5a,0x4b,0x6c,0x75,0x71,0x91}};
+        return &AreaGuid;
+    };
+
+    //
+    // Event: mof class name ANCMAppStart,
+    // Description: Start application success
+    // EventTypeName: ANCM_START_APPLICATION_SUCCESS
+    // EventType: 1
+    // EventLevel: 4
+    //
+    
+    class ANCM_START_APPLICATION_SUCCESS
+    {
+    public:
+        static
+        HRESULT
+        RaiseEvent(
+            IHttpTraceContext * pHttpTraceContext,
+            LPCGUID    pContextId,
+            LPCWSTR     pAppDescription
+        )
+        //
+        // Raise ANCM_START_APPLICATION_SUCCESS Event
+        //
+        {
+            HTTP_TRACE_EVENT Event;
+            Event.pProviderGuid = WWWServerTraceProvider::GetProviderGuid();
+            Event.dwArea =  WWWServerTraceProvider::ANCM;
+            Event.pAreaGuid = ANCMEvents::GetAreaGuid();
+            Event.dwEvent = 1;
+            Event.pszEventName = L"ANCM_START_APPLICATION_SUCCESS";
+            Event.dwEventVersion = 1;
+            Event.dwVerbosity = 4;
+            Event.cEventItems = 2;
+            Event.pActivityGuid = NULL;
+            Event.pRelatedActivityGuid = NULL;
+            Event.dwTimeStamp = 0;
+            Event.dwFlags = HTTP_TRACE_EVENT_FLAG_STATIC_DESCRIPTIVE_FIELDS;
+    
+            // pActivityGuid, pRelatedActivityGuid, Timestamp to be filled in by IIS
+    
+            HTTP_TRACE_EVENT_ITEM Items[ 2 ];
+            Items[ 0 ].pszName = L"ContextId";
+            Items[ 0 ].dwDataType = HTTP_TRACE_TYPE_LPCGUID; // mof type (object)
+            Items[ 0 ].pbData = (PBYTE) pContextId;
+            Items[ 0 ].cbData = 16;
+            Items[ 0 ].pszDataDescription = NULL;
+            Items[ 1 ].pszName = L"AppDescription";
+            Items[ 1 ].dwDataType = HTTP_TRACE_TYPE_LPCWSTR; // mof type (string)
+            Items[ 1 ].pbData = (PBYTE) pAppDescription;
+            Items[ 1 ].cbData  = 
+                 ( Items[ 1 ].pbData == NULL )? 0 : ( sizeof(WCHAR) * (1 + (DWORD) wcslen( (PWSTR) Items[ 1 ].pbData  ) ) );
+            Items[ 1 ].pszDataDescription = NULL;
+            Event.pEventItems = Items;
+            pHttpTraceContext->RaiseTraceEvent( &Event );
+            return S_OK;
+        };
+    
+        static
+        BOOL
+        IsEnabled( 
+            IHttpTraceContext *  pHttpTraceContext )
+        // Check if tracing for this event is enabled
+        {
+            return WWWServerTraceProvider::CheckTracingEnabled( 
+                                 pHttpTraceContext,
+                                 WWWServerTraceProvider::ANCM,
+                                 4 ); //Verbosity
+        };
+    };
+    //
+    // Event: mof class name ANCMAppStartFail,
+    // Description: Start application failed
+    // EventTypeName: ANCM_START_APPLICATION_FAIL
+    // EventType: 2
+    // EventLevel: 2
+    //
+    
+    class ANCM_START_APPLICATION_FAIL
+    {
+    public:
+        static
+        HRESULT
+        RaiseEvent(
+            IHttpTraceContext * pHttpTraceContext,
+            LPCGUID    pContextId,
+            LPCWSTR     pFailureDescription
+        )
+        //
+        // Raise ANCM_START_APPLICATION_FAIL Event
+        //
+        {
+            HTTP_TRACE_EVENT Event;
+            Event.pProviderGuid = WWWServerTraceProvider::GetProviderGuid();
+            Event.dwArea =  WWWServerTraceProvider::ANCM;
+            Event.pAreaGuid = ANCMEvents::GetAreaGuid();
+            Event.dwEvent = 2;
+            Event.pszEventName = L"ANCM_START_APPLICATION_FAIL";
+            Event.dwEventVersion = 1;
+            Event.dwVerbosity = 2;
+            Event.cEventItems = 2;
+            Event.pActivityGuid = NULL;
+            Event.pRelatedActivityGuid = NULL;
+            Event.dwTimeStamp = 0;
+            Event.dwFlags = HTTP_TRACE_EVENT_FLAG_STATIC_DESCRIPTIVE_FIELDS;
+    
+            // pActivityGuid, pRelatedActivityGuid, Timestamp to be filled in by IIS
+    
+            HTTP_TRACE_EVENT_ITEM Items[ 2 ];
+            Items[ 0 ].pszName = L"ContextId";
+            Items[ 0 ].dwDataType = HTTP_TRACE_TYPE_LPCGUID; // mof type (object)
+            Items[ 0 ].pbData = (PBYTE) pContextId;
+            Items[ 0 ].cbData = 16;
+            Items[ 0 ].pszDataDescription = NULL;
+            Items[ 1 ].pszName = L"FailureDescription";
+            Items[ 1 ].dwDataType = HTTP_TRACE_TYPE_LPCWSTR; // mof type (string)
+            Items[ 1 ].pbData = (PBYTE) pFailureDescription;
+            Items[ 1 ].cbData  = 
+                 ( Items[ 1 ].pbData == NULL )? 0 : ( sizeof(WCHAR) * (1 + (DWORD) wcslen( (PWSTR) Items[ 1 ].pbData  ) ) );
+            Items[ 1 ].pszDataDescription = NULL;
+            Event.pEventItems = Items;
+            pHttpTraceContext->RaiseTraceEvent( &Event );
+            return S_OK;
+        };
+    
+        static
+        BOOL
+        IsEnabled( 
+            IHttpTraceContext *  pHttpTraceContext )
+        // Check if tracing for this event is enabled
+        {
+            return WWWServerTraceProvider::CheckTracingEnabled( 
+                                 pHttpTraceContext,
+                                 WWWServerTraceProvider::ANCM,
+                                 2 ); //Verbosity
+        };
+    };
+    //
+    // Event: mof class name ANCMForwardStart,
+    // Description: Start forwarding request
+    // EventTypeName: ANCM_REQUEST_FORWARD_START
+    // EventType: 3
+    // EventLevel: 4
+    //
+    
+    class ANCM_REQUEST_FORWARD_START
+    {
+    public:
+        static
+        HRESULT
+        RaiseEvent(
+            IHttpTraceContext * pHttpTraceContext,
+            LPCGUID    pContextId
+        )
+        //
+        // Raise ANCM_REQUEST_FORWARD_START Event
+        //
+        {
+            HTTP_TRACE_EVENT Event;
+            Event.pProviderGuid = WWWServerTraceProvider::GetProviderGuid();
+            Event.dwArea =  WWWServerTraceProvider::ANCM;
+            Event.pAreaGuid = ANCMEvents::GetAreaGuid();
+            Event.dwEvent = 3;
+            Event.pszEventName = L"ANCM_REQUEST_FORWARD_START";
+            Event.dwEventVersion = 1;
+            Event.dwVerbosity = 4;
+            Event.cEventItems = 1;
+            Event.pActivityGuid = NULL;
+            Event.pRelatedActivityGuid = NULL;
+            Event.dwTimeStamp = 0;
+            Event.dwFlags = HTTP_TRACE_EVENT_FLAG_STATIC_DESCRIPTIVE_FIELDS;
+    
+            // pActivityGuid, pRelatedActivityGuid, Timestamp to be filled in by IIS
+    
+            HTTP_TRACE_EVENT_ITEM Items[ 1 ];
+            Items[ 0 ].pszName = L"ContextId";
+            Items[ 0 ].dwDataType = HTTP_TRACE_TYPE_LPCGUID; // mof type (object)
+            Items[ 0 ].pbData = (PBYTE) pContextId;
+            Items[ 0 ].cbData = 16;
+            Items[ 0 ].pszDataDescription = NULL;
+            Event.pEventItems = Items;
+            pHttpTraceContext->RaiseTraceEvent( &Event );
+            return S_OK;
+        };
+    
+        static
+        BOOL
+        IsEnabled( 
+            IHttpTraceContext *  pHttpTraceContext )
+        // Check if tracing for this event is enabled
+        {
+            return WWWServerTraceProvider::CheckTracingEnabled( 
+                                 pHttpTraceContext,
+                                 WWWServerTraceProvider::ANCM,
+                                 4 ); //Verbosity
+        };
+    };
+    //
+    // Event: mof class name ANCMForwardEnd,
+    // Description: Finish forwarding request
+    // EventTypeName: ANCM_REQUEST_FORWARD_END
+    // EventType: 4
+    // EventLevel: 4
+    //
+    
+    class ANCM_REQUEST_FORWARD_END
+    {
+    public:
+        static
+        HRESULT
+        RaiseEvent(
+            IHttpTraceContext * pHttpTraceContext,
+            LPCGUID    pContextId
+        )
+        //
+        // Raise ANCM_REQUEST_FORWARD_END Event
+        //
+        {
+            HTTP_TRACE_EVENT Event;
+            Event.pProviderGuid = WWWServerTraceProvider::GetProviderGuid();
+            Event.dwArea =  WWWServerTraceProvider::ANCM;
+            Event.pAreaGuid = ANCMEvents::GetAreaGuid();
+            Event.dwEvent = 4;
+            Event.pszEventName = L"ANCM_REQUEST_FORWARD_END";
+            Event.dwEventVersion = 1;
+            Event.dwVerbosity = 4;
+            Event.cEventItems = 1;
+            Event.pActivityGuid = NULL;
+            Event.pRelatedActivityGuid = NULL;
+            Event.dwTimeStamp = 0;
+            Event.dwFlags = HTTP_TRACE_EVENT_FLAG_STATIC_DESCRIPTIVE_FIELDS;
+    
+            // pActivityGuid, pRelatedActivityGuid, Timestamp to be filled in by IIS
+    
+            HTTP_TRACE_EVENT_ITEM Items[ 1 ];
+            Items[ 0 ].pszName = L"ContextId";
+            Items[ 0 ].dwDataType = HTTP_TRACE_TYPE_LPCGUID; // mof type (object)
+            Items[ 0 ].pbData = (PBYTE) pContextId;
+            Items[ 0 ].cbData = 16;
+            Items[ 0 ].pszDataDescription = NULL;
+            Event.pEventItems = Items;
+            pHttpTraceContext->RaiseTraceEvent( &Event );
+            return S_OK;
+        };
+    
+        static
+        BOOL
+        IsEnabled( 
+            IHttpTraceContext *  pHttpTraceContext )
+        // Check if tracing for this event is enabled
+        {
+            return WWWServerTraceProvider::CheckTracingEnabled( 
+                                 pHttpTraceContext,
+                                 WWWServerTraceProvider::ANCM,
+                                 4 ); //Verbosity
+        };
+    };
+    //
+    // Event: mof class name ANCMForwardFail,
+    // Description: Forwarding request failure
+    // EventTypeName: ANCM_REQUEST_FORWARD_FAIL
+    // EventType: 5
+    // EventLevel: 2
+    //
+    
+    class ANCM_REQUEST_FORWARD_FAIL
+    {
+    public:
+        static
+        HRESULT
+        RaiseEvent(
+            IHttpTraceContext * pHttpTraceContext,
+            LPCGUID    pContextId,
+            ULONG      ErrorCode
+        )
+        //
+        // Raise ANCM_REQUEST_FORWARD_FAIL Event
+        //
+        {
+            HTTP_TRACE_EVENT Event;
+            Event.pProviderGuid = WWWServerTraceProvider::GetProviderGuid();
+            Event.dwArea =  WWWServerTraceProvider::ANCM;
+            Event.pAreaGuid = ANCMEvents::GetAreaGuid();
+            Event.dwEvent = 5;
+            Event.pszEventName = L"ANCM_REQUEST_FORWARD_FAIL";
+            Event.dwEventVersion = 1;
+            Event.dwVerbosity = 2;
+            Event.cEventItems = 2;
+            Event.pActivityGuid = NULL;
+            Event.pRelatedActivityGuid = NULL;
+            Event.dwTimeStamp = 0;
+            Event.dwFlags = HTTP_TRACE_EVENT_FLAG_STATIC_DESCRIPTIVE_FIELDS;
+    
+            // pActivityGuid, pRelatedActivityGuid, Timestamp to be filled in by IIS
+    
+            HTTP_TRACE_EVENT_ITEM Items[ 2 ];
+            Items[ 0 ].pszName = L"ContextId";
+            Items[ 0 ].dwDataType = HTTP_TRACE_TYPE_LPCGUID; // mof type (object)
+            Items[ 0 ].pbData = (PBYTE) pContextId;
+            Items[ 0 ].cbData = 16;
+            Items[ 0 ].pszDataDescription = NULL;
+            Items[ 1 ].pszName = L"ErrorCode";
+            Items[ 1 ].dwDataType = HTTP_TRACE_TYPE_ULONG; // mof type (uint32)
+            Items[ 1 ].pbData = (PBYTE) &ErrorCode;
+            Items[ 1 ].cbData = 4;
+            Items[ 1 ].pszDataDescription = NULL;
+            Event.pEventItems = Items;
+            pHttpTraceContext->RaiseTraceEvent( &Event );
+            return S_OK;
+        };
+    
+        static
+        BOOL
+        IsEnabled( 
+            IHttpTraceContext *  pHttpTraceContext )
+        // Check if tracing for this event is enabled
+        {
+            return WWWServerTraceProvider::CheckTracingEnabled( 
+                                 pHttpTraceContext,
+                                 WWWServerTraceProvider::ANCM,
+                                 2 ); //Verbosity
+        };
+    };
+    //
+    // Event: mof class name ANCMWinHttpCallBack,
+    // Description: Receiving callback from WinHttp
+    // EventTypeName: ANCM_WINHTTP_CALLBACK
+    // EventType: 6
+    // EventLevel: 4
+    //
+    
+    class ANCM_WINHTTP_CALLBACK
+    {
+    public:
+        static
+        HRESULT
+        RaiseEvent(
+            IHttpTraceContext * pHttpTraceContext,
+            LPCGUID    pContextId,
+            ULONG      InternetStatus
+        )
+        //
+        // Raise ANCM_WINHTTP_CALLBACK Event
+        //
+        {
+            HTTP_TRACE_EVENT Event;
+            Event.pProviderGuid = WWWServerTraceProvider::GetProviderGuid();
+            Event.dwArea =  WWWServerTraceProvider::ANCM;
+            Event.pAreaGuid = ANCMEvents::GetAreaGuid();
+            Event.dwEvent = 6;
+            Event.pszEventName = L"ANCM_WINHTTP_CALLBACK";
+            Event.dwEventVersion = 1;
+            Event.dwVerbosity = 4;
+            Event.cEventItems = 2;
+            Event.pActivityGuid = NULL;
+            Event.pRelatedActivityGuid = NULL;
+            Event.dwTimeStamp = 0;
+            Event.dwFlags = HTTP_TRACE_EVENT_FLAG_STATIC_DESCRIPTIVE_FIELDS;
+    
+            // pActivityGuid, pRelatedActivityGuid, Timestamp to be filled in by IIS
+    
+            HTTP_TRACE_EVENT_ITEM Items[ 2 ];
+            Items[ 0 ].pszName = L"ContextId";
+            Items[ 0 ].dwDataType = HTTP_TRACE_TYPE_LPCGUID; // mof type (object)
+            Items[ 0 ].pbData = (PBYTE) pContextId;
+            Items[ 0 ].cbData = 16;
+            Items[ 0 ].pszDataDescription = NULL;
+            Items[ 1 ].pszName = L"InternetStatus";
+            Items[ 1 ].dwDataType = HTTP_TRACE_TYPE_ULONG; // mof type (uint32)
+            Items[ 1 ].pbData = (PBYTE) &InternetStatus;
+            Items[ 1 ].cbData = 4;
+            Items[ 1 ].pszDataDescription = NULL;
+            Event.pEventItems = Items;
+            pHttpTraceContext->RaiseTraceEvent( &Event );
+            return S_OK;
+        };
+    
+        static
+        BOOL
+        IsEnabled( 
+            IHttpTraceContext *  pHttpTraceContext )
+        // Check if tracing for this event is enabled
+        {
+            return WWWServerTraceProvider::CheckTracingEnabled( 
+                                 pHttpTraceContext,
+                                 WWWServerTraceProvider::ANCM,
+                                 4 ); //Verbosity
+        };
+    };
+    //
+    // Event: mof class name ANCMForwardEnd,
+    // Description: Inprocess executing request failure
+    // EventTypeName: ANCM_EXECUTE_REQUEST_FAIL
+    // EventType: 7
+    // EventLevel: 2
+    //
+    
+    class ANCM_EXECUTE_REQUEST_FAIL
+    {
+    public:
+        static
+        HRESULT
+        RaiseEvent(
+            IHttpTraceContext * pHttpTraceContext,
+            LPCGUID    pContextId,
+            ULONG      ErrorCode
+        )
+        //
+        // Raise ANCM_EXECUTE_REQUEST_FAIL Event
+        //
+        {
+            HTTP_TRACE_EVENT Event;
+            Event.pProviderGuid = WWWServerTraceProvider::GetProviderGuid();
+            Event.dwArea =  WWWServerTraceProvider::ANCM;
+            Event.pAreaGuid = ANCMEvents::GetAreaGuid();
+            Event.dwEvent = 7;
+            Event.pszEventName = L"ANCM_EXECUTE_REQUEST_FAIL";
+            Event.dwEventVersion = 1;
+            Event.dwVerbosity = 2;
+            Event.cEventItems = 2;
+            Event.pActivityGuid = NULL;
+            Event.pRelatedActivityGuid = NULL;
+            Event.dwTimeStamp = 0;
+            Event.dwFlags = HTTP_TRACE_EVENT_FLAG_STATIC_DESCRIPTIVE_FIELDS;
+    
+            // pActivityGuid, pRelatedActivityGuid, Timestamp to be filled in by IIS
+    
+            HTTP_TRACE_EVENT_ITEM Items[ 2 ];
+            Items[ 0 ].pszName = L"ContextId";
+            Items[ 0 ].dwDataType = HTTP_TRACE_TYPE_LPCGUID; // mof type (object)
+            Items[ 0 ].pbData = (PBYTE) pContextId;
+            Items[ 0 ].cbData = 16;
+            Items[ 0 ].pszDataDescription = NULL;
+            Items[ 1 ].pszName = L"ErrorCode";
+            Items[ 1 ].dwDataType = HTTP_TRACE_TYPE_ULONG; // mof type (uint32)
+            Items[ 1 ].pbData = (PBYTE) &ErrorCode;
+            Items[ 1 ].cbData = 4;
+            Items[ 1 ].pszDataDescription = NULL;
+            Event.pEventItems = Items;
+            pHttpTraceContext->RaiseTraceEvent( &Event );
+            return S_OK;
+        };
+    
+        static
+        BOOL
+        IsEnabled( 
+            IHttpTraceContext *  pHttpTraceContext )
+        // Check if tracing for this event is enabled
+        {
+            return WWWServerTraceProvider::CheckTracingEnabled( 
+                                 pHttpTraceContext,
+                                 WWWServerTraceProvider::ANCM,
+                                 2 ); //Verbosity
+        };
+    };
+};
+#endif
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/RequestHandler/disconnectcontext.h b/src/IISIntegration/src/AspNetCoreModuleV2/RequestHandler/disconnectcontext.h
new file mode 100644
index 0000000000000000000000000000000000000000..e43a49c0a011e958ce9ef13e96de62534b586f55
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/RequestHandler/disconnectcontext.h
@@ -0,0 +1,78 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#pragma once
+
+class ASYNC_DISCONNECT_CONTEXT : public IHttpConnectionStoredContext
+{
+public:
+    ASYNC_DISCONNECT_CONTEXT()
+    {
+        m_pHandler = NULL;
+    }
+
+    VOID
+    CleanupStoredContext()
+    {
+        DBG_ASSERT(m_pHandler == NULL);
+        delete this;
+    }
+
+    VOID
+    NotifyDisconnect()
+    {
+        REQUEST_HANDLER *pInitialValue = (REQUEST_HANDLER*)
+            InterlockedExchangePointer((PVOID*)&m_pHandler, NULL);
+
+        if (pInitialValue != NULL)
+        {
+            pInitialValue->TerminateRequest(TRUE);
+            pInitialValue->DereferenceRequestHandler();
+        }
+    }
+
+    VOID
+    SetHandler(
+        REQUEST_HANDLER *pHandler
+    )
+    {
+        //
+        // Take a reference on the forwarding handler.
+        // This reference will be released on either of two conditions:
+        //
+        // 1. When the request processing ends, in which case a ResetHandler()
+        // is called.
+        // 
+        // 2. When a disconnect notification arrives.
+        //
+        // We need to make sure that only one of them ends up dereferencing
+        // the object.
+        //
+
+        DBG_ASSERT(pHandler != NULL);
+        DBG_ASSERT(m_pHandler == NULL);
+
+        pHandler->ReferenceRequestHandler();
+        InterlockedExchangePointer((PVOID*)&m_pHandler, pHandler);
+    }
+
+    VOID
+    ResetHandler(
+        VOID
+    )
+    {
+        REQUEST_HANDLER *pInitialValue = (REQUEST_HANDLER*)
+            InterlockedExchangePointer((PVOID*)&m_pHandler, NULL);
+
+        if (pInitialValue != NULL)
+        {
+            pInitialValue->DereferenceRequestHandler();
+        }
+    }
+
+private:
+    ~ASYNC_DISCONNECT_CONTEXT()
+    {}
+
+    REQUEST_HANDLER *     m_pHandler;
+};
\ No newline at end of file
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/RequestHandler/dllmain.cxx b/src/IISIntegration/src/AspNetCoreModuleV2/RequestHandler/dllmain.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..3cfdef0798404386bc08c9c09764c3b5af16c392
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/RequestHandler/dllmain.cxx
@@ -0,0 +1,369 @@
+// dllmain.cpp : Defines the entry point for the DLL application.
+#include "precomp.hxx"
+#include <IPHlpApi.h>
+#include <VersionHelpers.h>
+
+BOOL                g_fNsiApiNotSupported = FALSE;
+BOOL                g_fWebSocketSupported = FALSE;
+BOOL                g_fEnableReferenceCountTracing = FALSE;
+BOOL                g_fGlobalInitialize = FALSE;
+BOOL                g_fOutOfProcessInitialize = FALSE;
+BOOL                g_fOutOfProcessInitializeError = FALSE;
+BOOL                g_fWinHttpNonBlockingCallbackAvailable = FALSE;
+BOOL                g_fProcessDetach = FALSE;
+DWORD               g_OptionalWinHttpFlags = 0;
+DWORD               g_dwAspNetCoreDebugFlags = 0;
+DWORD               g_dwDebugFlags = 0;
+DWORD               g_dwTlsIndex = TLS_OUT_OF_INDEXES;
+SRWLOCK             g_srwLockRH;
+HINTERNET           g_hWinhttpSession = NULL;
+IHttpServer *       g_pHttpServer = NULL;
+HINSTANCE           g_hWinHttpModule;
+HINSTANCE           g_hAspNetCoreModule;
+HANDLE              g_hEventLog = NULL;
+
+
+VOID
+InitializeGlobalConfiguration(
+    IHttpServer * pServer
+)
+{
+    HKEY hKey;
+    BOOL fLocked = FALSE;
+    DWORD dwSize = 0;
+    DWORD dwResult = 0;
+
+    if (!g_fGlobalInitialize)
+    {
+        AcquireSRWLockExclusive(&g_srwLockRH);
+        fLocked = TRUE;
+
+        if (g_fGlobalInitialize)
+        {
+            // Done by another thread
+            goto Finished;
+        }
+
+        g_pHttpServer = pServer;
+        if (pServer->IsCommandLineLaunch())
+        {
+            g_hEventLog = RegisterEventSource(NULL, ASPNETCORE_IISEXPRESS_EVENT_PROVIDER);
+        }
+        else
+        {
+            g_hEventLog = RegisterEventSource(NULL, ASPNETCORE_EVENT_PROVIDER);
+        }
+
+        if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
+            L"SOFTWARE\\Microsoft\\IIS Extensions\\IIS AspNetCore Module\\Parameters",
+            0,
+            KEY_READ,
+            &hKey) == NO_ERROR)
+        {
+            DWORD dwType;
+            DWORD dwData;
+            DWORD cbData;
+
+            cbData = sizeof(dwData);
+            if ((RegQueryValueEx(hKey,
+                L"OptionalWinHttpFlags",
+                NULL,
+                &dwType,
+                (LPBYTE)&dwData,
+                &cbData) == NO_ERROR) &&
+                (dwType == REG_DWORD))
+            {
+                g_OptionalWinHttpFlags = dwData;
+            }
+
+            cbData = sizeof(dwData);
+            if ((RegQueryValueEx(hKey,
+                L"EnableReferenceCountTracing",
+                NULL,
+                &dwType,
+                (LPBYTE)&dwData,
+                &cbData) == NO_ERROR) &&
+                (dwType == REG_DWORD) && (dwData == 1 || dwData == 0))
+            {
+                g_fEnableReferenceCountTracing = !!dwData;
+            }
+
+            cbData = sizeof(dwData);
+            if ((RegQueryValueEx(hKey,
+                L"DebugFlags",
+                NULL,
+                &dwType,
+                (LPBYTE)&dwData,
+                &cbData) == NO_ERROR) &&
+                (dwType == REG_DWORD))
+            {
+                g_dwAspNetCoreDebugFlags = dwData;
+            }
+            RegCloseKey(hKey);
+        }
+
+        dwResult = GetExtendedTcpTable(NULL,
+            &dwSize,
+            FALSE,
+            AF_INET,
+            TCP_TABLE_OWNER_PID_LISTENER,
+            0);
+        if (dwResult != NO_ERROR && dwResult != ERROR_INSUFFICIENT_BUFFER)
+        {
+            g_fNsiApiNotSupported = TRUE;
+        }
+
+        g_fWebSocketSupported = IsWindows8OrGreater();
+
+        g_fGlobalInitialize = TRUE;
+    }
+Finished:
+    if (fLocked)
+    {
+        ReleaseSRWLockExclusive(&g_srwLockRH);
+    }
+}
+
+//
+// Global initialization routine for OutOfProcess
+//
+HRESULT
+EnsureOutOfProcessInitializtion()
+{
+
+    DBG_ASSERT(pServer);
+
+    HRESULT hr = S_OK;
+    BOOL    fLocked = FALSE;
+
+    if (g_fOutOfProcessInitializeError)
+    {
+        hr = E_NOT_VALID_STATE;
+        goto Finished;
+    }
+
+    if (!g_fOutOfProcessInitialize)
+    {
+        AcquireSRWLockExclusive(&g_srwLockRH);
+        fLocked = TRUE;
+        if (g_fOutOfProcessInitializeError)
+        {
+            hr = E_NOT_VALID_STATE;
+            goto Finished;
+        }
+
+        if (g_fOutOfProcessInitialize)
+        {
+            // Done by another thread
+            goto Finished;
+        }
+
+        g_hWinHttpModule = GetModuleHandle(TEXT("winhttp.dll"));
+
+        g_hAspNetCoreModule = GetModuleHandle(TEXT("aspnetcore.dll"));
+
+        hr = WINHTTP_HELPER::StaticInitialize();
+        if (FAILED(hr))
+        {
+            if (hr == HRESULT_FROM_WIN32(ERROR_PROC_NOT_FOUND))
+            {
+                g_fWebSocketSupported = FALSE;
+            }
+            else
+            {
+                goto Finished;
+            }
+        }
+
+        g_hWinhttpSession = WinHttpOpen(L"",
+            WINHTTP_ACCESS_TYPE_NO_PROXY,
+            WINHTTP_NO_PROXY_NAME,
+            WINHTTP_NO_PROXY_BYPASS,
+            WINHTTP_FLAG_ASYNC);
+        if (g_hWinhttpSession == NULL)
+        {
+            hr = HRESULT_FROM_WIN32(GetLastError());
+            goto Finished;
+        }
+
+        //
+        // Don't set non-blocking callbacks WINHTTP_OPTION_ASSURED_NON_BLOCKING_CALLBACKS, 
+        // as we will call WinHttpQueryDataAvailable to get response on the same thread
+        // that we received callback from Winhttp on completing sending/forwarding the request
+        // 
+
+        //
+        // Setup the callback function
+        //
+        if (WinHttpSetStatusCallback(g_hWinhttpSession,
+            FORWARDING_HANDLER::OnWinHttpCompletion,
+            (WINHTTP_CALLBACK_FLAG_ALL_COMPLETIONS |
+                WINHTTP_CALLBACK_STATUS_SENDING_REQUEST),
+            NULL) == WINHTTP_INVALID_STATUS_CALLBACK)
+        {
+            hr = HRESULT_FROM_WIN32(GetLastError());
+            goto Finished;
+        }
+
+        //
+        // Make sure we see the redirects (rather than winhttp doing it
+        // automatically)
+        //
+        DWORD dwRedirectOption = WINHTTP_OPTION_REDIRECT_POLICY_NEVER;
+        if (!WinHttpSetOption(g_hWinhttpSession,
+            WINHTTP_OPTION_REDIRECT_POLICY,
+            &dwRedirectOption,
+            sizeof(dwRedirectOption)))
+        {
+            hr = HRESULT_FROM_WIN32(GetLastError());
+            goto Finished;
+        }
+
+        g_dwTlsIndex = TlsAlloc();
+        if (g_dwTlsIndex == TLS_OUT_OF_INDEXES)
+        {
+            hr = HRESULT_FROM_WIN32(GetLastError());
+            goto Finished;
+        }
+
+        hr = FORWARDING_HANDLER::StaticInitialize(g_fEnableReferenceCountTracing);
+        if (FAILED(hr))
+        {
+            goto Finished;
+        }
+
+        hr = WEBSOCKET_HANDLER::StaticInitialize(g_fEnableReferenceCountTracing);
+        if (FAILED(hr))
+        {
+            goto Finished;
+        }
+    }
+
+Finished:
+    if (FAILED(hr))
+    {
+        g_fOutOfProcessInitializeError = TRUE;
+    }
+    if (fLocked)
+    {
+        ReleaseSRWLockExclusive(&g_srwLockRH);
+    }
+    return hr;
+}
+
+BOOL APIENTRY DllMain(HMODULE hModule,
+    DWORD  ul_reason_for_call,
+    LPVOID lpReserved
+)
+{
+    UNREFERENCED_PARAMETER(lpReserved);
+
+    switch (ul_reason_for_call)
+    {
+    case DLL_PROCESS_ATTACH:
+        DisableThreadLibraryCalls(hModule);
+        InitializeSRWLock(&g_srwLockRH);
+        break;
+    case DLL_PROCESS_DETACH:
+        g_fProcessDetach = TRUE;
+    default:
+        break;
+    }
+    return TRUE;
+}
+
+HRESULT
+__stdcall
+CreateApplication(
+    _In_  IHttpServer        *pServer,
+    _In_  ASPNETCORE_CONFIG  *pConfig,
+    _Out_ APPLICATION       **ppApplication
+)
+{
+    HRESULT      hr = S_OK;
+    APPLICATION *pApplication = NULL;
+
+    // Initialze some global variables here
+    InitializeGlobalConfiguration(pServer);
+
+    if (pConfig->QueryHostingModel() == APP_HOSTING_MODEL::HOSTING_IN_PROCESS)
+    {
+        pApplication = new IN_PROCESS_APPLICATION(pServer, pConfig);
+        if (pApplication == NULL)
+        {
+            hr = HRESULT_FROM_WIN32(ERROR_OUTOFMEMORY);
+            goto Finished;
+        }
+    }
+    else if (pConfig->QueryHostingModel() == APP_HOSTING_MODEL::HOSTING_OUT_PROCESS)
+    {
+        hr = EnsureOutOfProcessInitializtion();
+        if (FAILED(hr))
+        {
+            goto Finished;
+        }
+
+        pApplication = new OUT_OF_PROCESS_APPLICATION(pServer, pConfig);
+        if (pApplication == NULL)
+        {
+            hr = HRESULT_FROM_WIN32(ERROR_OUTOFMEMORY);
+            goto Finished;
+        }
+
+        hr = ((OUT_OF_PROCESS_APPLICATION*)pApplication)->Initialize();
+        if (FAILED(hr))
+        {
+            delete pApplication;
+            pApplication = NULL;
+            goto Finished;
+        }
+    }
+    else
+    {
+        hr = HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
+        goto Finished;
+    }
+
+    *ppApplication = pApplication;
+
+Finished:
+    return hr;
+}
+
+HRESULT
+__stdcall
+CreateRequestHandler(
+    _In_  IHttpContext       *pHttpContext,
+    _In_  HTTP_MODULE_ID     *pModuleId,
+    _In_  APPLICATION        *pApplication,
+    _Out_ REQUEST_HANDLER   **pRequestHandler
+)
+{
+    HRESULT hr = S_OK;
+    REQUEST_HANDLER* pHandler = NULL;
+    ASPNETCORE_CONFIG* pConfig = pApplication->QueryConfig();
+    DBG_ASSERT(pConfig);
+
+    if (pConfig->QueryHostingModel() == APP_HOSTING_MODEL::HOSTING_IN_PROCESS)
+    {
+        pHandler = new IN_PROCESS_HANDLER(pHttpContext, pModuleId, pApplication);
+    }
+    else if (pConfig->QueryHostingModel() == APP_HOSTING_MODEL::HOSTING_OUT_PROCESS)
+    {
+        pHandler = new FORWARDING_HANDLER(pHttpContext, pModuleId, pApplication);
+    }
+    else
+    {
+        return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
+    }
+
+    if (pHandler == NULL)
+    {
+        hr = HRESULT_FROM_WIN32(ERROR_OUTOFMEMORY);
+    }
+    else
+    {
+        *pRequestHandler = pHandler;
+    }
+    return hr;
+}
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/RequestHandler/environmentvariablehelpers.h b/src/IISIntegration/src/AspNetCoreModuleV2/RequestHandler/environmentvariablehelpers.h
new file mode 100644
index 0000000000000000000000000000000000000000..268011d30a87c492bd44a404ead8dc1fcc05acb4
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/RequestHandler/environmentvariablehelpers.h
@@ -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();
+};
+
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/RequestHandler/inprocess/inprocessapplication.cpp b/src/IISIntegration/src/AspNetCoreModuleV2/RequestHandler/inprocess/inprocessapplication.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..d8566262e1714d02174389d7e089e0d3ba14559f
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/RequestHandler/inprocess/inprocessapplication.cpp
@@ -0,0 +1,986 @@
+#include "..\precomp.hxx"
+
+IN_PROCESS_APPLICATION*  IN_PROCESS_APPLICATION::s_Application = NULL;
+
+IN_PROCESS_APPLICATION::IN_PROCESS_APPLICATION(
+    IHttpServer*        pHttpServer,
+    ASPNETCORE_CONFIG*  pConfig) :
+    APPLICATION(pHttpServer, pConfig),
+    m_pHttpServer(pHttpServer),
+    m_ProcessExitCode(0),
+    m_hLogFileHandle(INVALID_HANDLE_VALUE),
+    m_hErrReadPipe(INVALID_HANDLE_VALUE),
+    m_hErrWritePipe(INVALID_HANDLE_VALUE),
+    m_dwStdErrReadTotal(0),
+    m_fDoneStdRedirect(FALSE),
+    m_fBlockCallbacksIntoManaged(FALSE),
+    m_fInitialized(FALSE),
+    m_fShutdownCalledFromNative(FALSE),
+    m_fShutdownCalledFromManaged(FALSE),
+    m_srwLock()
+{
+    // is it guaranteed that we have already checked app offline at this point?
+    // If so, I don't think there is much to do here.
+    DBG_ASSERT(pHttpServer != NULL);
+    DBG_ASSERT(pConfig != NULL);
+    InitializeSRWLock(&m_srwLock);
+
+    // TODO we can probably initialized as I believe we are the only ones calling recycle.
+    m_status = APPLICATION_STATUS::STARTING;
+}
+
+IN_PROCESS_APPLICATION::~IN_PROCESS_APPLICATION()
+{
+    if (m_hLogFileHandle != INVALID_HANDLE_VALUE)
+    {
+        m_Timer.CancelTimer();
+        CloseHandle(m_hLogFileHandle);
+        m_hLogFileHandle = INVALID_HANDLE_VALUE;
+    }
+
+    m_hThread = NULL;
+    s_Application = NULL;
+}
+
+//static
+VOID
+IN_PROCESS_APPLICATION::DoShutDown(
+    LPVOID lpParam
+)
+{
+    IN_PROCESS_APPLICATION* pApplication = static_cast<IN_PROCESS_APPLICATION*>(lpParam);
+    DBG_ASSERT(pApplication);
+    pApplication->ShutDownInternal();
+}
+
+__override
+VOID
+IN_PROCESS_APPLICATION::ShutDown(
+    VOID
+)
+{
+    HRESULT hr = S_OK;
+    CHandle  hThread;
+    DWORD    dwThreadStatus = 0;
+    DWORD    dwTimeout = m_pConfig->QueryShutdownTimeLimitInMS();
+
+    if (IsDebuggerPresent())
+    {
+        dwTimeout = INFINITE;
+    }
+
+    hThread.Attach(CreateThread(
+        NULL,       // default security attributes
+        0,          // default stack size
+        (LPTHREAD_START_ROUTINE)DoShutDown,
+        this,       // thread function arguments
+        0,          // default creation flags
+        NULL));      // receive thread identifier
+
+    if ((HANDLE)hThread == NULL)
+    {
+        hr = HRESULT_FROM_WIN32(GetLastError());
+        goto Finished;
+    }
+
+    if (WaitForSingleObject(hThread, dwTimeout) != WAIT_OBJECT_0)
+    {
+        // if the thread is still running, we need kill it first before exit to avoid AV
+        if (GetExitCodeThread(m_hThread, &dwThreadStatus) != 0 && dwThreadStatus == STILL_ACTIVE)
+        {
+            // Calling back into managed at this point is prone to have AVs
+            // Calling terminate thread here may be our best solution.
+            TerminateThread(hThread, STATUS_CONTROL_C_EXIT);
+            hr = HRESULT_FROM_WIN32(ERROR_TIMEOUT);
+        }
+    }
+
+Finished:
+
+    if (FAILED(hr))
+    {
+        UTILITY::LogEventF(g_hEventLog,
+            EVENTLOG_WARNING_TYPE,
+            ASPNETCORE_EVENT_GRACEFUL_SHUTDOWN_FAILURE,
+            ASPNETCORE_EVENT_APP_SHUTDOWN_FAILURE_MSG,
+            m_pConfig->QueryConfigPath()->QueryStr());
+
+        //
+        // Managed layer may block the shutdown and lead to shutdown timeout
+        // Assumption: only one inprocess application is hosted.
+        // Call process exit to force shutdown
+        //
+        exit(hr);
+    }
+}
+
+
+VOID
+IN_PROCESS_APPLICATION::ShutDownInternal()
+{
+    DWORD    dwThreadStatus = 0;
+    DWORD    dwTimeout = m_pConfig->QueryShutdownTimeLimitInMS();
+    HANDLE   handle = NULL;
+    WIN32_FIND_DATA fileData;
+
+    if (IsDebuggerPresent())
+    {
+        dwTimeout = INFINITE;
+    }
+
+    if (m_fShutdownCalledFromNative ||
+        m_status == APPLICATION_STATUS::STARTING ||
+        m_status == APPLICATION_STATUS::FAIL)
+    {
+        return;
+    }
+
+    {
+        SRWLockWrapper lock(m_srwLock);
+
+        if (m_fShutdownCalledFromNative ||
+            m_status == APPLICATION_STATUS::STARTING ||
+            m_status == APPLICATION_STATUS::FAIL)
+        {
+            return;
+        }
+
+        // We need to keep track of when both managed and native initiate shutdown
+        // to avoid AVs. If shutdown has already been initiated in managed, we don't want to call into
+        // managed. We still need to wait on main exiting no matter what. m_fShutdownCalledFromNative
+        // is used for detecting redundant calls and blocking more requests to OnExecuteRequestHandler.
+        m_fShutdownCalledFromNative = TRUE;
+        m_status = APPLICATION_STATUS::SHUTDOWN;
+
+        if (!m_fShutdownCalledFromManaged)
+        {
+            // We cannot call into managed if the dll is detaching from the process.
+            // Calling into managed code when the dll is detaching is strictly a bad idea,
+            // and usually results in an AV saying "The string binding is invalid"
+            if (!g_fProcessDetach)
+            {
+                m_ShutdownHandler(m_ShutdownHandlerContext);
+                m_ShutdownHandler = NULL;
+            }
+        }
+
+        // Release the lock before we wait on the thread to exit.
+    }
+
+    if (!m_fShutdownCalledFromManaged)
+    {
+        if (m_hThread != NULL &&
+            GetExitCodeThread(m_hThread, &dwThreadStatus) != 0 &&
+            dwThreadStatus == STILL_ACTIVE)
+        {
+            // wait for graceful shutdown, i.e., the exit of the background thread or timeout
+            if (WaitForSingleObject(m_hThread, dwTimeout) != WAIT_OBJECT_0)
+            {
+                // if the thread is still running, we need kill it first before exit to avoid AV
+                if (GetExitCodeThread(m_hThread, &dwThreadStatus) != 0 && dwThreadStatus == STILL_ACTIVE)
+                {
+                    // Calling back into managed at this point is prone to have AVs
+                    // Calling terminate thread here may be our best solution.
+                    TerminateThread(m_hThread, STATUS_CONTROL_C_EXIT);
+                }
+            }
+        }
+    }
+
+    CloseHandle(m_hThread);
+    m_hThread = NULL;
+    s_Application = NULL;
+
+    CloseStdErrHandles();
+
+    if (m_pStdFile != NULL)
+    {
+        fflush(stdout);
+        fflush(stderr);
+        fclose(m_pStdFile);
+    }
+
+    if (m_hLogFileHandle != INVALID_HANDLE_VALUE)
+    {
+        m_Timer.CancelTimer();
+        CloseHandle(m_hLogFileHandle);
+        m_hLogFileHandle = INVALID_HANDLE_VALUE;
+    }
+
+    // delete empty log file
+    handle = FindFirstFile(m_struLogFilePath.QueryStr(), &fileData);
+    if (handle != INVALID_HANDLE_VALUE &&
+        fileData.nFileSizeHigh == 0 &&
+        fileData.nFileSizeLow == 0) // skip check of nFileSizeHigh
+    {
+        FindClose(handle);
+        // no need to check whether the deletion succeeds
+        // as nothing can be done
+        DeleteFile(m_struLogFilePath.QueryStr());
+    }
+}
+
+__override
+VOID
+IN_PROCESS_APPLICATION::Recycle(
+    VOID
+)
+{
+    // We need to guarantee that recycle is only called once, as calling pHttpServer->RecycleProcess
+    // multiple times can lead to AVs.
+    if (m_fRecycleCalled)
+    {
+        return;
+    }
+
+    {
+        SRWLockWrapper lock(m_srwLock);
+
+        if (m_fRecycleCalled)
+        {
+            return;
+        }
+
+        m_fRecycleCalled = true;
+    }
+
+    if (!m_pHttpServer->IsCommandLineLaunch())
+    {
+        // IIS scenario.
+        // notify IIS first so that new request will be routed to new worker process
+        m_pHttpServer->RecycleProcess(L"AspNetCore InProcess Recycle Process on Demand");
+    }
+    else
+    {
+        // IISExpress scenario
+        // Shutdown the managed application and call exit to terminate current process
+        ShutDown();
+        exit(0);
+    }
+}
+
+REQUEST_NOTIFICATION_STATUS
+IN_PROCESS_APPLICATION::OnAsyncCompletion(
+    DWORD           cbCompletion,
+    HRESULT         hrCompletionStatus,
+    IN_PROCESS_HANDLER* pInProcessHandler
+)
+{
+    REQUEST_NOTIFICATION_STATUS dwRequestNotificationStatus = RQ_NOTIFICATION_CONTINUE;
+
+    ReferenceApplication();
+
+    if (pInProcessHandler->QueryIsManagedRequestComplete())
+    {
+        // means PostCompletion has been called and this is the associated callback.
+        dwRequestNotificationStatus = pInProcessHandler->QueryAsyncCompletionStatus();
+    }
+    else if (m_fBlockCallbacksIntoManaged)
+    {
+        // this can potentially happen in ungraceful shutdown.
+        // Or something really wrong happening with async completions
+        // At this point, managed is in a shutting down state and we cannot send a request to it.
+        pInProcessHandler->QueryHttpContext()->GetResponse()->SetStatus(503,
+            "Server has been shutdown",
+            0,
+            (ULONG)HRESULT_FROM_WIN32(ERROR_SHUTDOWN_IN_PROGRESS));
+        dwRequestNotificationStatus = RQ_NOTIFICATION_FINISH_REQUEST;
+    }
+    else
+    {
+        // Call the managed handler for async completion.
+        dwRequestNotificationStatus = m_AsyncCompletionHandler(pInProcessHandler->QueryManagedHttpContext(), hrCompletionStatus, cbCompletion);
+    }
+
+    DereferenceApplication();
+
+    return dwRequestNotificationStatus;
+}
+
+REQUEST_NOTIFICATION_STATUS
+IN_PROCESS_APPLICATION::OnExecuteRequest(
+    _In_ IHttpContext* pHttpContext,
+    _In_ IN_PROCESS_HANDLER* pInProcessHandler
+)
+{
+    REQUEST_NOTIFICATION_STATUS dwRequestNotificationStatus = RQ_NOTIFICATION_CONTINUE;
+    PFN_REQUEST_HANDLER pRequestHandler = NULL;
+
+    ReferenceApplication();
+    pRequestHandler = m_RequestHandler;
+
+    if (pRequestHandler == NULL)
+    {
+        //
+        // return error as the application did not register callback
+        //
+        if (ANCMEvents::ANCM_EXECUTE_REQUEST_FAIL::IsEnabled(pHttpContext->GetTraceContext()))
+        {
+            ANCMEvents::ANCM_EXECUTE_REQUEST_FAIL::RaiseEvent(pHttpContext->GetTraceContext(),
+                NULL,
+                (ULONG)E_APPLICATION_ACTIVATION_EXEC_FAILURE);
+        }
+
+        pHttpContext->GetResponse()->SetStatus(500,
+            "Internal Server Error",
+            0,
+            (ULONG)E_APPLICATION_ACTIVATION_EXEC_FAILURE);
+
+        dwRequestNotificationStatus = RQ_NOTIFICATION_FINISH_REQUEST;
+    }
+    else if (m_status != APPLICATION_STATUS::RUNNING || m_fBlockCallbacksIntoManaged)
+    {
+        pHttpContext->GetResponse()->SetStatus(503,
+            "Server is currently shutting down.",
+            0,
+            (ULONG)HRESULT_FROM_WIN32(ERROR_SHUTDOWN_IN_PROGRESS));
+        dwRequestNotificationStatus = RQ_NOTIFICATION_FINISH_REQUEST;
+    }
+    else
+    {
+        dwRequestNotificationStatus = pRequestHandler(pInProcessHandler, m_RequestHandlerContext);
+    }
+
+    DereferenceApplication();
+
+    return dwRequestNotificationStatus;
+}
+
+VOID
+IN_PROCESS_APPLICATION::SetCallbackHandles(
+    _In_ PFN_REQUEST_HANDLER request_handler,
+    _In_ PFN_SHUTDOWN_HANDLER shutdown_handler,
+    _In_ PFN_MANAGED_CONTEXT_HANDLER async_completion_handler,
+    _In_ VOID* pvRequstHandlerContext,
+    _In_ VOID* pvShutdownHandlerContext
+)
+{
+    m_RequestHandler = request_handler;
+    m_RequestHandlerContext = pvRequstHandlerContext;
+    m_ShutdownHandler = shutdown_handler;
+    m_ShutdownHandlerContext = pvShutdownHandlerContext;
+    m_AsyncCompletionHandler = async_completion_handler;
+
+    CloseStdErrHandles();
+    // Can't check the std err handle as it isn't a critical error
+    SetStdHandle(STD_ERROR_HANDLE, INVALID_HANDLE_VALUE);
+    // Initialization complete
+    SetEvent(m_pInitalizeEvent);
+    m_fInitialized = TRUE;
+}
+
+VOID
+IN_PROCESS_APPLICATION::SetStdOut(
+    VOID
+)
+{
+    HRESULT                 hr = S_OK;
+    STRU                    struPath;
+    SYSTEMTIME              systemTime;
+    SECURITY_ATTRIBUTES     saAttr = { 0 };
+    HANDLE                  hStdErrReadPipe;
+    HANDLE                  hStdErrWritePipe;
+
+    if (!m_fDoneStdRedirect)
+    {
+        // Have not set stdout yet, redirect stdout to log file
+        SRWLockWrapper lock(m_srwLock);
+        if (!m_fDoneStdRedirect)
+        {
+            saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
+            saAttr.bInheritHandle = TRUE;
+            saAttr.lpSecurityDescriptor = NULL;
+
+            //
+            // best effort
+            // no need to capture the error code as nothing we can do here
+            // in case mamanged layer exits abnormally, may not be able to capture the log content as it is buffered.
+            //
+            if (!GetConsoleWindow())
+            {
+                // Full IIS scenario.
+
+                //
+                // SetStdHandle works as w3wp does not have Console
+                // Current process does not have a console
+                //
+                if (m_pConfig->QueryStdoutLogEnabled())
+                {
+                    hr = UTILITY::ConvertPathToFullPath(
+                        m_pConfig->QueryStdoutLogFile()->QueryStr(),
+                        m_pConfig->QueryApplicationPhysicalPath()->QueryStr(),
+                        &struPath);
+                    if (FAILED(hr))
+                    {
+                        goto Finished;
+                    }
+
+                    hr = UTILITY::EnsureDirectoryPathExist(struPath.QueryStr());
+                    if (FAILED(hr))
+                    {
+                        goto Finished;
+                    }
+
+                    GetSystemTime(&systemTime);
+                    hr = m_struLogFilePath.SafeSnwprintf(L"%s_%d%02d%02d%02d%02d%02d_%d.log",
+                        struPath.QueryStr(),
+                        systemTime.wYear,
+                        systemTime.wMonth,
+                        systemTime.wDay,
+                        systemTime.wHour,
+                        systemTime.wMinute,
+                        systemTime.wSecond,
+                        GetCurrentProcessId());
+                    if (FAILED(hr))
+                    {
+                        goto Finished;
+                    }
+
+                    m_hLogFileHandle = CreateFileW(m_struLogFilePath.QueryStr(),
+                        FILE_READ_DATA | FILE_WRITE_DATA,
+                        FILE_SHARE_READ,
+                        &saAttr,
+                        CREATE_ALWAYS,
+                        FILE_ATTRIBUTE_NORMAL,
+                        NULL);
+
+                    if (m_hLogFileHandle == INVALID_HANDLE_VALUE)
+                    {
+                        hr = HRESULT_FROM_WIN32(GetLastError());
+                        goto Finished;
+                    }
+
+                    if (!SetStdHandle(STD_OUTPUT_HANDLE, m_hLogFileHandle))
+                    {
+                        hr = HRESULT_FROM_WIN32(GetLastError());
+                        goto Finished;
+                    }
+
+                    if (!SetStdHandle(STD_ERROR_HANDLE, m_hLogFileHandle))
+                    {
+                        hr = HRESULT_FROM_WIN32(GetLastError());
+                        goto Finished;
+                    }
+
+                    // not work
+                    // AllocConsole()  does not help
+                    // *stdout = *m_pStdFile;
+                    // *stderr = *m_pStdFile;
+                    // _dup2(_fileno(m_pStdFile), _fileno(stdout));
+                    // _dup2(_fileno(m_pStdFile), _fileno(stderr));
+                    // this one cannot capture the process start failure
+                    // _wfreopen_s(&m_pStdFile, struLogFileName.QueryStr(), L"w", stdout);
+
+                    // Periodically flush the log content to file
+                    m_Timer.InitializeTimer(STTIMER::TimerCallback, &m_struLogFilePath, 3000, 3000);
+                }
+                else
+                {
+                    //
+                    // CreatePipe for outputting stderr to the windows event log.
+                    // Ignore failures
+                    //
+                    if (!CreatePipe(&hStdErrReadPipe, &hStdErrWritePipe, &saAttr, 0 /*nSize*/))
+                    {
+                        goto Finished;
+                    }
+
+                    if (!SetStdHandle(STD_ERROR_HANDLE, hStdErrWritePipe))
+                    {
+                        goto Finished;
+                    }
+
+                    m_hErrReadPipe = hStdErrReadPipe;
+                    m_hErrWritePipe = hStdErrWritePipe;
+
+                    // Read the stderr handle on a separate thread until we get 4096 bytes.
+                    m_hErrThread = CreateThread(
+                        NULL,       // default security attributes
+                        0,          // default stack size
+                        (LPTHREAD_START_ROUTINE)ReadStdErrHandle,
+                        this,       // thread function arguments
+                        0,          // default creation flags
+                        NULL);      // receive thread identifier
+
+                    if (m_hErrThread == NULL)
+                    {
+                        hr = HRESULT_FROM_WIN32(GetLastError());
+                        goto Finished;
+                    }
+                }
+            }
+            else
+            {
+                // The process has console, e.g., IIS Express scenario
+
+                if (_wfopen_s(&m_pStdFile, m_struLogFilePath.QueryStr(), L"w") == 0)
+                {
+                    // known issue: error info may not be capture when process crashes during buffering
+                    // even we disabled FILE buffering
+                    setvbuf(m_pStdFile, NULL, _IONBF, 0);
+                    _dup2(_fileno(m_pStdFile), _fileno(stdout));
+                    _dup2(_fileno(m_pStdFile), _fileno(stderr));
+                }
+                // These don't work for console scenario
+                // close and AllocConsole does not help
+                //_wfreopen_s(&m_pStdFile, struLogFileName.QueryStr(), L"w", stdout);
+                // SetStdHandle(STD_ERROR_HANDLE, m_hLogFileHandle);
+                // SetStdHandle(STD_OUTPUT_HANDLE, m_hLogFileHandle);
+                //*stdout = *m_pStdFile;
+                //*stderr = *m_pStdFile;
+            }
+        }
+    }
+
+Finished:
+    m_fDoneStdRedirect = TRUE;
+    if (FAILED(hr) && m_pConfig->QueryStdoutLogEnabled())
+    {
+        UTILITY::LogEventF(g_hEventLog,
+            EVENTLOG_WARNING_TYPE,
+            ASPNETCORE_EVENT_CONFIG_ERROR,
+            ASPNETCORE_EVENT_INVALID_STDOUT_LOG_FILE_MSG,
+            m_struLogFilePath.QueryStr(),
+            hr);
+    }
+}
+
+VOID
+IN_PROCESS_APPLICATION::ReadStdErrHandle(
+    LPVOID pContext
+)
+{
+    IN_PROCESS_APPLICATION *pApplication = (IN_PROCESS_APPLICATION*)pContext;
+    DBG_ASSERT(pApplication != NULL);
+    pApplication->ReadStdErrHandleInternal();
+}
+
+VOID
+IN_PROCESS_APPLICATION::ReadStdErrHandleInternal(
+    VOID
+)
+{
+    DWORD dwNumBytesRead = 0;
+    while (true)
+    {
+        if (ReadFile(m_hErrReadPipe, &m_pzFileContents[m_dwStdErrReadTotal], 4096 - m_dwStdErrReadTotal, &dwNumBytesRead, NULL))
+        {
+            m_dwStdErrReadTotal += dwNumBytesRead;
+            if (m_dwStdErrReadTotal >= 4096)
+            {
+                break;
+            }
+        }
+        else if (GetLastError() == ERROR_BROKEN_PIPE)
+        {
+            break;
+        }
+    }
+}
+
+VOID
+IN_PROCESS_APPLICATION::CloseStdErrHandles
+(
+    VOID
+)
+{
+    DWORD    dwThreadStatus = 0;
+    DWORD    dwTimeout = m_pConfig->QueryShutdownTimeLimitInMS();
+    // Close Handles for stderr as we only care about capturing startup errors
+    if (m_hErrWritePipe != INVALID_HANDLE_VALUE)
+    {
+        CloseHandle(m_hErrWritePipe);
+        m_hErrWritePipe = INVALID_HANDLE_VALUE;
+    }
+
+    if (m_hErrThread != NULL &&
+        GetExitCodeThread(m_hErrThread, &dwThreadStatus) != 0 &&
+        dwThreadStatus == STILL_ACTIVE)
+    {
+        // wait for gracefullshut down, i.e., the exit of the background thread or timeout
+        if (WaitForSingleObject(m_hErrThread, dwTimeout) != WAIT_OBJECT_0)
+        {
+            // if the thread is still running, we need kill it first before exit to avoid AV
+            if (GetExitCodeThread(m_hErrThread, &dwThreadStatus) != 0 && dwThreadStatus == STILL_ACTIVE)
+            {
+                TerminateThread(m_hErrThread, STATUS_CONTROL_C_EXIT);
+            }
+        }
+    }
+
+    CloseHandle(m_hErrThread);
+    m_hErrThread = NULL;
+
+    if (m_hErrReadPipe != INVALID_HANDLE_VALUE)
+    {
+        CloseHandle(m_hErrReadPipe);
+        m_hErrReadPipe = INVALID_HANDLE_VALUE;
+    }
+}
+
+// Will be called by the inprocesshandler
+HRESULT
+IN_PROCESS_APPLICATION::LoadManagedApplication
+(
+    VOID
+)
+{
+    HRESULT    hr = S_OK;
+    DWORD      dwTimeout;
+    DWORD      dwResult;
+
+    ReferenceApplication();
+
+    if (m_status != APPLICATION_STATUS::STARTING)
+    {
+        // Core CLR has already been loaded.
+        // Cannot load more than once even there was a failure
+        if (m_status == APPLICATION_STATUS::FAIL)
+        {
+            hr = E_APPLICATION_ACTIVATION_EXEC_FAILURE;
+        }
+        else if (m_status == APPLICATION_STATUS::SHUTDOWN)
+        {
+            hr = HRESULT_FROM_WIN32(ERROR_SHUTDOWN_IS_SCHEDULED);
+        }
+
+        goto Finished;
+    }
+
+    // Set up stdout redirect
+    SetStdOut();
+
+    {
+        SRWLockWrapper lock(m_srwLock);
+        if (m_status != APPLICATION_STATUS::STARTING)
+        {
+            if (m_status == APPLICATION_STATUS::FAIL)
+            {
+                hr = E_APPLICATION_ACTIVATION_EXEC_FAILURE;
+            }
+            else if (m_status == APPLICATION_STATUS::SHUTDOWN)
+            {
+                hr = HRESULT_FROM_WIN32(ERROR_SHUTDOWN_IS_SCHEDULED);
+            }
+
+            goto Finished;
+        }
+        m_hThread = CreateThread(
+            NULL,       // default security attributes
+            0,          // default stack size
+            (LPTHREAD_START_ROUTINE)ExecuteAspNetCoreProcess,
+            this,       // thread function arguments
+            0,          // default creation flags
+            NULL);      // receive thread identifier
+
+        if (m_hThread == NULL)
+        {
+            hr = HRESULT_FROM_WIN32(GetLastError());
+            goto Finished;
+        }
+
+        m_pInitalizeEvent = CreateEvent(
+            NULL,   // default security attributes
+            TRUE,   // manual reset event
+            FALSE,  // not set
+            NULL);  // name
+
+        if (m_pInitalizeEvent == NULL)
+        {
+            hr = HRESULT_FROM_WIN32(GetLastError());
+        }
+
+        // If the debugger is attached, never timeout
+        if (IsDebuggerPresent())
+        {
+            dwTimeout = INFINITE;
+        }
+        else
+        {
+            dwTimeout = m_pConfig->QueryStartupTimeLimitInMS();
+        }
+
+        const HANDLE pHandles[2]{ m_hThread, m_pInitalizeEvent };
+
+        // Wait on either the thread to complete or the event to be set
+        dwResult = WaitForMultipleObjects(2, pHandles, FALSE, dwTimeout);
+
+        // It all timed out
+        if (dwResult == WAIT_TIMEOUT)
+        {
+            // kill the backend thread as loading dotnet timedout
+            TerminateThread(m_hThread, 0);
+            hr = HRESULT_FROM_WIN32(dwResult);
+            goto Finished;
+        }
+        else if (dwResult == WAIT_FAILED)
+        {
+            hr = HRESULT_FROM_WIN32(GetLastError());
+            goto Finished;
+        }
+
+        // The thread ended it means that something failed
+        if (dwResult == WAIT_OBJECT_0)
+        {
+            hr = E_APPLICATION_ACTIVATION_EXEC_FAILURE;
+            goto Finished;
+        }
+
+        m_status = APPLICATION_STATUS::RUNNING;
+    }
+Finished:
+
+    if (FAILED(hr))
+    {
+        m_status = APPLICATION_STATUS::FAIL;
+
+        UTILITY::LogEventF(g_hEventLog,
+            EVENTLOG_ERROR_TYPE,
+            ASPNETCORE_EVENT_LOAD_CLR_FALIURE,
+            ASPNETCORE_EVENT_LOAD_CLR_FALIURE_MSG,
+            m_pConfig->QueryApplicationPath()->QueryStr(),
+            m_pConfig->QueryApplicationPhysicalPath()->QueryStr(),
+            hr);
+    }
+    DereferenceApplication();
+
+    return hr;
+}
+
+// static
+VOID
+IN_PROCESS_APPLICATION::ExecuteAspNetCoreProcess(
+    _In_ LPVOID pContext
+)
+{
+    HRESULT hr = S_OK;
+    IN_PROCESS_APPLICATION *pApplication = (IN_PROCESS_APPLICATION*)pContext;
+    DBG_ASSERT(pApplication != NULL);
+    hr = pApplication->ExecuteApplication();
+    //
+    // no need to log the error here as if error happened, the thread will exit
+    // the error will ba catched by caller LoadManagedApplication which will log an error
+    //
+
+}
+
+HRESULT
+IN_PROCESS_APPLICATION::SetEnvironementVariablesOnWorkerProcess(
+    VOID
+)
+{
+    HRESULT hr = S_OK;
+    ENVIRONMENT_VAR_HASH* pHashTable = NULL;
+    if (FAILED(hr = ENVIRONMENT_VAR_HELPERS::InitEnvironmentVariablesTable(
+        m_pConfig->QueryEnvironmentVariables(),
+        m_pConfig->QueryWindowsAuthEnabled(),
+        m_pConfig->QueryBasicAuthEnabled(),
+        m_pConfig->QueryAnonymousAuthEnabled(),
+        &pHashTable)))
+    {
+        goto Finished;
+    }
+
+    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;
+}
+
+HRESULT
+IN_PROCESS_APPLICATION::ExecuteApplication(
+    VOID
+)
+{
+    HRESULT             hr = S_OK;
+    HMODULE             hModule;
+    hostfxr_main_fn     pProc;
+
+    DBG_ASSERT(m_status == APPLICATION_STATUS::STARTING);
+
+    hModule = LoadLibraryW(m_pConfig->QueryHostFxrFullPath());
+
+    if (hModule == NULL)
+    {
+        // .NET Core not installed (we can log a more detailed error message here)
+        hr = ERROR_BAD_ENVIRONMENT;
+        goto Finished;
+    }
+
+    // Get the entry point for main
+    pProc = (hostfxr_main_fn)GetProcAddress(hModule, "hostfxr_main");
+    if (pProc == NULL)
+    {
+        hr = ERROR_BAD_ENVIRONMENT;
+        goto Finished;
+    }
+
+    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;
+
+    hr = RunDotnetApplication(m_pConfig->QueryHostFxrArgCount(), m_pConfig->QueryHostFxrArguments(), pProc);
+
+Finished:
+
+    //
+    // this method is called by the background thread and should never exit unless shutdown
+    // If main returned and shutdown was not called in managed, we want to block native from calling into
+    // managed. To do this, we can say that shutdown was called from managed.
+    // Don't bother locking here as there will always be a race between receiving a native shutdown
+    // notification and unexpected managed exit.
+    //
+    m_status = APPLICATION_STATUS::SHUTDOWN;
+    m_fShutdownCalledFromManaged = TRUE;
+    FreeLibrary(hModule);
+
+    if (!m_fShutdownCalledFromNative)
+    {
+        LogErrorsOnMainExit(hr);
+        if (m_fInitialized)
+        {
+            //
+            // If the inprocess server was initialized, we need to cause recycle to be called on the worker process.
+            //
+            Recycle();
+        }
+    }
+
+    return hr;
+}
+
+VOID
+IN_PROCESS_APPLICATION::LogErrorsOnMainExit(
+    HRESULT hr
+)
+{
+    //
+    // Ungraceful shutdown, try to log an error message.
+    // This will be a common place for errors as it means the hostfxr_main returned
+    // or there was an exception.
+    //
+    CHAR            pzFileContents[4096] = { 0 };
+    DWORD           dwNumBytesRead;
+    STRU            struStdErrLog;
+    LARGE_INTEGER   li = { 0 };
+    BOOL            fLogged = FALSE;
+    DWORD           dwFilePointer = 0;
+
+    if (m_pConfig->QueryStdoutLogEnabled())
+    {
+        // Put stdout/stderr logs into
+        if (m_hLogFileHandle != INVALID_HANDLE_VALUE)
+        {
+            if (GetFileSizeEx(m_hLogFileHandle, &li) && li.LowPart > 0 && li.HighPart == 0)
+            {
+                if (li.LowPart > 4096)
+                {
+                    dwFilePointer = SetFilePointer(m_hLogFileHandle, -4096, NULL, FILE_END);
+                }
+                else
+                {
+                    dwFilePointer = SetFilePointer(m_hLogFileHandle, 0, NULL, FILE_BEGIN);
+                }
+                if (dwFilePointer != INVALID_SET_FILE_POINTER)
+                {
+                    if (ReadFile(m_hLogFileHandle, pzFileContents, 4096, &dwNumBytesRead, NULL))
+                    {
+                        if (SUCCEEDED(struStdErrLog.CopyA(m_pzFileContents, m_dwStdErrReadTotal)))
+                        {
+                            UTILITY::LogEventF(g_hEventLog,
+                                EVENTLOG_ERROR_TYPE,
+                                ASPNETCORE_EVENT_INPROCESS_THREAD_EXIT,
+                                ASPNETCORE_EVENT_INPROCESS_THREAD_EXIT_STDOUT_MSG,
+                                m_pConfig->QueryApplicationPath()->QueryStr(),
+                                m_pConfig->QueryApplicationPhysicalPath()->QueryStr(),
+                                hr,
+                                struStdErrLog.QueryStr());
+                            fLogged = TRUE;
+
+                        }
+                    }
+                }
+            }
+        }
+    }
+    else
+    {
+        if (m_dwStdErrReadTotal > 0)
+        {
+            if (SUCCEEDED(struStdErrLog.CopyA(m_pzFileContents, m_dwStdErrReadTotal)))
+            {
+                UTILITY::LogEventF(g_hEventLog,
+                    EVENTLOG_ERROR_TYPE,
+                    ASPNETCORE_EVENT_INPROCESS_THREAD_EXIT,
+                    ASPNETCORE_EVENT_INPROCESS_THREAD_EXIT_STDERR_MSG,
+                    m_pConfig->QueryApplicationPath()->QueryStr(),
+                    m_pConfig->QueryApplicationPhysicalPath()->QueryStr(),
+                    hr,
+                    struStdErrLog.QueryStr());
+                fLogged = TRUE;
+            }
+        }
+    }
+
+    if (!fLogged)
+    {
+        // If we didn't log, log the generic message.
+        UTILITY::LogEventF(g_hEventLog,
+            EVENTLOG_ERROR_TYPE,
+            ASPNETCORE_EVENT_INPROCESS_THREAD_EXIT,
+            ASPNETCORE_EVENT_INPROCESS_THREAD_EXIT_MSG,
+            m_pConfig->QueryApplicationPath()->QueryStr(),
+            m_pConfig->QueryApplicationPhysicalPath()->QueryStr(),
+            hr);
+        fLogged = TRUE;
+    }
+}
+
+//
+// Calls hostfxr_main with the hostfxr and application as arguments.
+// Method should be called with only
+// Need to have __try / __except in methods that require unwinding.
+// Note, this will not
+//
+HRESULT
+IN_PROCESS_APPLICATION::RunDotnetApplication(DWORD argc, CONST PCWSTR* argv, hostfxr_main_fn pProc)
+{
+    HRESULT hr = S_OK;
+    __try
+    {
+        m_ProcessExitCode = pProc(argc, argv);
+    }
+    __except (FilterException(GetExceptionCode(), GetExceptionInformation()))
+    {
+        // TODO Log error message here.
+        hr = E_APPLICATION_ACTIVATION_EXEC_FAILURE;
+    }
+
+    return hr;
+}
+
+// static
+INT
+IN_PROCESS_APPLICATION::FilterException(unsigned int, struct _EXCEPTION_POINTERS*)
+{
+    // We assume that any exception is a failure as the applicaiton didn't start or there was a startup error.
+    // TODO, log error based on exception code.
+    return EXCEPTION_EXECUTE_HANDLER;
+}
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/RequestHandler/inprocess/inprocessapplication.h b/src/IISIntegration/src/AspNetCoreModuleV2/RequestHandler/inprocess/inprocessapplication.h
new file mode 100644
index 0000000000000000000000000000000000000000..a97fa0a3a94ec71f75b55dfbb3846a7a4ba46b1b
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/RequestHandler/inprocess/inprocessapplication.h
@@ -0,0 +1,191 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#pragma once
+
+typedef REQUEST_NOTIFICATION_STATUS(WINAPI * PFN_REQUEST_HANDLER) (IN_PROCESS_HANDLER* pInProcessHandler, void* pvRequestHandlerContext);
+typedef BOOL(WINAPI * PFN_SHUTDOWN_HANDLER) (void* pvShutdownHandlerContext);
+typedef REQUEST_NOTIFICATION_STATUS(WINAPI * PFN_MANAGED_CONTEXT_HANDLER)(void *pvManagedHttpContext, HRESULT hrCompletionStatus, DWORD cbCompletion);
+
+class IN_PROCESS_APPLICATION : public APPLICATION
+{
+public:
+    IN_PROCESS_APPLICATION(IHttpServer* pHttpServer, ASPNETCORE_CONFIG* pConfig);
+
+    ~IN_PROCESS_APPLICATION();
+
+    __override
+    VOID
+    ShutDown();
+
+    VOID
+    SetCallbackHandles(
+        _In_ PFN_REQUEST_HANDLER request_callback,
+        _In_ PFN_SHUTDOWN_HANDLER shutdown_callback,
+        _In_ PFN_MANAGED_CONTEXT_HANDLER managed_context_callback,
+        _In_ VOID* pvRequstHandlerContext,
+        _In_ VOID* pvShutdownHandlerContext
+    );
+
+    __override
+    VOID
+    Recycle(
+        VOID
+    );
+
+    // Executes the .NET Core process
+    HRESULT
+    ExecuteApplication(
+        VOID
+    );
+
+    VOID
+    ReadStdErrHandleInternal(
+        VOID
+    );
+
+    VOID
+    CloseStdErrHandles(
+        VOID
+    );
+
+    HRESULT
+    LoadManagedApplication(
+        VOID
+    );
+
+    VOID
+    LogErrorsOnMainExit(
+        HRESULT hr
+    );
+
+    REQUEST_NOTIFICATION_STATUS
+    OnAsyncCompletion(
+        DWORD                   cbCompletion,
+        HRESULT                 hrCompletionStatus,
+        IN_PROCESS_HANDLER*     pInProcessHandler
+    );
+
+    REQUEST_NOTIFICATION_STATUS
+    OnExecuteRequest
+    (
+        IHttpContext* pHttpContext,
+        IN_PROCESS_HANDLER* pInProcessHandler
+    );
+
+    VOID
+    StopCallsIntoManaged(
+        VOID
+    )
+    {
+        m_fBlockCallbacksIntoManaged = TRUE;
+    }
+
+    VOID
+    StopIncomingRequests(
+        VOID
+    )
+    {
+        m_fShutdownCalledFromManaged = TRUE;
+    }
+
+    static
+    IN_PROCESS_APPLICATION*
+    GetInstance(
+        VOID
+    )
+    {
+        return s_Application;
+    }
+
+private:
+    static
+    VOID
+    DoShutDown(
+        LPVOID lpParam
+    );
+
+    VOID
+    ShutDownInternal(
+        VOID
+    );
+
+    IHttpServer* const      m_pHttpServer;
+
+    // Thread executing the .NET Core process
+    HANDLE                          m_hThread;
+
+    // The request handler callback from managed code
+    PFN_REQUEST_HANDLER             m_RequestHandler;
+    VOID*                           m_RequestHandlerContext;
+
+    // The shutdown handler callback from managed code
+    PFN_SHUTDOWN_HANDLER            m_ShutdownHandler;
+    VOID*                           m_ShutdownHandlerContext;
+
+    PFN_MANAGED_CONTEXT_HANDLER     m_AsyncCompletionHandler;
+
+    // The event that gets triggered when managed initialization is complete
+    HANDLE                          m_pInitalizeEvent;
+
+    // The std log file handle
+    HANDLE                          m_hLogFileHandle;
+    HANDLE                          m_hErrReadPipe;
+    HANDLE                          m_hErrWritePipe;
+    STRU                            m_struLogFilePath;
+
+    // The exit code of the .NET Core process
+    INT                             m_ProcessExitCode;
+
+    BOOL                            m_fIsWebSocketsConnection;
+    BOOL                            m_fDoneStdRedirect;
+    volatile BOOL                   m_fBlockCallbacksIntoManaged;
+    volatile BOOL                   m_fShutdownCalledFromNative;
+    volatile BOOL                   m_fShutdownCalledFromManaged;
+    BOOL                            m_fRecycleCalled;
+    BOOL                            m_fInitialized;
+
+    FILE*                           m_pStdFile;
+    STTIMER                         m_Timer;
+    SRWLOCK                         m_srwLock;
+
+    // Thread for capturing startup stderr logs when logging is disabled
+    HANDLE                          m_hErrThread;
+    CHAR                            m_pzFileContents[4096] = { 0 };
+    DWORD                           m_dwStdErrReadTotal;
+    static IN_PROCESS_APPLICATION*  s_Application;
+
+    VOID
+    SetStdOut(
+        VOID
+    );
+
+    static
+    VOID
+    ExecuteAspNetCoreProcess(
+        _In_ LPVOID pContext
+    );
+
+    static
+    VOID
+    ReadStdErrHandle
+    (
+        _In_ LPVOID pContext
+    );
+
+    HRESULT
+    SetEnvironementVariablesOnWorkerProcess(
+        VOID
+    );
+
+    static
+    INT
+    FilterException(unsigned int code, struct _EXCEPTION_POINTERS *ep);
+
+    HRESULT
+    RunDotnetApplication(
+        DWORD argc,
+        CONST PCWSTR* argv,
+        hostfxr_main_fn pProc
+    );
+};
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/RequestHandler/inprocess/inprocesshandler.cpp b/src/IISIntegration/src/AspNetCoreModuleV2/RequestHandler/inprocess/inprocesshandler.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..c98d84744ca77ff53d02d9e991659136b7c6df41
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/RequestHandler/inprocess/inprocesshandler.cpp
@@ -0,0 +1,136 @@
+#include "..\precomp.hxx"
+
+IN_PROCESS_HANDLER::IN_PROCESS_HANDLER(
+    _In_ IHttpContext   *pW3Context,
+    _In_ HTTP_MODULE_ID *pModuleId,
+    _In_ APPLICATION    *pApplication
+): REQUEST_HANDLER(pW3Context, pModuleId, pApplication)
+{
+    m_fManagedRequestComplete = FALSE;
+}
+
+IN_PROCESS_HANDLER::~IN_PROCESS_HANDLER()
+{
+    //todo
+}
+
+__override
+REQUEST_NOTIFICATION_STATUS
+IN_PROCESS_HANDLER::OnExecuteRequestHandler()
+{
+    // First get the in process Application
+    HRESULT hr;
+    hr = ((IN_PROCESS_APPLICATION*)m_pApplication)->LoadManagedApplication();
+    if (FAILED(hr))
+    {
+        // TODO remove com_error?
+        /*_com_error err(hr);
+        if (ANCMEvents::ANCM_START_APPLICATION_FAIL::IsEnabled(m_pW3Context->GetTraceContext()))
+        {
+            ANCMEvents::ANCM_START_APPLICATION_FAIL::RaiseEvent(
+                m_pW3Context->GetTraceContext(),
+                NULL,
+                err.ErrorMessage());
+        }
+        */
+        //fInternalError = TRUE;
+        m_pW3Context->GetResponse()->SetStatus(500, "Internal Server Error", 0, hr);
+        return REQUEST_NOTIFICATION_STATUS::RQ_NOTIFICATION_FINISH_REQUEST;
+    }
+
+    // FREB log
+    
+    if (ANCMEvents::ANCM_START_APPLICATION_SUCCESS::IsEnabled(m_pW3Context->GetTraceContext()))
+    {
+        ANCMEvents::ANCM_START_APPLICATION_SUCCESS::RaiseEvent(
+            m_pW3Context->GetTraceContext(),
+            NULL,
+            L"InProcess Application");
+    }
+
+    //SetHttpSysDisconnectCallback();
+    return ((IN_PROCESS_APPLICATION*)m_pApplication)->OnExecuteRequest(m_pW3Context, this);
+}
+
+__override
+REQUEST_NOTIFICATION_STATUS
+IN_PROCESS_HANDLER::OnAsyncCompletion(
+    DWORD       cbCompletion,
+    HRESULT     hrCompletionStatus
+)
+{
+    IN_PROCESS_APPLICATION* application = (IN_PROCESS_APPLICATION*)m_pApplication;
+    if (application == NULL)
+    {
+        return RQ_NOTIFICATION_FINISH_REQUEST;
+    }
+
+    // OnAsyncCompletion must call into the application if there was a error. We will redo calls
+    // to Read/Write if we called cancelIo on the IHttpContext.
+    return application->OnAsyncCompletion(cbCompletion, hrCompletionStatus, this);
+}
+
+VOID
+IN_PROCESS_HANDLER::TerminateRequest(
+    bool    fClientInitiated
+)
+{
+    UNREFERENCED_PARAMETER(fClientInitiated);
+    //todo
+}
+
+PVOID
+IN_PROCESS_HANDLER::QueryManagedHttpContext(
+    VOID
+)
+{
+    return m_pManagedHttpContext;
+}
+
+BOOL
+IN_PROCESS_HANDLER::QueryIsManagedRequestComplete(
+    VOID
+)
+{
+    return m_fManagedRequestComplete;
+}
+
+IHttpContext*
+IN_PROCESS_HANDLER::QueryHttpContext(
+    VOID
+)
+{
+    return m_pW3Context;
+}
+
+VOID
+IN_PROCESS_HANDLER::IndicateManagedRequestComplete(
+    VOID
+)
+{
+    m_fManagedRequestComplete = TRUE;
+}
+
+REQUEST_NOTIFICATION_STATUS
+IN_PROCESS_HANDLER::QueryAsyncCompletionStatus(
+    VOID
+)
+{
+    return m_requestNotificationStatus;
+}
+
+VOID
+IN_PROCESS_HANDLER::SetAsyncCompletionStatus(
+    REQUEST_NOTIFICATION_STATUS requestNotificationStatus
+)
+{
+    m_requestNotificationStatus = requestNotificationStatus;
+}
+
+VOID
+IN_PROCESS_HANDLER::SetManagedHttpContext(
+    PVOID pManagedHttpContext
+)
+{
+    m_pManagedHttpContext = pManagedHttpContext;
+}
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/RequestHandler/inprocess/inprocesshandler.h b/src/IISIntegration/src/AspNetCoreModuleV2/RequestHandler/inprocess/inprocesshandler.h
new file mode 100644
index 0000000000000000000000000000000000000000..1ea1a8dbc56e79c17d9a00ae0c0f21c5495c0614
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/RequestHandler/inprocess/inprocesshandler.h
@@ -0,0 +1,72 @@
+#pragma once
+
+class IN_PROCESS_HANDLER : public REQUEST_HANDLER
+{
+public:
+    IN_PROCESS_HANDLER(
+
+        _In_ IHttpContext   *pW3Context,
+        _In_ HTTP_MODULE_ID *pModuleId,
+        _In_ APPLICATION    *pApplication);
+
+    ~IN_PROCESS_HANDLER();
+
+    __override
+    REQUEST_NOTIFICATION_STATUS
+    OnExecuteRequestHandler();
+
+    __override
+    REQUEST_NOTIFICATION_STATUS
+    OnAsyncCompletion(
+        DWORD       cbCompletion,
+        HRESULT     hrCompletionStatus
+    );
+
+    __override
+    VOID
+    TerminateRequest(
+        bool    fClientInitiated
+
+    );
+
+    PVOID
+    QueryManagedHttpContext(
+        VOID
+    );
+
+    VOID
+    SetManagedHttpContext(
+        PVOID pManagedHttpContext
+    );
+
+    IHttpContext*
+    QueryHttpContext(
+        VOID
+    );
+
+    BOOL
+    QueryIsManagedRequestComplete(
+        VOID
+    );
+
+    VOID
+    IndicateManagedRequestComplete(
+        VOID
+    );
+
+    REQUEST_NOTIFICATION_STATUS
+    QueryAsyncCompletionStatus(
+        VOID
+    );
+
+    VOID
+    SetAsyncCompletionStatus(
+        REQUEST_NOTIFICATION_STATUS requestNotificationStatus
+    );
+
+private:
+    PVOID m_pManagedHttpContext;
+    IHttpContext* m_pHttpContext;
+    BOOL m_fManagedRequestComplete;
+    REQUEST_NOTIFICATION_STATUS m_requestNotificationStatus;
+};
\ No newline at end of file
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/RequestHandler/managedexports.cxx b/src/IISIntegration/src/AspNetCoreModuleV2/RequestHandler/managedexports.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..85eb5b4d47df3c58adaa85bbc34290feec1639e7
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/RequestHandler/managedexports.cxx
@@ -0,0 +1,450 @@
+// Copyright (c) .NET Foundation and contributors. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+#include "precomp.hxx"
+
+//
+// Initialization export
+//
+EXTERN_C __MIDL_DECLSPEC_DLLEXPORT
+VOID
+register_callbacks(
+    _In_ PFN_REQUEST_HANDLER request_handler,
+    _In_ PFN_SHUTDOWN_HANDLER shutdown_handler,
+    _In_ PFN_MANAGED_CONTEXT_HANDLER async_completion_handler,
+    _In_ VOID* pvRequstHandlerContext,
+    _In_ VOID* pvShutdownHandlerContext
+)
+{
+    IN_PROCESS_APPLICATION::GetInstance()->SetCallbackHandles(
+        request_handler,
+        shutdown_handler,
+        async_completion_handler,
+        pvRequstHandlerContext,
+        pvShutdownHandlerContext
+    );
+}
+
+EXTERN_C __MIDL_DECLSPEC_DLLEXPORT
+HTTP_REQUEST*
+http_get_raw_request(
+    _In_ IN_PROCESS_HANDLER* pInProcessHandler
+)
+{
+    return pInProcessHandler->QueryHttpContext()->GetRequest()->GetRawHttpRequest();
+}
+
+EXTERN_C __MIDL_DECLSPEC_DLLEXPORT
+HTTP_RESPONSE*
+http_get_raw_response(
+    _In_ IN_PROCESS_HANDLER* pInProcessHandler
+)
+{
+    return pInProcessHandler->QueryHttpContext()->GetResponse()->GetRawHttpResponse();
+}
+
+EXTERN_C __MIDL_DECLSPEC_DLLEXPORT
+HRESULT
+http_get_server_variable(
+    _In_ IN_PROCESS_HANDLER* pInProcessHandler,
+    _In_ PCSTR pszVariableName,
+    _Out_ BSTR* pwszReturn
+)
+{
+    PCWSTR pszVariableValue;
+    DWORD cbLength;
+    HRESULT hr = pInProcessHandler
+        ->QueryHttpContext()
+        ->GetServerVariable(pszVariableName, &pszVariableValue, &cbLength);
+
+    if (FAILED(hr) || cbLength == 0)
+    {
+        goto Finished;
+    }
+
+    *pwszReturn = SysAllocString(pszVariableValue);
+
+    if (*pwszReturn == NULL)
+    {
+        hr = E_OUTOFMEMORY;
+        goto Finished;
+    }
+
+Finished:
+    return hr;
+}
+
+EXTERN_C __MIDL_DECLSPEC_DLLEXPORT
+HRESULT
+http_set_response_status_code(
+    _In_ IN_PROCESS_HANDLER* pInProcessHandler,
+    _In_ USHORT statusCode,
+    _In_ PCSTR pszReason
+)
+{
+    return pInProcessHandler->QueryHttpContext()->GetResponse()->SetStatus(statusCode, pszReason);
+}
+
+EXTERN_C __MIDL_DECLSPEC_DLLEXPORT
+HRESULT
+http_post_completion(
+    _In_ IN_PROCESS_HANDLER* pInProcessHandler,
+    DWORD cbBytes
+)
+{
+    return pInProcessHandler->QueryHttpContext()->PostCompletion(cbBytes);
+}
+
+EXTERN_C __MIDL_DECLSPEC_DLLEXPORT
+HRESULT
+http_set_completion_status(
+    _In_ IN_PROCESS_HANDLER* pInProcessHandler,
+    _In_ REQUEST_NOTIFICATION_STATUS requestNotificationStatus
+)
+{
+    HRESULT hr = S_OK;
+
+    pInProcessHandler->IndicateManagedRequestComplete();
+    pInProcessHandler->SetAsyncCompletionStatus(requestNotificationStatus);
+    return hr;
+}
+
+EXTERN_C __MIDL_DECLSPEC_DLLEXPORT
+HRESULT
+http_set_managed_context(
+    _In_ IN_PROCESS_HANDLER* pInProcessHandler,
+    _In_ PVOID pvManagedContext
+)
+{
+    // todo: should we consider changing the signature
+    HRESULT hr = S_OK;
+    pInProcessHandler->SetManagedHttpContext(pvManagedContext);
+
+    return hr;
+}
+
+EXTERN_C __MIDL_DECLSPEC_DLLEXPORT
+VOID
+http_indicate_completion(
+    _In_ IN_PROCESS_HANDLER* pInProcessHandler,
+    _In_ REQUEST_NOTIFICATION_STATUS notificationStatus
+)
+{
+    pInProcessHandler->QueryHttpContext()->IndicateCompletion(notificationStatus);
+}
+
+EXTERN_C __MIDL_DECLSPEC_DLLEXPORT
+VOID
+http_get_completion_info(
+    _In_ IHttpCompletionInfo2* info,
+    _Out_ DWORD* cbBytes,
+    _Out_ HRESULT* hr
+)
+{
+    *cbBytes = info->GetCompletionBytes();
+    *hr = info->GetCompletionStatus();
+}
+
+//
+// todo: we should not rely on IN_PROCESS_APPLICATION::GetInstance()
+// the signature should be changed. application's based address should be passed in
+//
+
+struct IISConfigurationData
+{
+    BSTR pwzFullApplicationPath;
+    BSTR pwzVirtualApplicationPath;
+    BOOL fWindowsAuthEnabled;
+    BOOL fBasicAuthEnabled;
+    BOOL fAnonymousAuthEnable;
+};
+
+EXTERN_C __MIDL_DECLSPEC_DLLEXPORT
+HRESULT
+http_get_application_properties(
+    _In_ IISConfigurationData* pIISCofigurationData
+)
+{
+    ASPNETCORE_CONFIG* pConfiguration = NULL;
+    IN_PROCESS_APPLICATION* pApplication = IN_PROCESS_APPLICATION::GetInstance();
+
+    if (pApplication == NULL)
+    {
+        return E_FAIL;
+    }
+
+    pConfiguration = pApplication->QueryConfig();
+
+    pIISCofigurationData->pwzFullApplicationPath = SysAllocString(pConfiguration->QueryApplicationPhysicalPath()->QueryStr());
+    pIISCofigurationData->pwzVirtualApplicationPath = SysAllocString(pConfiguration->QueryApplicationVirtualPath()->QueryStr());
+    pIISCofigurationData->fWindowsAuthEnabled = pConfiguration->QueryWindowsAuthEnabled();
+    pIISCofigurationData->fBasicAuthEnabled = pConfiguration->QueryBasicAuthEnabled();
+    pIISCofigurationData->fAnonymousAuthEnable = pConfiguration->QueryAnonymousAuthEnabled();
+
+    return S_OK;
+}
+
+EXTERN_C __MIDL_DECLSPEC_DLLEXPORT
+HRESULT
+http_read_request_bytes(
+    _In_ IN_PROCESS_HANDLER* pInProcessHandler,
+    _Out_ CHAR* pvBuffer,
+    _In_ DWORD dwCbBuffer,
+    _Out_ DWORD* pdwBytesReceived,
+    _Out_ BOOL* pfCompletionPending
+)
+{
+    HRESULT hr = S_OK;
+
+    if (pInProcessHandler == NULL)
+    {
+        return E_FAIL;
+    }
+    if (dwCbBuffer == 0)
+    {
+        return E_FAIL;
+    }
+    IHttpRequest *pHttpRequest = (IHttpRequest*)pInProcessHandler->QueryHttpContext()->GetRequest();
+
+    // Check if there is anything to read
+    if (pHttpRequest->GetRemainingEntityBytes() > 0)
+    {
+        BOOL fAsync = TRUE;
+        hr = pHttpRequest->ReadEntityBody(
+            pvBuffer,
+            dwCbBuffer,
+            fAsync,
+            pdwBytesReceived,
+            pfCompletionPending);
+
+        if (hr == HRESULT_FROM_WIN32(ERROR_HANDLE_EOF))
+        {
+            // We reached the end of the data
+            hr = S_OK;
+        }
+    }
+    else
+    {
+        *pdwBytesReceived = 0;
+        *pfCompletionPending = FALSE;
+    }
+
+    return hr;
+}
+
+EXTERN_C __MIDL_DECLSPEC_DLLEXPORT
+HRESULT
+http_write_response_bytes(
+    _In_ IN_PROCESS_HANDLER* pInProcessHandler,
+    _In_ HTTP_DATA_CHUNK* pDataChunks,
+    _In_ DWORD dwChunks,
+    _In_ BOOL* pfCompletionExpected
+)
+{
+    IHttpResponse *pHttpResponse = (IHttpResponse*)pInProcessHandler->QueryHttpContext()->GetResponse();
+    BOOL fAsync = TRUE;
+    BOOL fMoreData = TRUE;
+    DWORD dwBytesSent = 0;
+
+    HRESULT hr = pHttpResponse->WriteEntityChunks(
+        pDataChunks,
+        dwChunks,
+        fAsync,
+        fMoreData,
+        &dwBytesSent,
+        pfCompletionExpected);
+
+    return hr;
+}
+
+EXTERN_C __MIDL_DECLSPEC_DLLEXPORT
+HRESULT
+http_flush_response_bytes(
+    _In_ IN_PROCESS_HANDLER* pInProcessHandler,
+    _Out_ BOOL* pfCompletionExpected
+)
+{
+    IHttpResponse *pHttpResponse = (IHttpResponse*)pInProcessHandler->QueryHttpContext()->GetResponse();
+
+    BOOL fAsync = TRUE;
+    BOOL fMoreData = TRUE;
+    DWORD dwBytesSent = 0;
+
+    HRESULT hr = pHttpResponse->Flush(
+        fAsync,
+        fMoreData,
+        &dwBytesSent,
+        pfCompletionExpected);
+    return hr;
+}
+
+EXTERN_C __MIDL_DECLSPEC_DLLEXPORT
+HRESULT
+http_websockets_read_bytes(
+    _In_ IN_PROCESS_HANDLER* pInProcessHandler,
+    _In_ CHAR* pvBuffer,
+    _In_ DWORD cbBuffer,
+    _In_ PFN_ASYNC_COMPLETION pfnCompletionCallback,
+    _In_ VOID* pvCompletionContext,
+    _In_ DWORD* pDwBytesReceived,
+    _In_ BOOL* pfCompletionPending
+)
+{
+    IHttpRequest3 *pHttpRequest = (IHttpRequest3*)pInProcessHandler->QueryHttpContext()->GetRequest();
+
+    BOOL fAsync = TRUE;
+
+    HRESULT hr = pHttpRequest->ReadEntityBody(
+        pvBuffer,
+        cbBuffer,
+        fAsync,
+        pfnCompletionCallback,
+        pvCompletionContext,
+        pDwBytesReceived,
+        pfCompletionPending);
+
+    if (hr == HRESULT_FROM_WIN32(ERROR_HANDLE_EOF))
+    {
+        // We reached the end of the data
+        hr = S_OK;
+    }
+
+    return hr;
+}
+
+EXTERN_C __MIDL_DECLSPEC_DLLEXPORT
+HRESULT
+http_websockets_write_bytes(
+    _In_ IN_PROCESS_HANDLER* pInProcessHandler,
+    _In_ HTTP_DATA_CHUNK* pDataChunks,
+    _In_ DWORD dwChunks,
+    _In_ PFN_ASYNC_COMPLETION pfnCompletionCallback,
+    _In_ VOID* pvCompletionContext,
+    _In_ BOOL* pfCompletionExpected
+)
+{
+    IHttpResponse2 *pHttpResponse = (IHttpResponse2*)pInProcessHandler->QueryHttpContext()->GetResponse();
+
+    BOOL fAsync = TRUE;
+    BOOL fMoreData = TRUE;
+    DWORD dwBytesSent;
+
+    HRESULT hr = pHttpResponse->WriteEntityChunks(
+        pDataChunks,
+        dwChunks,
+        fAsync,
+        fMoreData,
+        pfnCompletionCallback,
+        pvCompletionContext,
+        &dwBytesSent,
+        pfCompletionExpected);
+
+    return hr;
+}
+
+EXTERN_C __MIDL_DECLSPEC_DLLEXPORT
+HRESULT
+http_websockets_flush_bytes(
+    _In_ IN_PROCESS_HANDLER* pInProcessHandler,
+    _In_ PFN_ASYNC_COMPLETION pfnCompletionCallback,
+    _In_ VOID* pvCompletionContext,
+    _In_ BOOL* pfCompletionExpected
+)
+{
+    IHttpResponse2 *pHttpResponse = (IHttpResponse2*)pInProcessHandler->QueryHttpContext()->GetResponse();
+
+    BOOL fAsync = TRUE;
+    BOOL fMoreData = TRUE;
+    DWORD dwBytesSent;
+
+    HRESULT hr = pHttpResponse->Flush(
+        fAsync,
+        fMoreData,
+        pfnCompletionCallback,
+        pvCompletionContext,
+        &dwBytesSent,
+        pfCompletionExpected);
+    return hr;
+}
+
+EXTERN_C __MIDL_DECLSPEC_DLLEXPORT
+HRESULT
+http_enable_websockets(
+    _In_ IN_PROCESS_HANDLER* pInProcessHandler
+)
+{
+    //if (!g_fWebSocketSupported)
+    //{
+    //    return E_FAIL;
+    //}
+
+    ((IHttpContext3*)pInProcessHandler->QueryHttpContext())->EnableFullDuplex();
+    ((IHttpResponse2*)pInProcessHandler->QueryHttpContext()->GetResponse())->DisableBuffering();
+
+    return S_OK;
+}
+
+EXTERN_C __MIDL_DECLSPEC_DLLEXPORT
+HRESULT
+http_cancel_io(
+    _In_ IN_PROCESS_HANDLER* pInProcessHandler
+)
+{
+    return pInProcessHandler->QueryHttpContext()->CancelIo();
+}
+
+EXTERN_C __MIDL_DECLSPEC_DLLEXPORT
+HRESULT
+http_response_set_unknown_header(
+    _In_ IN_PROCESS_HANDLER* pInProcessHandler,
+    _In_ PCSTR pszHeaderName,
+    _In_ PCSTR pszHeaderValue,
+    _In_ USHORT usHeaderValueLength,
+    _In_ BOOL  fReplace
+)
+{
+    return pInProcessHandler->QueryHttpContext()->GetResponse()->SetHeader(pszHeaderName, pszHeaderValue, usHeaderValueLength, fReplace);
+}
+
+EXTERN_C __MIDL_DECLSPEC_DLLEXPORT
+HRESULT
+http_response_set_known_header(
+    _In_ IN_PROCESS_HANDLER* pInProcessHandler,
+    _In_ HTTP_HEADER_ID dwHeaderId,
+    _In_ PCSTR pszHeaderValue,
+    _In_ USHORT usHeaderValueLength,
+    _In_ BOOL  fReplace
+)
+{
+    return pInProcessHandler->QueryHttpContext()->GetResponse()->SetHeader(dwHeaderId, pszHeaderValue, usHeaderValueLength, fReplace);
+}
+
+EXTERN_C __MIDL_DECLSPEC_DLLEXPORT
+HRESULT
+http_get_authentication_information(
+    _In_ IN_PROCESS_HANDLER* pInProcessHandler,
+    _Out_ BSTR* pstrAuthType,
+    _Out_ VOID** pvToken
+)
+{
+    *pstrAuthType = SysAllocString(pInProcessHandler->QueryHttpContext()->GetUser()->GetAuthenticationType());
+    *pvToken = pInProcessHandler->QueryHttpContext()->GetUser()->GetPrimaryToken();
+
+    return S_OK;
+}
+
+EXTERN_C __MIDL_DECLSPEC_DLLEXPORT
+VOID
+http_stop_calls_into_managed()
+{
+    IN_PROCESS_APPLICATION::GetInstance()->StopCallsIntoManaged();
+}
+
+EXTERN_C __MIDL_DECLSPEC_DLLEXPORT
+VOID
+http_stop_incoming_requests()
+{
+    IN_PROCESS_APPLICATION::GetInstance()->StopIncomingRequests();
+}
+
+// End of export
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/RequestHandler/outofprocess/forwarderconnection.cxx b/src/IISIntegration/src/AspNetCoreModuleV2/RequestHandler/outofprocess/forwarderconnection.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..99990f938cf931451c89ea619f81359c1aece967
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/RequestHandler/outofprocess/forwarderconnection.cxx
@@ -0,0 +1,52 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#include "..\precomp.hxx"
+
+FORWARDER_CONNECTION::FORWARDER_CONNECTION(
+    VOID
+) : m_cRefs (1),
+    m_hConnection (NULL)
+{    
+}
+
+HRESULT
+FORWARDER_CONNECTION::Initialize(
+    DWORD   dwPort
+)
+{
+    HRESULT hr = S_OK;
+
+    hr = m_ConnectionKey.Initialize( dwPort );
+    if ( FAILED( hr ) )
+    {
+        goto Finished;
+    }
+
+    m_hConnection = WinHttpConnect(g_hWinhttpSession,
+                                   L"127.0.0.1",
+                                   (USHORT) dwPort,
+                                   0);
+    if (m_hConnection == NULL)
+    {
+        hr = HRESULT_FROM_WIN32(GetLastError());
+        goto Finished;
+    }
+
+    //
+    // Since WinHttp will not emit WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING
+    // when closing WebSocket handle on Win8. Register callback at Connect level as a workaround
+    //
+    if (WinHttpSetStatusCallback(m_hConnection,
+                                 FORWARDING_HANDLER::OnWinHttpCompletion,
+                                 WINHTTP_CALLBACK_FLAG_HANDLES,
+                                 NULL) == WINHTTP_INVALID_STATUS_CALLBACK)
+    {
+        hr = HRESULT_FROM_WIN32(GetLastError());
+        goto Finished;
+    }
+
+Finished:
+
+    return hr;
+}
\ No newline at end of file
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/RequestHandler/outofprocess/forwarderconnection.h b/src/IISIntegration/src/AspNetCoreModuleV2/RequestHandler/outofprocess/forwarderconnection.h
new file mode 100644
index 0000000000000000000000000000000000000000..232e23988826ec6e30c526f497cafb0abb2b54f0
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/RequestHandler/outofprocess/forwarderconnection.h
@@ -0,0 +1,157 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#pragma once
+
+//
+// The key used for hash-table lookups, consists of the port on which the http process is created.
+//
+class FORWARDER_CONNECTION_KEY
+{
+public:
+
+    FORWARDER_CONNECTION_KEY(
+        VOID
+    )
+    {
+    }
+
+    HRESULT
+    Initialize(
+        _In_ DWORD  dwPort
+    )
+    {
+        m_dwPort = dwPort;
+        return S_OK;
+    }
+
+    BOOL
+    GetIsEqual(
+        const FORWARDER_CONNECTION_KEY * key2
+    ) const
+    {
+        return m_dwPort == key2->m_dwPort;
+    }
+
+    DWORD CalcKeyHash() const
+    {
+        // TODO: Review hash distribution.
+        return Hash(m_dwPort);
+    }
+
+private:
+
+    DWORD      m_dwPort;
+};
+
+class FORWARDER_CONNECTION
+{
+public:
+
+    FORWARDER_CONNECTION(
+        VOID
+    );
+
+    HRESULT
+    Initialize(
+        DWORD   dwPort
+    );
+
+    HINTERNET
+    QueryHandle() const
+    {
+        return m_hConnection;
+    }
+
+    VOID
+    ReferenceForwarderConnection() const
+    {
+        InterlockedIncrement(&m_cRefs);
+    }
+
+    VOID
+    DereferenceForwarderConnection() const
+    {
+        if (InterlockedDecrement(&m_cRefs) == 0)
+        {
+            delete this;
+        }
+    }
+
+    FORWARDER_CONNECTION_KEY *
+    QueryConnectionKey()
+    {
+        return &m_ConnectionKey;
+    }
+
+private:
+
+    ~FORWARDER_CONNECTION()
+    {
+        if (m_hConnection != NULL)
+        {
+            WinHttpCloseHandle(m_hConnection);
+            m_hConnection = NULL;
+        }
+    }
+
+    mutable LONG                m_cRefs;
+    FORWARDER_CONNECTION_KEY    m_ConnectionKey;
+    HINTERNET                   m_hConnection;
+};
+
+class FORWARDER_CONNECTION_HASH :
+    public HASH_TABLE<FORWARDER_CONNECTION, FORWARDER_CONNECTION_KEY *>
+{
+
+public:
+
+    FORWARDER_CONNECTION_HASH()
+    {}
+
+    FORWARDER_CONNECTION_KEY *
+    ExtractKey(
+        FORWARDER_CONNECTION *pConnection
+    )
+    {
+        return pConnection->QueryConnectionKey();
+    }
+
+    DWORD
+    CalcKeyHash(
+        FORWARDER_CONNECTION_KEY *key
+    )
+    {
+        return key->CalcKeyHash();
+    }
+
+    BOOL
+    EqualKeys(
+        FORWARDER_CONNECTION_KEY *key1,
+        FORWARDER_CONNECTION_KEY *key2
+    )
+    {
+        return key1->GetIsEqual(key2);
+    }
+
+    VOID
+    ReferenceRecord(
+        FORWARDER_CONNECTION *pConnection
+    )
+    {
+        pConnection->ReferenceForwarderConnection();
+    }
+
+    VOID
+    DereferenceRecord(
+        FORWARDER_CONNECTION *pConnection
+    )
+    {
+        pConnection->DereferenceForwarderConnection();
+    }
+
+private:
+
+    FORWARDER_CONNECTION_HASH(const FORWARDER_CONNECTION_HASH &);
+    void operator=(const FORWARDER_CONNECTION_HASH &);
+};
\ No newline at end of file
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/RequestHandler/outofprocess/forwardinghandler.cpp b/src/IISIntegration/src/AspNetCoreModuleV2/RequestHandler/outofprocess/forwardinghandler.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..4614b27d34b789030911198d2e83b266cc795ce1
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/RequestHandler/outofprocess/forwardinghandler.cpp
@@ -0,0 +1,2747 @@
+#include "..\precomp.hxx"
+
+// Just to be aware of the FORWARDING_HANDLER object size.
+C_ASSERT(sizeof(FORWARDING_HANDLER) <= 632);
+
+#define DEF_MAX_FORWARDS        32
+#define HEX_TO_ASCII(c) ((CHAR)(((c) < 10) ? ((c) + '0') : ((c) + 'a' - 10)))
+#define BUFFER_SIZE         (8192UL)
+#define ENTITY_BUFFER_SIZE  (6 + BUFFER_SIZE + 2)
+
+#define FORWARDING_HANDLER_SIGNATURE        ((DWORD)'FHLR')
+#define FORWARDING_HANDLER_SIGNATURE_FREE   ((DWORD)'fhlr')
+
+STRA                        FORWARDING_HANDLER::sm_pStra502ErrorMsg;
+ALLOC_CACHE_HANDLER *       FORWARDING_HANDLER::sm_pAlloc = NULL;
+TRACE_LOG *                 FORWARDING_HANDLER::sm_pTraceLog = NULL;
+PROTOCOL_CONFIG             FORWARDING_HANDLER::sm_ProtocolConfig;
+RESPONSE_HEADER_HASH *      FORWARDING_HANDLER::sm_pResponseHeaderHash = NULL;
+
+FORWARDING_HANDLER::FORWARDING_HANDLER(
+    _In_ IHttpContext     *pW3Context,
+    _In_  HTTP_MODULE_ID  *pModuleId,
+    _In_ APPLICATION      *pApplication
+) : REQUEST_HANDLER(pW3Context, pModuleId, pApplication),
+    m_Signature(FORWARDING_HANDLER_SIGNATURE),
+    m_RequestStatus(FORWARDER_START),
+    m_fClientDisconnected(FALSE),
+    m_fResponseHeadersReceivedAndSet(FALSE),
+    m_fDoReverseRewriteHeaders(FALSE),
+    m_fFinishRequest(FALSE),
+    m_fHasError(FALSE),
+    m_pszHeaders(NULL),
+    m_cchHeaders(0),
+    m_BytesToReceive(0),
+    m_BytesToSend(0),
+    m_fWebSocketEnabled(FALSE),
+    m_pWebSocket(NULL),
+    m_dwHandlers (1), // default http handler
+    m_fDoneAsyncCompletion(FALSE),
+    m_fHttpHandleInClose(FALSE),
+    m_fWebSocketHandleInClose(FALSE),
+    m_fServerResetConn(FALSE)
+{
+#ifdef DEBUG
+    DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO,
+        "FORWARDING_HANDLER::FORWARDING_HANDLER");
+#endif
+
+    InitializeSRWLock(&m_RequestLock);
+}
+
+FORWARDING_HANDLER::~FORWARDING_HANDLER(
+)
+{
+    //
+    // Destructor has started.
+    //
+    m_Signature = FORWARDING_HANDLER_SIGNATURE_FREE;
+
+#ifdef DEBUG
+    DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO,
+        "FORWARDING_HANDLER::~FORWARDING_HANDLER");
+#endif
+    //
+    // RemoveRequest() should already have been called and m_pDisconnect
+    // has been freed or m_pDisconnect was never initialized.
+    //
+    // Disconnect notification cleanup would happen first, before
+    // the FORWARDING_HANDLER instance got removed from m_pSharedhandler list.
+    // The m_pServer cleanup would happen afterwards, since there may be a 
+    // call pending from SHARED_HANDLER to  FORWARDING_HANDLER::SetStatusAndHeaders()
+    // 
+    DBG_ASSERT(m_pDisconnect == NULL);
+
+    RemoveRequest();
+
+    FreeResponseBuffers();
+
+    if (m_pWebSocket)
+    {
+        m_pWebSocket->Terminate();
+        m_pWebSocket = NULL;
+    }
+}
+
+__override
+REQUEST_NOTIFICATION_STATUS
+FORWARDING_HANDLER::OnExecuteRequestHandler()
+{
+    REQUEST_NOTIFICATION_STATUS retVal = RQ_NOTIFICATION_CONTINUE;
+    HRESULT                     hr = S_OK;
+    BOOL                        fRequestLocked = FALSE;
+    BOOL                        fHandleSet = FALSE;
+    BOOL                        fFailedToStartKestrel = FALSE;
+    BOOL                        fSecure = FALSE;
+    HINTERNET                   hConnect = NULL;
+    IHttpRequest               *pRequest = m_pW3Context->GetRequest();
+    IHttpResponse              *pResponse = m_pW3Context->GetResponse();
+    IHttpConnection            *pClientConnection = NULL;
+    OUT_OF_PROCESS_APPLICATION *pApplication = NULL;
+    PROTOCOL_CONFIG            *pProtocol = &sm_ProtocolConfig;
+    SERVER_PROCESS             *pServerProcess = NULL;
+
+    USHORT                      cchHostName = 0;
+
+    STACK_STRU(strDestination, 32);
+    STACK_STRU(strUrl, 2048);
+    STACK_STRU(struEscapedUrl, 2048);
+
+    //
+    // Take a reference so that object does not go away as a result of
+    // async completion.
+    //
+    ReferenceRequestHandler();
+
+    // override Protocol related config from aspNetCore config
+    pProtocol->OverrideConfig(m_pApplication->QueryConfig());
+
+    // check connection
+    pClientConnection = m_pW3Context->GetConnection();
+    if (pClientConnection == NULL ||
+        !pClientConnection->IsConnected())
+    {
+        hr = HRESULT_FROM_WIN32(WSAECONNRESET);
+        goto Failure;
+    }
+
+    pApplication = static_cast<OUT_OF_PROCESS_APPLICATION*> (m_pApplication);
+    if (pApplication == NULL)
+    {
+        hr = E_INVALIDARG;
+        goto Failure;
+    }
+
+    hr = pApplication->GetProcess(&pServerProcess);
+    if (FAILED(hr))
+    {
+        fFailedToStartKestrel = TRUE;
+        goto Failure;
+    }
+
+    if (pServerProcess == NULL)
+    {
+        fFailedToStartKestrel = TRUE;
+        hr = HRESULT_FROM_WIN32(ERROR_CREATE_FAILED);
+        goto Failure;
+    }
+
+    if (pServerProcess->QueryWinHttpConnection() == NULL)
+    {
+        hr = HRESULT_FROM_WIN32(ERROR_INVALID_HANDLE);
+        goto Failure;
+    }
+
+    hConnect = pServerProcess->QueryWinHttpConnection()->QueryHandle();
+
+    m_pszOriginalHostHeader = pRequest->GetHeader(HttpHeaderHost, &cchHostName);
+    //
+    // parse original url
+    //
+    if (FAILED(hr = UTILITY::SplitUrl(pRequest->GetRawHttpRequest()->CookedUrl.pFullUrl,
+        &fSecure,
+        &strDestination,
+        &strUrl)))
+    {
+        goto Failure;
+    }
+
+    if (FAILED(hr = UTILITY::EscapeAbsPath(pRequest, &struEscapedUrl)))
+    {
+        goto Failure;
+    }
+
+    m_fDoReverseRewriteHeaders = pProtocol->QueryReverseRewriteHeaders();
+
+    m_cMinBufferLimit = pProtocol->QueryMinResponseBuffer();
+
+    //
+    // Mark request as websocket if upgrade header is present.
+    //
+    if (pApplication->QueryConfig()->QueryWebSocketEnabled())
+    {
+        USHORT cchHeader = 0;
+        PCSTR pszWebSocketHeader = pRequest->GetHeader("Upgrade", &cchHeader);
+        if (cchHeader == 9 && _stricmp(pszWebSocketHeader, "websocket") == 0)
+        {
+            m_fWebSocketEnabled = TRUE;
+        }
+    }
+
+    hr = CreateWinHttpRequest(pRequest,
+        pProtocol,
+        hConnect,
+        &struEscapedUrl,
+        pServerProcess);
+    if (FAILED(hr))
+    {
+        goto Failure;
+    }
+
+    // Set client disconnect callback contract with IIS
+    m_pDisconnect = static_cast<ASYNC_DISCONNECT_CONTEXT *>(
+        pClientConnection->GetModuleContextContainer()->
+        GetConnectionModuleContext(m_pModuleId));
+    if (m_pDisconnect == NULL)
+    {
+        m_pDisconnect = new ASYNC_DISCONNECT_CONTEXT();
+        if (m_pDisconnect == NULL)
+        {
+            hr = E_OUTOFMEMORY;
+            goto Failure;
+        }
+
+        hr = pClientConnection->GetModuleContextContainer()->
+            SetConnectionModuleContext(m_pDisconnect,
+                m_pModuleId);
+        DBG_ASSERT(hr != HRESULT_FROM_WIN32(ERROR_ALREADY_ASSIGNED));
+        if (FAILED(hr))
+        {
+            goto Failure;
+        }
+    }
+
+    m_pDisconnect->SetHandler(this);
+    fHandleSet = TRUE;
+
+    // require lock as client disconnect callback may happen
+    AcquireSRWLockShared(&m_RequestLock);
+    fRequestLocked = TRUE;
+
+    //
+    // Remember the handler being processed in the current thread
+    // before staring a WinHTTP operation.
+    //
+    DBG_ASSERT(fRequestLocked);
+    DBG_ASSERT(TlsGetValue(g_dwTlsIndex) == NULL);
+    TlsSetValue(g_dwTlsIndex, this);
+    DBG_ASSERT(TlsGetValue(g_dwTlsIndex) == this);
+
+    if (m_hRequest == NULL)
+    {
+        hr = HRESULT_FROM_WIN32(WSAECONNRESET);
+        goto Failure;
+    }
+
+    //
+    // Begins normal request handling. Send request to server.
+    //
+    m_RequestStatus = FORWARDER_SENDING_REQUEST;
+
+    //
+    // Calculate the bytes to receive from the content length.
+    //
+    DWORD cbContentLength = 0;
+    PCSTR pszContentLength = pRequest->GetHeader(HttpHeaderContentLength);
+    if (pszContentLength != NULL)
+    {
+        cbContentLength = m_BytesToReceive = atol(pszContentLength);
+        if (m_BytesToReceive == INFINITE)
+        {
+            hr = HRESULT_FROM_WIN32(WSAECONNRESET);
+            goto Failure;
+        }
+    }
+    else if (pRequest->GetHeader(HttpHeaderTransferEncoding) != NULL)
+    {
+        m_BytesToReceive = INFINITE;
+    }
+
+    if (m_fWebSocketEnabled)
+    {
+        //
+        // Set the upgrade flag for a websocket request.
+        //
+        if (!WinHttpSetOption(m_hRequest,
+            WINHTTP_OPTION_UPGRADE_TO_WEB_SOCKET,
+            NULL,
+            0))
+        {
+            hr = HRESULT_FROM_WIN32(GetLastError());
+            goto Finished;
+        }
+    }
+
+    m_cchLastSend = m_cchHeaders;
+
+    //FREB log
+    if (ANCMEvents::ANCM_REQUEST_FORWARD_START::IsEnabled(m_pW3Context->GetTraceContext()))
+    {
+        ANCMEvents::ANCM_REQUEST_FORWARD_START::RaiseEvent(
+            m_pW3Context->GetTraceContext(),
+            NULL);
+    }
+
+    if (!WinHttpSendRequest(m_hRequest,
+        m_pszHeaders,
+        m_cchHeaders,
+        NULL,
+        0,
+        cbContentLength,
+        reinterpret_cast<DWORD_PTR>(static_cast<PVOID>(this))))
+    {
+        hr = HRESULT_FROM_WIN32(GetLastError());
+#ifdef DEBUG
+        DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO,
+            "FORWARDING_HANDLER::OnExecuteRequestHandler, Send request failed");
+#endif
+        // FREB log
+        if (ANCMEvents::ANCM_REQUEST_FORWARD_FAIL::IsEnabled(m_pW3Context->GetTraceContext()))
+        {
+            ANCMEvents::ANCM_REQUEST_FORWARD_FAIL::RaiseEvent(
+                m_pW3Context->GetTraceContext(),
+                NULL,
+                hr);
+        }
+
+        goto Failure;
+    }
+
+    //
+    // Async WinHTTP operation is in progress. Release this thread meanwhile,
+    // OnWinHttpCompletion method should resume the work by posting an IIS completion.
+    //
+    retVal = RQ_NOTIFICATION_PENDING;
+    goto Finished;
+
+Failure:
+    m_RequestStatus = FORWARDER_DONE;
+
+    //disable client disconnect callback
+    RemoveRequest();
+
+    pResponse->DisableKernelCache();
+    pResponse->GetRawHttpResponse()->EntityChunkCount = 0;
+    if (hr == HRESULT_FROM_WIN32(WSAECONNRESET))
+    {
+        pResponse->SetStatus(400, "Bad Request", 0, hr);
+    }
+    else if (fFailedToStartKestrel && !m_pApplication->QueryConfig()->QueryDisableStartUpErrorPage())
+    {
+        HTTP_DATA_CHUNK   DataChunk;
+        pResponse->SetStatus(502, "Bad Gateway", 5, hr, NULL, TRUE);
+        pResponse->SetHeader("Content-Type",
+            "text/html",
+            (USHORT)strlen("text/html"),
+            FALSE
+        );
+
+        DataChunk.DataChunkType = HttpDataChunkFromMemory;
+        DataChunk.FromMemory.pBuffer = (PVOID)sm_pStra502ErrorMsg.QueryStr();
+        DataChunk.FromMemory.BufferLength = sm_pStra502ErrorMsg.QueryCB();
+        pResponse->WriteEntityChunkByReference(&DataChunk);
+    }
+    else
+    {
+        //
+        // default error behavior
+        //
+        pResponse->SetStatus(502, "Bad Gateway", 3, hr);
+    }
+    //
+    // Finish the request on failure.
+    //
+    retVal = RQ_NOTIFICATION_FINISH_REQUEST;
+
+Finished:
+    if (fRequestLocked)
+    {
+        DBG_ASSERT(TlsGetValue(g_dwTlsIndex) == this);
+        TlsSetValue(g_dwTlsIndex, NULL);
+        ReleaseSRWLockShared(&m_RequestLock);
+        DBG_ASSERT(TlsGetValue(g_dwTlsIndex) == NULL);
+    }
+
+    DereferenceRequestHandler();
+    //
+    // Do not use this object after dereferencing it, it may be gone.
+    //
+
+    return retVal;
+}
+
+__override
+REQUEST_NOTIFICATION_STATUS
+FORWARDING_HANDLER::OnAsyncCompletion(
+    DWORD           cbCompletion,
+    HRESULT         hrCompletionStatus
+)
+/*++
+
+Routine Description:
+
+Handle the completion from IIS and continue the execution
+of this request based on the current state.
+
+Arguments:
+
+cbCompletion - Number of bytes associated with this completion
+dwCompletionStatus - the win32 status associated with this completion
+
+Return Value:
+
+REQUEST_NOTIFICATION_STATUS
+
+--*/
+{
+    HRESULT                     hr = S_OK;
+    REQUEST_NOTIFICATION_STATUS retVal = RQ_NOTIFICATION_PENDING;
+    BOOL                        fLocked = FALSE;
+    BOOL                        fClientError = FALSE;
+    BOOL                        fClosed = FALSE;
+    BOOL                        fWebSocketUpgraded = FALSE;
+
+    DBG_ASSERT(m_pW3Context != NULL);
+    __analysis_assume(m_pW3Context != NULL);
+
+    //
+    // Take a reference so that object does not go away as a result of
+    // async completion.
+    //
+    ReferenceRequestHandler();
+
+    if (sm_pTraceLog != NULL)
+    {
+        WriteRefTraceLogEx(sm_pTraceLog,
+            m_cRefs,
+            this,
+            "FORWARDING_HANDLER::OnAsyncCompletion Enter",
+            reinterpret_cast<PVOID>(static_cast<DWORD_PTR>(cbCompletion)),
+            reinterpret_cast<PVOID>(static_cast<DWORD_PTR>(hrCompletionStatus)));
+    }
+
+    if (TlsGetValue(g_dwTlsIndex) != this)
+    {
+        //
+        // Acquire exclusive lock as WinHTTP callback may happen on different thread
+        // We don't want two threads signal IIS pipeline simultaneously
+        //
+        AcquireLockExclusive();
+        fLocked = TRUE;
+    }
+
+    if (m_fClientDisconnected && (m_RequestStatus != FORWARDER_DONE))
+    {
+        hr = ERROR_CONNECTION_ABORTED;
+        goto Failure;
+    }
+
+    if (m_RequestStatus == FORWARDER_RECEIVED_WEBSOCKET_RESPONSE)
+    {
+#ifdef DEBUG
+        DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO,
+            "FORWARDING_HANDLER::OnAsyncCompletion, Send completed for 101 response");
+#endif
+        //
+        // This should be the write completion of the 101 response.
+        //
+        m_pWebSocket = new WEBSOCKET_HANDLER();
+        if (m_pWebSocket == NULL)
+        {
+            hr = E_OUTOFMEMORY;
+            goto Failure;
+        }
+
+        hr = m_pWebSocket->ProcessRequest(this, m_pW3Context, m_hRequest, &fWebSocketUpgraded);
+        if (fWebSocketUpgraded)
+        {
+            // WinHttp WebSocket handle has been created, bump the counter so that remember to close it
+            // and prevent from premature postcomplation and unexpected callback from winhttp
+            InterlockedIncrement(&m_dwHandlers);
+        }
+
+        if (FAILED(hr))
+        {
+            // This failure could happen when client disconnect happens or backend server fails 
+            // after websocket upgrade
+            goto Failure;
+        }
+
+        //
+        // WebSocket upgrade is successful. Close the WinHttpRequest Handle
+        //
+        m_fHttpHandleInClose = TRUE;
+        fClosed = WinHttpCloseHandle(m_hRequest);
+        DBG_ASSERT(fClosed);
+        m_hRequest = NULL;
+
+        if (!fClosed)
+        {
+            hr = HRESULT_FROM_WIN32(GetLastError());
+            goto Failure;
+        }
+        retVal = RQ_NOTIFICATION_PENDING;
+        goto Finished;
+    }
+
+    //
+    // Begins normal completion handling. There is already an exclusive acquired lock
+    // for protecting the WinHTTP request handle from being closed.
+    //
+    switch (m_RequestStatus)
+    {
+    case FORWARDER_RECEIVING_RESPONSE:
+
+        //
+        // This is a completion of a write (send) to http.sys, abort in case of
+        // failure, if there is more data available from WinHTTP, read it
+        // or else ask if there is more.
+        //
+        if (FAILED(hrCompletionStatus))
+        {
+            hr = hrCompletionStatus;
+            fClientError = TRUE;
+            goto Failure;
+        }
+
+        hr = OnReceivingResponse();
+        if (FAILED(hr))
+        {
+            goto Failure;
+        }
+        break;
+
+    case FORWARDER_SENDING_REQUEST:
+
+        hr = OnSendingRequest(cbCompletion,
+            hrCompletionStatus,
+            &fClientError);
+        if (FAILED(hr))
+        {
+            goto Failure;
+        }
+        break;
+
+    default:
+        DBG_ASSERT(m_RequestStatus == FORWARDER_DONE);
+        if (m_hRequest == NULL && m_pWebSocket == NULL)
+        {
+            // Request must have been done
+            if (!m_fFinishRequest)
+            {
+                goto Failure;
+            }
+
+            if (m_fHasError)
+            {
+                retVal = RQ_NOTIFICATION_FINISH_REQUEST;
+            }
+            else
+            {
+                retVal = RQ_NOTIFICATION_CONTINUE;
+            }
+        }
+        goto Finished;
+    }
+
+    //
+    // Either OnReceivingResponse or OnSendingRequest initiated an
+    // async WinHTTP operation, release this thread meanwhile,
+    // OnWinHttpCompletion method should resume the work by posting an IIS completion.
+    //
+    retVal = RQ_NOTIFICATION_PENDING;
+    goto Finished;
+
+Failure:
+
+    //
+    // Reset status for consistency.
+    //
+    m_RequestStatus = FORWARDER_DONE;
+    if (!m_fHasError)
+    {
+        m_fHasError = TRUE;
+
+        //
+        // Do the right thing based on where the error originated from.
+        //
+        IHttpResponse *pResponse = m_pW3Context->GetResponse();
+        pResponse->DisableKernelCache();
+        pResponse->GetRawHttpResponse()->EntityChunkCount = 0;
+
+        if (fClientError || m_fClientDisconnected)
+        {
+            if (!m_fResponseHeadersReceivedAndSet)
+            {
+                pResponse->SetStatus(400, "Bad Request", 0, HRESULT_FROM_WIN32(WSAECONNRESET));
+            }
+            else
+            {
+                //
+                // Response headers from origin server were
+                // already received and set for the current response.
+                // Honor the response status.
+                //
+            }
+        }
+        else
+        {
+            STACK_STRU(strDescription, 128);
+
+            pResponse->SetStatus(502, "Bad Gateway", 3, hr);
+
+            if (hr > HRESULT_FROM_WIN32(WINHTTP_ERROR_BASE) &&
+                hr <= HRESULT_FROM_WIN32(WINHTTP_ERROR_LAST))
+            {
+#pragma prefast (suppress : __WARNING_FUNCTION_NEEDS_REVIEW, "Function and parameters reviewed.")
+                FormatMessage(
+                    FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_HMODULE,
+                    g_hWinHttpModule,
+                    HRESULT_CODE(hr),
+                    0,
+                    strDescription.QueryStr(),
+                    strDescription.QuerySizeCCH(),
+                    NULL);
+            }
+            else
+            {
+                LoadString(g_hAspNetCoreModule,
+                    IDS_SERVER_ERROR,
+                    strDescription.QueryStr(),
+                    strDescription.QuerySizeCCH());
+            }
+            (VOID)strDescription.SyncWithBuffer();
+
+            if (strDescription.QueryCCH() != 0)
+            {
+                pResponse->SetErrorDescription(
+                    strDescription.QueryStr(),
+                    strDescription.QueryCCH(),
+                    FALSE);
+            }
+
+            if (hr == HRESULT_FROM_WIN32(ERROR_WINHTTP_INVALID_SERVER_RESPONSE))
+            {
+                if (!m_fServerResetConn)
+                {
+                    RemoveRequest();
+                    pResponse->ResetConnection();
+                    m_fServerResetConn = TRUE;
+                }
+            }
+        }
+    }
+
+    if (m_pWebSocket != NULL && !m_fWebSocketHandleInClose)
+    {
+        m_fWebSocketHandleInClose = TRUE;
+        m_pWebSocket->TerminateRequest();
+    }
+
+    if (m_hRequest != NULL && !m_fHttpHandleInClose)
+    {
+        m_fHttpHandleInClose = TRUE;
+        WinHttpCloseHandle(m_hRequest);
+        m_hRequest = NULL;
+    }
+
+Finished:
+
+    if (retVal != RQ_NOTIFICATION_PENDING)
+    {
+
+        DBG_ASSERT(m_dwHandlers == 0);
+        RemoveRequest();
+
+        // This is just a safety guard to prevent from returning non pending status no more once
+        // which should never happen
+        if (!m_fDoneAsyncCompletion)
+        {
+            m_fDoneAsyncCompletion = TRUE;
+        }
+        else
+        {
+            retVal = RQ_NOTIFICATION_PENDING;
+        }
+    }
+
+    if (fLocked)
+    {
+        ReleaseLockExclusive();
+    }
+
+    DereferenceRequestHandler();
+    //
+    // Do not use this object after dereferencing it, it may be gone.
+    //
+#ifdef DEBUG
+    DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO,
+        "FORWARDING_HANDLER::OnAsyncCompletion Done %d", retVal);
+#endif
+    return retVal;
+}
+
+// static
+HRESULT
+FORWARDING_HANDLER::StaticInitialize(
+    BOOL fEnableReferenceCountTracing
+)
+/*++
+
+Routine Description:
+
+Global initialization routine for FORWARDING_HANDLERs
+
+Arguments:
+
+fEnableReferenceCountTracing  - True if ref count tracing should be use.
+
+Return Value:
+
+HRESULT
+
+--*/
+{
+    HRESULT                         hr = S_OK;
+
+    sm_pAlloc = new ALLOC_CACHE_HANDLER;
+    if (sm_pAlloc == NULL)
+    {
+        hr = E_OUTOFMEMORY;
+        goto Finished;
+    }
+
+    hr = sm_pAlloc->Initialize(sizeof(FORWARDING_HANDLER),
+        64); // nThreshold
+    if (FAILED(hr))
+    {
+        goto Finished;
+    }
+
+    sm_pResponseHeaderHash = new RESPONSE_HEADER_HASH;
+    if (sm_pResponseHeaderHash == NULL)
+    {
+        hr = E_OUTOFMEMORY;
+        goto Finished;
+    }
+
+    hr = sm_pResponseHeaderHash->Initialize();
+    if (FAILED(hr))
+    {
+        goto Finished;
+    }
+
+    // Initialize PROTOCOL_CONFIG
+    hr = sm_ProtocolConfig.Initialize();
+    if (FAILED(hr))
+    {
+        goto Finished;
+    }
+
+    if (fEnableReferenceCountTracing)
+    {
+        sm_pTraceLog = CreateRefTraceLog(10000, 0);
+    }
+
+    sm_pStra502ErrorMsg.Copy(
+        "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\"> \
+        <html xmlns=\"http://www.w3.org/1999/xhtml\"> \
+        <head> \
+        <meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\" /> \
+        <title> IIS 502.5 Error </title><style type=\"text/css\"></style></head> \
+        <body> <div id = \"content\"> \
+          <div class = \"content-container\"><h3> HTTP Error 502.5 - Process Failure </h3></div>  \
+          <div class = \"content-container\"> \
+           <fieldset> <h4> Common causes of this issue: </h4> \
+            <ul><li> The application process failed to start </li> \
+             <li> The application process started but then stopped </li> \
+             <li> The application process started but failed to listen on the configured port </li></ul></fieldset> \
+          </div> \
+          <div class = \"content-container\"> \
+            <fieldset><h4> Troubleshooting steps: </h4> \
+             <ul><li> Check the system event log for error messages </li> \
+             <li> Enable logging the application process' stdout messages </li> \
+             <li> Attach a debugger to the application process and inspect </li></ul></fieldset> \
+             <fieldset><h4> For more information visit: \
+             <a href=\"https://go.microsoft.com/fwlink/?linkid=808681\"> <cite> https://go.microsoft.com/fwlink/?LinkID=808681 </cite></a></h4> \
+             </fieldset> \
+          </div> \
+       </div></body></html>");
+
+Finished:
+    if (FAILED(hr))
+    {
+        StaticTerminate();
+    }
+    return hr;
+}
+
+//static
+VOID
+FORWARDING_HANDLER::StaticTerminate()
+{
+    sm_pStra502ErrorMsg.Reset();
+
+    if (sm_pResponseHeaderHash != NULL)
+    {
+        sm_pResponseHeaderHash->Clear();
+        delete sm_pResponseHeaderHash;
+        sm_pResponseHeaderHash = NULL;
+    }
+
+    if (sm_pTraceLog != NULL)
+    {
+        DestroyRefTraceLog(sm_pTraceLog);
+        sm_pTraceLog = NULL;
+    }
+
+    if (sm_pAlloc != NULL)
+    {
+        delete sm_pAlloc;
+        sm_pAlloc = NULL;
+    }
+}
+
+HRESULT
+FORWARDING_HANDLER::GetHeaders(
+    _In_ const PROTOCOL_CONFIG *    pProtocol,
+    _In_    BOOL                    fForwardWindowsAuthToken,
+    _In_    SERVER_PROCESS*         pServerProcess,
+    _Out_   PCWSTR *                ppszHeaders,
+    _Inout_ DWORD *                 pcchHeaders
+)
+{
+    HRESULT hr = S_OK;
+    PCSTR pszCurrentHeader;
+    PCSTR ppHeadersToBeRemoved;
+    PCSTR pszFinalHeader;
+    USHORT cchCurrentHeader;
+    DWORD cchFinalHeader;
+    BOOL  fSecure = FALSE;  // dummy. Used in SplitUrl. Value will not be used 
+                            // as ANCM always use http protocol to communicate with backend  
+    STRU  struDestination;
+    STRU  struUrl;
+    STACK_STRA(strTemp, 64);
+    HTTP_REQUEST_HEADERS *pHeaders;
+    IHttpRequest *pRequest = m_pW3Context->GetRequest();
+    MULTISZA mszMsAspNetCoreHeaders;
+
+    //
+    // We historically set the host section in request url to the new host header
+    // this is wrong but Kestrel has dependency on it.
+    // should change it in the future
+    //
+    if (!pProtocol->QueryPreserveHostHeader())
+    {
+        if (FAILED(hr = UTILITY::SplitUrl(pRequest->GetRawHttpRequest()->CookedUrl.pFullUrl,
+            &fSecure,
+            &struDestination,
+            &struUrl)) ||
+            FAILED(hr = strTemp.CopyW(struDestination.QueryStr())) ||
+            FAILED(hr = pRequest->SetHeader(HttpHeaderHost,
+                strTemp.QueryStr(),
+                static_cast<USHORT>(strTemp.QueryCCH()),
+                TRUE))) // fReplace
+        {
+            return hr;
+        }
+    }
+    //
+    // Strip all headers starting with MS-ASPNETCORE.
+    // These headers are generated by the asp.net core module and 
+    // passed to the process it creates.
+    //
+
+    pHeaders = &m_pW3Context->GetRequest()->GetRawHttpRequest()->Headers;
+    for (DWORD i = 0; i<pHeaders->UnknownHeaderCount; i++)
+    {
+        if (_strnicmp(pHeaders->pUnknownHeaders[i].pName, "MS-ASPNETCORE", 13) == 0)
+        {
+            mszMsAspNetCoreHeaders.Append(pHeaders->pUnknownHeaders[i].pName, (DWORD)pHeaders->pUnknownHeaders[i].NameLength);
+        }
+    }
+
+    ppHeadersToBeRemoved = mszMsAspNetCoreHeaders.First();
+
+    //
+    // iterate the list of headers to be removed and delete them from the request.
+    //
+
+    while (ppHeadersToBeRemoved != NULL)
+    {
+        m_pW3Context->GetRequest()->DeleteHeader(ppHeadersToBeRemoved);
+        ppHeadersToBeRemoved = mszMsAspNetCoreHeaders.Next(ppHeadersToBeRemoved);
+    }
+
+    if (pServerProcess->QueryGuid() != NULL)
+    {
+        hr = m_pW3Context->GetRequest()->SetHeader("MS-ASPNETCORE-TOKEN",
+            pServerProcess->QueryGuid(),
+            (USHORT)strlen(pServerProcess->QueryGuid()),
+            TRUE);
+        if (FAILED(hr))
+        {
+            return hr;
+        }
+    }
+
+    if (fForwardWindowsAuthToken &&
+        (_wcsicmp(m_pW3Context->GetUser()->GetAuthenticationType(), L"negotiate") == 0 ||
+            _wcsicmp(m_pW3Context->GetUser()->GetAuthenticationType(), L"ntlm") == 0))
+    {
+        if (m_pW3Context->GetUser()->GetPrimaryToken() != NULL &&
+            m_pW3Context->GetUser()->GetPrimaryToken() != INVALID_HANDLE_VALUE)
+        {
+            HANDLE hTargetTokenHandle = NULL;
+            hr = pServerProcess->SetWindowsAuthToken(m_pW3Context->GetUser()->GetPrimaryToken(),
+                &hTargetTokenHandle);
+            if (FAILED(hr))
+            {
+                return hr;
+            }
+
+            //
+            // set request header with target token value
+            //
+            CHAR pszHandleStr[16] = { 0 };
+            if (_ui64toa_s((UINT64)hTargetTokenHandle, pszHandleStr, 16, 16) != 0)
+            {
+                hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
+                return hr;
+            }
+
+            hr = m_pW3Context->GetRequest()->SetHeader("MS-ASPNETCORE-WINAUTHTOKEN",
+                pszHandleStr,
+                (USHORT)strlen(pszHandleStr),
+                TRUE);
+            if (FAILED(hr))
+            {
+                return hr;
+            }
+        }
+    }
+
+    if (!pProtocol->QueryXForwardedForName()->IsEmpty())
+    {
+        strTemp.Reset();
+
+        pszCurrentHeader = pRequest->GetHeader(pProtocol->QueryXForwardedForName()->QueryStr(), &cchCurrentHeader);
+        if (pszCurrentHeader != NULL)
+        {
+            if (FAILED(hr = strTemp.Copy(pszCurrentHeader, cchCurrentHeader)) ||
+                FAILED(hr = strTemp.Append(", ", 2)))
+            {
+                return hr;
+            }
+        }
+
+        if (FAILED(hr = m_pW3Context->GetServerVariable("REMOTE_ADDR",
+            &pszFinalHeader,
+            &cchFinalHeader)))
+        {
+            return hr;
+        }
+
+        if (pRequest->GetRawHttpRequest()->Address.pRemoteAddress->sa_family == AF_INET6)
+        {
+            if (FAILED(hr = strTemp.Append("[", 1)) ||
+                FAILED(hr = strTemp.Append(pszFinalHeader, cchFinalHeader)) ||
+                FAILED(hr = strTemp.Append("]", 1)))
+            {
+                return hr;
+            }
+        }
+        else
+        {
+            if (FAILED(hr = strTemp.Append(pszFinalHeader, cchFinalHeader)))
+            {
+                return hr;
+            }
+        }
+
+        if (pProtocol->QueryIncludePortInXForwardedFor())
+        {
+            if (FAILED(hr = m_pW3Context->GetServerVariable("REMOTE_PORT",
+                &pszFinalHeader,
+                &cchFinalHeader)))
+            {
+                return hr;
+            }
+
+            if (FAILED(hr = strTemp.Append(":", 1)) ||
+                FAILED(hr = strTemp.Append(pszFinalHeader, cchFinalHeader)))
+            {
+                return hr;
+            }
+        }
+
+        if (FAILED(hr = pRequest->SetHeader(pProtocol->QueryXForwardedForName()->QueryStr(),
+            strTemp.QueryStr(),
+            static_cast<USHORT>(strTemp.QueryCCH()),
+            TRUE))) // fReplace
+        {
+            return hr;
+        }
+    }
+
+    if (!pProtocol->QuerySslHeaderName()->IsEmpty())
+    {
+        const HTTP_SSL_INFO *pSslInfo = pRequest->GetRawHttpRequest()->pSslInfo;
+        LPSTR pszScheme = "http";
+        if (pSslInfo != NULL)
+        {
+            pszScheme = "https";
+        }
+
+        strTemp.Reset();
+
+        pszCurrentHeader = pRequest->GetHeader(pProtocol->QuerySslHeaderName()->QueryStr(), &cchCurrentHeader);
+        if (pszCurrentHeader != NULL)
+        {
+            if (FAILED(hr = strTemp.Copy(pszCurrentHeader, cchCurrentHeader)) ||
+                FAILED(hr = strTemp.Append(", ", 2)))
+            {
+                return hr;
+            }
+        }
+
+        if (FAILED(hr = strTemp.Append(pszScheme)))
+        {
+            return hr;
+        }
+
+        if (FAILED(pRequest->SetHeader(pProtocol->QuerySslHeaderName()->QueryStr(),
+            strTemp.QueryStr(),
+            (USHORT)strTemp.QueryCCH(),
+            TRUE)))
+        {
+            return hr;
+        }
+    }
+
+    if (!pProtocol->QueryClientCertName()->IsEmpty())
+    {
+        if (pRequest->GetRawHttpRequest()->pSslInfo == NULL ||
+            pRequest->GetRawHttpRequest()->pSslInfo->pClientCertInfo == NULL)
+        {
+            pRequest->DeleteHeader(pProtocol->QueryClientCertName()->QueryStr());
+        }
+        else
+        {
+            // Resize the buffer large enough to hold the encoded certificate info
+            if (FAILED(hr = strTemp.Resize(
+                1 + (pRequest->GetRawHttpRequest()->pSslInfo->pClientCertInfo->CertEncodedSize + 2) / 3 * 4)))
+            {
+                return hr;
+            }
+
+            Base64Encode(
+                pRequest->GetRawHttpRequest()->pSslInfo->pClientCertInfo->pCertEncoded,
+                pRequest->GetRawHttpRequest()->pSslInfo->pClientCertInfo->CertEncodedSize,
+                strTemp.QueryStr(),
+                strTemp.QuerySize(),
+                NULL);
+            strTemp.SyncWithBuffer();
+
+            if (FAILED(hr = pRequest->SetHeader(
+                pProtocol->QueryClientCertName()->QueryStr(),
+                strTemp.QueryStr(),
+                static_cast<USHORT>(strTemp.QueryCCH()),
+                TRUE))) // fReplace
+            {
+                return hr;
+            }
+        }
+    }
+
+    //
+    // Remove the connection header
+    //
+    if (!m_fWebSocketEnabled)
+    {
+        pRequest->DeleteHeader(HttpHeaderConnection);
+    }
+
+    //
+    // Get all the headers to send to the client
+    //
+    hr = m_pW3Context->GetServerVariable("ALL_RAW",
+        ppszHeaders,
+        pcchHeaders);
+    if (FAILED(hr))
+    {
+        return hr;
+    }
+
+    return S_OK;
+}
+
+HRESULT
+FORWARDING_HANDLER::CreateWinHttpRequest(
+    _In_ const IHttpRequest *       pRequest,
+    _In_ const PROTOCOL_CONFIG *    pProtocol,
+    _In_ HINTERNET                  hConnect,
+    _Inout_ STRU *                  pstrUrl,
+    _In_ SERVER_PROCESS*            pServerProcess
+)
+{
+    HRESULT         hr = S_OK;
+    PCWSTR          pszVersion = NULL;
+    PCSTR           pszVerb;
+    STACK_STRU(strVerb, 32);
+
+    //
+    // Create the request handle for this request (leave some fields blank,
+    // we will fill them when sending the request)
+    //
+    pszVerb = pRequest->GetHttpMethod();
+    if (FAILED(hr = strVerb.CopyA(pszVerb)))
+    {
+        goto Finished;
+    }
+
+    //pszVersion = pProtocol->QueryVersion();
+    if (pszVersion == NULL)
+    {
+        DWORD cchUnused;
+        hr = m_pW3Context->GetServerVariable(
+            "HTTP_VERSION",
+            &pszVersion,
+            &cchUnused);
+        if (FAILED(hr))
+        {
+            goto Finished;
+        }
+    }
+
+    m_hRequest = WinHttpOpenRequest(hConnect,
+        strVerb.QueryStr(),
+        pstrUrl->QueryStr(),
+        pszVersion,
+        WINHTTP_NO_REFERER,
+        WINHTTP_DEFAULT_ACCEPT_TYPES,
+        WINHTTP_FLAG_ESCAPE_DISABLE_QUERY
+        | g_OptionalWinHttpFlags);
+    if (m_hRequest == NULL)
+    {
+        hr = HRESULT_FROM_WIN32(GetLastError());
+        goto Finished;
+    }
+
+    if (!WinHttpSetTimeouts(m_hRequest,
+        pProtocol->QueryTimeout(),
+        pProtocol->QueryTimeout(),
+        pProtocol->QueryTimeout(),
+        pProtocol->QueryTimeout()))
+    {
+        hr = HRESULT_FROM_WIN32(GetLastError());
+        goto Finished;
+    }
+
+    DWORD dwResponseBufferLimit = pProtocol->QueryResponseBufferLimit();
+    if (!WinHttpSetOption(m_hRequest,
+        WINHTTP_OPTION_MAX_RESPONSE_DRAIN_SIZE,
+        &dwResponseBufferLimit,
+        sizeof(dwResponseBufferLimit)))
+    {
+        hr = HRESULT_FROM_WIN32(GetLastError());
+        goto Finished;
+    }
+
+    DWORD dwMaxHeaderSize = pProtocol->QueryMaxResponseHeaderSize();
+    if (!WinHttpSetOption(m_hRequest,
+        WINHTTP_OPTION_MAX_RESPONSE_HEADER_SIZE,
+        &dwMaxHeaderSize,
+        sizeof(dwMaxHeaderSize)))
+    {
+        hr = HRESULT_FROM_WIN32(GetLastError());
+        goto Finished;
+    }
+
+    DWORD dwOption = WINHTTP_DISABLE_COOKIES;
+
+    dwOption |= WINHTTP_DISABLE_AUTHENTICATION;
+
+    if (!pProtocol->QueryDoKeepAlive())
+    {
+        dwOption |= WINHTTP_DISABLE_KEEP_ALIVE;
+    }
+    if (!WinHttpSetOption(m_hRequest,
+        WINHTTP_OPTION_DISABLE_FEATURE,
+        &dwOption,
+        sizeof(dwOption)))
+    {
+        hr = HRESULT_FROM_WIN32(GetLastError());
+        goto Finished;
+    }
+
+    if (WinHttpSetStatusCallback(m_hRequest,
+        FORWARDING_HANDLER::OnWinHttpCompletion,
+        (WINHTTP_CALLBACK_FLAG_ALL_COMPLETIONS |
+            WINHTTP_CALLBACK_FLAG_HANDLES |
+            WINHTTP_CALLBACK_STATUS_SENDING_REQUEST),
+        NULL) == WINHTTP_INVALID_STATUS_CALLBACK)
+    {
+        hr = HRESULT_FROM_WIN32(GetLastError());
+        goto Finished;
+    }
+
+    hr = GetHeaders(pProtocol,
+                    m_pApplication->QueryConfig()->QueryForwardWindowsAuthToken(),
+                    pServerProcess,
+                   &m_pszHeaders,
+                   &m_cchHeaders);
+    if (FAILED(hr))
+    {
+        goto Finished;
+    }
+
+Finished:
+
+    return hr;
+}
+
+VOID
+FORWARDING_HANDLER::OnWinHttpCompletion(
+    HINTERNET   hRequest,
+    DWORD_PTR   dwContext,
+    DWORD       dwInternetStatus,
+    LPVOID      lpvStatusInformation,
+    DWORD       dwStatusInformationLength
+)
+{
+    FORWARDING_HANDLER * pThis = static_cast<FORWARDING_HANDLER *>(reinterpret_cast<PVOID>(dwContext));
+    if (pThis == NULL)
+    {
+        //error happened, nothing can be done here
+        return;
+    }
+    DBG_ASSERT(pThis->m_Signature == FORWARDING_HANDLER_SIGNATURE);
+    pThis->OnWinHttpCompletionInternal(hRequest,
+        dwInternetStatus,
+        lpvStatusInformation,
+        dwStatusInformationLength);
+}
+
+VOID
+FORWARDING_HANDLER::OnWinHttpCompletionInternal(
+    _In_ HINTERNET   hRequest,
+    _In_ DWORD       dwInternetStatus,
+    _In_ LPVOID      lpvStatusInformation,
+    _In_ DWORD       dwStatusInformationLength
+)
+/*++
+
+Routine Description:
+
+Completion call associated with a WinHTTP operation
+
+Arguments:
+
+hRequest - The winhttp request handle associated with this completion
+dwInternetStatus - enum specifying what the completion is for
+lpvStatusInformation - completion specific information
+dwStatusInformationLength - length of the above information
+
+Return Value:
+
+None
+
+--*/
+{
+    HRESULT hr = S_OK;
+    BOOL fExclusiveLocked = FALSE;
+    BOOL fSharedLocked = FALSE;
+    BOOL fClientError = FALSE;
+    BOOL fAnotherCompletionExpected = FALSE;
+    BOOL fDoPostCompletion = FALSE;
+    BOOL fHandleClosing = (dwInternetStatus == WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING);
+    DWORD dwHandlers = 1; // defaullt for http handler
+
+
+    DBG_ASSERT(m_pW3Context != NULL);
+    __analysis_assume(m_pW3Context != NULL);
+    IHttpResponse * pResponse = m_pW3Context->GetResponse();
+
+    // Reference the request handler to prevent it from being released prematurely
+    ReferenceRequestHandler();
+
+    UNREFERENCED_PARAMETER(dwStatusInformationLength);
+
+    if (sm_pTraceLog != NULL)
+    {
+        WriteRefTraceLogEx(sm_pTraceLog,
+            m_cRefs,
+            this,
+            "FORWARDING_HANDLER::OnWinHttpCompletionInternal Enter",
+            reinterpret_cast<PVOID>(static_cast<DWORD_PTR>(dwInternetStatus)),
+            NULL);
+    }
+
+    //FREB log
+    if (ANCMEvents::ANCM_WINHTTP_CALLBACK::IsEnabled(m_pW3Context->GetTraceContext()))
+    {
+        ANCMEvents::ANCM_WINHTTP_CALLBACK::RaiseEvent(
+            m_pW3Context->GetTraceContext(),
+            NULL,
+            dwInternetStatus);
+    }
+
+#ifdef DEBUG
+    DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO,
+        "FORWARDING_HANDLER::OnWinHttpCompletionInternal %x -- %d --%p\n", dwInternetStatus, GetCurrentThreadId(), m_pW3Context);
+#endif
+    //
+    // Exclusive lock on the winhttp handle to protect from a client disconnect/
+    // server stop closing the handle while we are using it.
+    //
+    // WinHttp can call async completion on the same thread/stack, so
+    // we have to account for that and not try to take the lock again,
+    // otherwise, we could end up in a deadlock.
+    //
+
+    if (TlsGetValue(g_dwTlsIndex) != this)
+    {
+        DBG_ASSERT(TlsGetValue(g_dwTlsIndex) == NULL);
+        if (m_RequestStatus != FORWARDER_RECEIVED_WEBSOCKET_RESPONSE)
+        {
+            // Webscoket has already been guarded by critical section
+            // Only require exclisive lock for non-websocket scenario which has duplex channel
+            // Otherwise, there will be a deadlock
+            AcquireLockExclusive();
+            fExclusiveLocked = TRUE;
+        }
+        else
+        {
+            AcquireSRWLockShared(&m_RequestLock);
+            TlsSetValue(g_dwTlsIndex, this);
+            fSharedLocked = TRUE;
+            DBG_ASSERT(TlsGetValue(g_dwTlsIndex) == this);
+        }
+    }
+
+    if (fHandleClosing)
+    {
+        dwHandlers = InterlockedDecrement(&m_dwHandlers);
+    }
+
+    if (m_fFinishRequest)
+    {
+        // Request was done by another thread, skip
+        goto Finished;
+    }
+
+
+    if (m_fClientDisconnected && (m_RequestStatus != FORWARDER_DONE))
+    {
+        hr = ERROR_CONNECTION_ABORTED;
+        goto Failure;
+    }
+
+    //
+    // In case of websocket, http request handle (m_hRequest) will be closed immediately after upgrading success
+    // This close will trigger a callback with WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING
+    // As m_RequestStatus is FORWARDER_RECEIVED_WEBSOCKET_RESPONSE, this callback will be skipped.
+    // When WebSocket handle (m_pWebsocket) gets closed, another winhttp handle close callback will be triggered
+    // This callback will be captured and then notify IIS pipeline to continue
+    // This ensures no request leaks
+    //
+    if (m_RequestStatus == FORWARDER_RECEIVED_WEBSOCKET_RESPONSE)
+    {
+        fAnotherCompletionExpected = TRUE;
+        if (m_pWebSocket == NULL)
+        {
+            goto Finished;
+        }
+
+        switch (dwInternetStatus)
+        {
+        case WINHTTP_CALLBACK_STATUS_SHUTDOWN_COMPLETE:
+            m_pWebSocket->OnWinHttpShutdownComplete();
+            break;
+
+        case WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE:
+            m_pWebSocket->OnWinHttpSendComplete(
+                (WINHTTP_WEB_SOCKET_STATUS*)lpvStatusInformation
+            );
+            break;
+
+        case WINHTTP_CALLBACK_STATUS_READ_COMPLETE:
+            m_pWebSocket->OnWinHttpReceiveComplete(
+                (WINHTTP_WEB_SOCKET_STATUS*)lpvStatusInformation
+            );
+            break;
+
+        case WINHTTP_CALLBACK_STATUS_REQUEST_ERROR:
+            m_pWebSocket->OnWinHttpIoError(
+                (WINHTTP_WEB_SOCKET_ASYNC_RESULT*)lpvStatusInformation
+            );
+            break;
+        }
+        goto Finished;
+    }
+
+    switch (dwInternetStatus)
+    {
+    case WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE:
+    case WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE:
+        hr = OnWinHttpCompletionSendRequestOrWriteComplete(hRequest,
+            dwInternetStatus,
+            &fClientError,
+            &fAnotherCompletionExpected);
+        break;
+
+    case WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE:
+        hr = OnWinHttpCompletionStatusHeadersAvailable(hRequest,
+            &fAnotherCompletionExpected);
+        break;
+
+    case WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE:
+        hr = OnWinHttpCompletionStatusDataAvailable(hRequest,
+            *reinterpret_cast<const DWORD *>(lpvStatusInformation), // dwBytes
+            &fAnotherCompletionExpected);
+        break;
+
+    case WINHTTP_CALLBACK_STATUS_READ_COMPLETE:
+        hr = OnWinHttpCompletionStatusReadComplete(pResponse,
+            dwStatusInformationLength,
+            &fAnotherCompletionExpected);
+        break;
+
+    case WINHTTP_CALLBACK_STATUS_REQUEST_ERROR:
+        hr = HRESULT_FROM_WIN32(static_cast<const WINHTTP_ASYNC_RESULT *>(lpvStatusInformation)->dwError);
+        break;
+
+    case WINHTTP_CALLBACK_STATUS_SENDING_REQUEST:
+        //
+        // This is a notification, not a completion.  This notifiation happens
+        // during the Send Request operation.
+        //
+        fAnotherCompletionExpected = TRUE;
+        break;
+
+    case WINHTTP_CALLBACK_STATUS_REQUEST_SENT:
+        //
+        // Need to ignore this event.  We get it as a side-effect of registering
+        // for WINHTTP_CALLBACK_STATUS_SENDING_REQUEST (which we actually need).
+        //
+        hr = S_OK;
+        fAnotherCompletionExpected = TRUE;
+        break;
+
+    case WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING:
+        if (ANCMEvents::ANCM_REQUEST_FORWARD_END::IsEnabled(m_pW3Context->GetTraceContext()))
+        {
+            ANCMEvents::ANCM_REQUEST_FORWARD_END::RaiseEvent(
+                m_pW3Context->GetTraceContext(),
+                NULL);
+        }
+        if (m_RequestStatus != FORWARDER_DONE)
+        {
+            hr = ERROR_CONNECTION_ABORTED;
+            fClientError = m_fClientDisconnected;
+        }
+        m_hRequest = NULL;
+        fAnotherCompletionExpected = FALSE;
+        break;
+
+    case WINHTTP_CALLBACK_STATUS_CONNECTION_CLOSED:
+        hr = ERROR_CONNECTION_ABORTED;
+        break;
+
+    default:
+        //
+        // E_UNEXPECTED is rarely used, if seen means that this condition may been occurred.
+        //
+        DBG_ASSERT(FALSE);
+        hr = E_UNEXPECTED;
+        if (sm_pTraceLog != NULL)
+        {
+            WriteRefTraceLogEx(sm_pTraceLog,
+                m_cRefs,
+                this,
+                "FORWARDING_HANDLER::OnWinHttpCompletionInternal Unexpected WinHTTP Status",
+                reinterpret_cast<PVOID>(static_cast<DWORD_PTR>(dwInternetStatus)),
+                NULL);
+        }
+        break;
+    }
+
+    //
+    // Handle failure code for switch statement above.
+    //
+    if (FAILED(hr))
+    {
+        goto Failure;
+    }
+
+    //
+    // WinHTTP completion handled successfully.
+    //
+    goto Finished;
+
+Failure:
+
+    if (!m_fHasError)
+    {
+        m_RequestStatus = FORWARDER_DONE;
+        m_fHasError = TRUE;
+
+        pResponse->DisableKernelCache();
+        pResponse->GetRawHttpResponse()->EntityChunkCount = 0;
+
+        if (hr == HRESULT_FROM_WIN32(ERROR_WINHTTP_INVALID_SERVER_RESPONSE))
+        {
+            m_fResetConnection = TRUE;
+        }
+
+        if (fClientError || m_fClientDisconnected)
+        {
+            if (!m_fResponseHeadersReceivedAndSet)
+            {
+                pResponse->SetStatus(400, "Bad Request", 0, HRESULT_FROM_WIN32(WSAECONNRESET));
+            }
+            else
+            {
+                //
+                // Response headers from origin server were
+                // already received and set for the current response.
+                // Honor the response status.
+                //
+            }
+        }
+        else
+        {
+            STACK_STRU(strDescription, 128);
+
+            pResponse->SetStatus(502, "Bad Gateway", 3, hr);
+
+            if (!(hr > HRESULT_FROM_WIN32(WINHTTP_ERROR_BASE) &&
+                hr <= HRESULT_FROM_WIN32(WINHTTP_ERROR_LAST)) ||
+#pragma prefast (suppress : __WARNING_FUNCTION_NEEDS_REVIEW, "Function and parameters reviewed.")
+                FormatMessage(
+                    FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_HMODULE,
+                    g_hWinHttpModule,
+                    HRESULT_CODE(hr),
+                    0,
+                    strDescription.QueryStr(),
+                    strDescription.QuerySizeCCH(),
+                    NULL) == 0)
+            {
+                LoadString(g_hAspNetCoreModule,
+                    IDS_SERVER_ERROR,
+                    strDescription.QueryStr(),
+                    strDescription.QuerySizeCCH());
+            }
+
+            strDescription.SyncWithBuffer();
+            if (strDescription.QueryCCH() != 0)
+            {
+                pResponse->SetErrorDescription(
+                    strDescription.QueryStr(),
+                    strDescription.QueryCCH(),
+                    FALSE);
+            }
+        }
+    }
+
+    // FREB log
+    if (ANCMEvents::ANCM_REQUEST_FORWARD_FAIL::IsEnabled(m_pW3Context->GetTraceContext()))
+    {
+        ANCMEvents::ANCM_REQUEST_FORWARD_FAIL::RaiseEvent(
+            m_pW3Context->GetTraceContext(),
+            NULL,
+            hr);
+    }
+
+Finished:
+    //
+    // Since we use TLS to guard WinHttp operation, call PostCompletion instead of
+    // IndicateCompletion to allow cleaning up the TLS before thread reuse.
+    // Never post after the request has been finished for whatever reason
+    //
+    // Only postCompletion after all WinHttp handles (http and websocket) got closed,
+    // i.e., received WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING callback for both handles
+    // So that no further WinHttp callback will be called
+    // Never post completion again after that
+    // Otherwise, there will be a AV as the request already passed IIS pipeline
+    //
+    if (fHandleClosing && dwHandlers == 0)
+    {
+        //
+        // Happy path
+        //
+        // Marked the request is finished, no more PostCompletion is allowed
+        RemoveRequest();
+        m_fFinishRequest = TRUE;
+        fDoPostCompletion = TRUE;
+        if (m_pWebSocket != NULL)
+        {
+            m_pWebSocket->Terminate();
+            m_pWebSocket = NULL;
+        }
+    }
+    else if (m_RequestStatus == FORWARDER_DONE)
+    {
+        //
+        // Error path
+        //
+        RemoveRequest();
+        if (m_hRequest != NULL && !m_fHttpHandleInClose)
+        {
+            m_fHttpHandleInClose = TRUE;
+            WinHttpCloseHandle(m_hRequest);
+            m_hRequest = NULL;
+        }
+
+        if (m_pWebSocket != NULL && !m_fWebSocketHandleInClose)
+        {
+            m_fWebSocketHandleInClose = TRUE;
+            m_pWebSocket->TerminateRequest();
+        }
+
+        if (fHandleClosing)
+        {
+            fDoPostCompletion = dwHandlers == 0;
+            m_fFinishRequest = fDoPostCompletion;
+        }
+    }
+    else if (!fAnotherCompletionExpected)
+    {
+        //
+        // Regular async IO operation
+        //
+        fDoPostCompletion = !m_fFinishRequest;
+    }
+
+    //
+    // No code should access IIS m_pW3Context after posting the completion.
+    //
+    if (fDoPostCompletion)
+    {
+        m_pW3Context->PostCompletion(0);
+    }
+
+    if (fExclusiveLocked)
+    {
+        ReleaseLockExclusive();
+    }
+    else if (fSharedLocked)
+    {
+        DBG_ASSERT(TlsGetValue(g_dwTlsIndex) == this);
+        TlsSetValue(g_dwTlsIndex, NULL);
+        ReleaseSRWLockShared(&m_RequestLock);
+        DBG_ASSERT(TlsGetValue(g_dwTlsIndex) == NULL);
+    }
+
+    DereferenceRequestHandler();
+
+}
+
+HRESULT
+FORWARDING_HANDLER::OnWinHttpCompletionSendRequestOrWriteComplete(
+    HINTERNET                   hRequest,
+    DWORD,
+    __out BOOL *                pfClientError,
+    __out BOOL *                pfAnotherCompletionExpected
+)
+{
+    HRESULT hr = S_OK;
+    IHttpRequest *      pRequest = m_pW3Context->GetRequest();
+
+    //
+    // completion for sending the initial request or request entity to
+    // winhttp, get more request entity if available, else start receiving
+    // the response
+    //
+    if (m_BytesToReceive > 0)
+    {
+        if (m_pEntityBuffer == NULL)
+        {
+            m_pEntityBuffer = GetNewResponseBuffer(
+                ENTITY_BUFFER_SIZE);
+            if (m_pEntityBuffer == NULL)
+            {
+                hr = E_OUTOFMEMORY;
+                goto Finished;
+            }
+        }
+
+        if (sm_pTraceLog != NULL)
+        {
+            WriteRefTraceLogEx(sm_pTraceLog,
+                m_cRefs,
+                this,
+                "Calling ReadEntityBody",
+                NULL,
+                NULL);
+        }
+        hr = pRequest->ReadEntityBody(
+            m_pEntityBuffer + 6,
+            min(m_BytesToReceive, BUFFER_SIZE),
+            TRUE,       // fAsync
+            NULL,       // pcbBytesReceived
+            NULL);      // pfCompletionPending
+        if (hr == HRESULT_FROM_WIN32(ERROR_HANDLE_EOF))
+        {
+            DBG_ASSERT(m_BytesToReceive == 0 ||
+                m_BytesToReceive == INFINITE);
+
+            //
+            // ERROR_HANDLE_EOF is not an error.
+            //
+            hr = S_OK;
+
+            if (m_BytesToReceive == INFINITE)
+            {
+                m_BytesToReceive = 0;
+                m_cchLastSend = 5;
+
+                //
+                // WinHttpWriteData can operate asynchronously.
+                //
+                // Take reference so that object does not go away as a result of
+                // async completion.
+                //
+                //ReferenceForwardingHandler();
+                if (!WinHttpWriteData(m_hRequest,
+                    "0\r\n\r\n",
+                    5,
+                    NULL))
+                {
+                    hr = HRESULT_FROM_WIN32(GetLastError());
+                    //DereferenceForwardingHandler();
+                    goto Finished;
+                }
+                *pfAnotherCompletionExpected = TRUE;
+
+                goto Finished;
+            }
+        }
+        else if (FAILED(hr))
+        {
+            *pfClientError = TRUE;
+            goto Finished;
+        }
+        else
+        {
+            //
+            // ReadEntityBody will post a completion to IIS.
+            //
+            *pfAnotherCompletionExpected = TRUE;
+
+            goto Finished;
+        }
+    }
+
+    m_RequestStatus = FORWARDER_RECEIVING_RESPONSE;
+
+    if (!WinHttpReceiveResponse(hRequest, NULL))
+    {
+        hr = HRESULT_FROM_WIN32(GetLastError());
+        goto Finished;
+    }
+    *pfAnotherCompletionExpected = TRUE;
+
+Finished:
+
+    return hr;
+}
+
+HRESULT
+FORWARDING_HANDLER::OnWinHttpCompletionStatusHeadersAvailable(
+    HINTERNET                   hRequest,
+    __out BOOL *                pfAnotherCompletionExpected
+)
+{
+    HRESULT       hr = S_OK;
+    STACK_BUFFER(bufHeaderBuffer, 2048);
+    STACK_STRA(strHeaders, 2048);
+    DWORD         dwHeaderSize = bufHeaderBuffer.QuerySize();
+
+    UNREFERENCED_PARAMETER(pfAnotherCompletionExpected);
+
+    //
+    // Headers are available, read the status line and headers and pass
+    // them on to the client
+    //
+    // WinHttpQueryHeaders operates synchronously,
+    // no need for taking reference.
+    //
+    dwHeaderSize = bufHeaderBuffer.QuerySize();
+    if (!WinHttpQueryHeaders(hRequest,
+        WINHTTP_QUERY_RAW_HEADERS_CRLF,
+        WINHTTP_HEADER_NAME_BY_INDEX,
+        bufHeaderBuffer.QueryPtr(),
+        &dwHeaderSize,
+        WINHTTP_NO_HEADER_INDEX))
+    {
+        if (!bufHeaderBuffer.Resize(dwHeaderSize))
+        {
+            hr = E_OUTOFMEMORY;
+            goto Finished;
+        }
+
+        //
+        // WinHttpQueryHeaders operates synchronously,
+        // no need for taking reference.
+        //
+        if (!WinHttpQueryHeaders(hRequest,
+            WINHTTP_QUERY_RAW_HEADERS_CRLF,
+            WINHTTP_HEADER_NAME_BY_INDEX,
+            bufHeaderBuffer.QueryPtr(),
+            &dwHeaderSize,
+            WINHTTP_NO_HEADER_INDEX))
+        {
+            hr = HRESULT_FROM_WIN32(GetLastError());
+            goto Finished;
+        }
+    }
+
+    if (FAILED(hr = strHeaders.CopyW(
+        reinterpret_cast<PWSTR>(bufHeaderBuffer.QueryPtr()))))
+    {
+        goto Finished;
+    }
+
+    // Issue: The reason we add trailing \r\n is to eliminate issues that have been observed
+    // in some configurations where status and headers would not have final \r\n nor \r\n\r\n
+    // (last header was null terminated).That caused crash within header parsing code that expected valid
+    // format. Parsing code was fized to return ERROR_INVALID_PARAMETER, but we still should make
+    // Example of a status+header string that was causing problems (note the missing \r\n at the end)
+    // HTTP/1.1 302 Moved Permanently\r\n....\r\nLocation:http://site\0
+    //
+
+    if (!strHeaders.IsEmpty() && strHeaders.QueryStr()[strHeaders.QueryCCH() - 1] != '\n')
+    {
+        hr = strHeaders.Append("\r\n");
+        if (FAILED(hr))
+        {
+            goto Finished;
+        }
+    }
+
+    if (FAILED(hr = SetStatusAndHeaders(
+        strHeaders.QueryStr(),
+        strHeaders.QueryCCH())))
+    {
+        goto Finished;
+    }
+
+    FreeResponseBuffers();
+
+    //
+    // If the request was websocket, and response was 101,
+    // trigger a flush, so that IIS's websocket module
+    // can get a chance to initialize and complete the handshake.
+    //
+
+    if (m_fWebSocketEnabled)
+    {
+        m_RequestStatus = FORWARDER_RECEIVED_WEBSOCKET_RESPONSE;
+
+        hr = m_pW3Context->GetResponse()->Flush(
+            TRUE,
+            TRUE,
+            NULL,
+            NULL);
+
+        if (FAILED(hr))
+        {
+            *pfAnotherCompletionExpected = FALSE;
+        }
+        else
+        {
+            *pfAnotherCompletionExpected = TRUE;
+        }
+    }
+
+Finished:
+
+    return hr;
+}
+
+HRESULT
+FORWARDING_HANDLER::OnWinHttpCompletionStatusDataAvailable(
+    HINTERNET                   hRequest,
+    DWORD                       dwBytes,
+    _Out_ BOOL *                pfAnotherCompletionExpected
+)
+{
+    HRESULT hr = S_OK;
+
+    //
+    // Response data is available from winhttp, read it
+    //
+    if (dwBytes == 0)
+    {
+        if (m_cContentLength != 0)
+        {
+            hr = HRESULT_FROM_WIN32(ERROR_WINHTTP_INVALID_SERVER_RESPONSE);
+            goto Finished;
+        }
+
+        m_RequestStatus = FORWARDER_DONE;
+
+        goto Finished;
+    }
+
+    m_BytesToSend = dwBytes;
+    if (m_cContentLength != 0)
+    {
+        m_cContentLength -= dwBytes;
+    }
+
+    m_pEntityBuffer = GetNewResponseBuffer(
+        min(m_BytesToSend, BUFFER_SIZE));
+    if (m_pEntityBuffer == NULL)
+    {
+        hr = E_OUTOFMEMORY;
+        goto Finished;
+    }
+
+    //
+    // WinHttpReadData can operate asynchronously.
+    //
+    // Take reference so that object does not go away as a result of
+    // async completion.
+    //
+    //ReferenceForwardingHandler();
+    if (!WinHttpReadData(hRequest,
+        m_pEntityBuffer,
+        min(m_BytesToSend, BUFFER_SIZE),
+        NULL))
+    {
+        hr = HRESULT_FROM_WIN32(GetLastError());
+        //DereferenceForwardingHandler();
+        goto Finished;
+    }
+    *pfAnotherCompletionExpected = TRUE;
+
+Finished:
+
+    return hr;
+}
+
+HRESULT
+FORWARDING_HANDLER::OnWinHttpCompletionStatusReadComplete(
+    __in IHttpResponse *        pResponse,
+    DWORD                       dwStatusInformationLength,
+    __out BOOL *                pfAnotherCompletionExpected
+)
+{
+    HRESULT hr = S_OK;
+
+    //
+    // Response data has been read from winhttp, send it to the client
+    //
+    m_BytesToSend -= dwStatusInformationLength;
+
+    if (m_cMinBufferLimit >= BUFFER_SIZE / 2)
+    {
+        if (m_cContentLength != 0)
+        {
+            m_cContentLength -= dwStatusInformationLength;
+        }
+
+        //
+        // If we were not using WinHttpQueryDataAvailable and winhttp
+        // did not fill our buffer, we must have reached the end of the
+        // response
+        //
+        if (dwStatusInformationLength == 0 ||
+            m_BytesToSend != 0)
+        {
+            if (m_cContentLength != 0)
+            {
+                hr = HRESULT_FROM_WIN32(ERROR_WINHTTP_INVALID_SERVER_RESPONSE);
+                goto Finished;
+            }
+
+            m_RequestStatus = FORWARDER_DONE;
+        }
+    }
+    else
+    {
+        DBG_ASSERT(dwStatusInformationLength != 0);
+    }
+
+    if (dwStatusInformationLength == 0)
+    {
+        goto Finished;
+    }
+    else
+    {
+        m_cBytesBuffered += dwStatusInformationLength;
+
+        HTTP_DATA_CHUNK Chunk;
+        Chunk.DataChunkType = HttpDataChunkFromMemory;
+        Chunk.FromMemory.pBuffer = m_pEntityBuffer;
+        Chunk.FromMemory.BufferLength = dwStatusInformationLength;
+        if (FAILED(hr = pResponse->WriteEntityChunkByReference(&Chunk)))
+        {
+            goto Finished;
+        }
+    }
+
+    if (m_cBytesBuffered >= m_cMinBufferLimit)
+    {
+        //
+        // Always post a completion to resume the WinHTTP data pump.
+        //
+        hr = pResponse->Flush(TRUE,     // fAsync
+            TRUE,     // fMoreData
+            NULL);    // pcbSent    
+        if (FAILED(hr))
+        {
+            goto Finished;
+        }
+        *pfAnotherCompletionExpected = TRUE;
+    }
+    else
+    {
+        *pfAnotherCompletionExpected = FALSE;
+    }
+
+Finished:
+
+    return hr;
+}
+
+HRESULT
+FORWARDING_HANDLER::OnSendingRequest(
+    DWORD                       cbCompletion,
+    HRESULT                     hrCompletionStatus,
+    __out BOOL *                pfClientError
+)
+{
+    HRESULT hr = S_OK;
+    //
+    // This is a completion for a read from http.sys, abort in case
+    // of failure, if we read anything write it out over WinHTTP,
+    // but we have already reached EOF, now read the response
+    //
+    if (hrCompletionStatus == HRESULT_FROM_WIN32(ERROR_HANDLE_EOF))
+    {
+        DBG_ASSERT(m_BytesToReceive == 0 || m_BytesToReceive == INFINITE);
+        if (m_BytesToReceive == INFINITE)
+        {
+            m_BytesToReceive = 0;
+            m_cchLastSend = 5; // "0\r\n\r\n"
+
+            if (!WinHttpWriteData(m_hRequest,
+                "0\r\n\r\n",
+                5,
+                NULL))
+            {
+                hr = HRESULT_FROM_WIN32(GetLastError());
+                goto Failure;
+            }
+        }
+        else
+        {
+            m_RequestStatus = FORWARDER_RECEIVING_RESPONSE;
+
+            if (!WinHttpReceiveResponse(m_hRequest, NULL))
+            {
+                hr = HRESULT_FROM_WIN32(GetLastError());
+                goto Failure;
+            }
+        }
+    }
+    else if (SUCCEEDED(hrCompletionStatus))
+    {
+        DWORD cbOffset;
+
+        if (m_BytesToReceive != INFINITE)
+        {
+            m_BytesToReceive -= cbCompletion;
+            cbOffset = 6;
+        }
+        else
+        {
+            //
+            // For chunk-encoded requests, need to re-chunk the entity body
+            // Add the CRLF just before and after the chunk data
+            //
+            m_pEntityBuffer[4] = '\r';
+            m_pEntityBuffer[5] = '\n';
+
+            m_pEntityBuffer[cbCompletion + 6] = '\r';
+            m_pEntityBuffer[cbCompletion + 7] = '\n';
+
+            if (cbCompletion < 0x10)
+            {
+                cbOffset = 3;
+                m_pEntityBuffer[3] = HEX_TO_ASCII(cbCompletion);
+                cbCompletion += 5;
+            }
+            else if (cbCompletion < 0x100)
+            {
+                cbOffset = 2;
+                m_pEntityBuffer[2] = HEX_TO_ASCII(cbCompletion >> 4);
+                m_pEntityBuffer[3] = HEX_TO_ASCII(cbCompletion & 0xf);
+                cbCompletion += 6;
+            }
+            else if (cbCompletion < 0x1000)
+            {
+                cbOffset = 1;
+                m_pEntityBuffer[1] = HEX_TO_ASCII(cbCompletion >> 8);
+                m_pEntityBuffer[2] = HEX_TO_ASCII((cbCompletion >> 4) & 0xf);
+                m_pEntityBuffer[3] = HEX_TO_ASCII(cbCompletion & 0xf);
+                cbCompletion += 7;
+            }
+            else
+            {
+                DBG_ASSERT(cbCompletion < 0x10000);
+
+                cbOffset = 0;
+                m_pEntityBuffer[0] = HEX_TO_ASCII(cbCompletion >> 12);
+                m_pEntityBuffer[1] = HEX_TO_ASCII((cbCompletion >> 8) & 0xf);
+                m_pEntityBuffer[2] = HEX_TO_ASCII((cbCompletion >> 4) & 0xf);
+                m_pEntityBuffer[3] = HEX_TO_ASCII(cbCompletion & 0xf);
+                cbCompletion += 8;
+            }
+        }
+        m_cchLastSend = cbCompletion;
+
+        if (!WinHttpWriteData(m_hRequest,
+            m_pEntityBuffer + cbOffset,
+            cbCompletion,
+            NULL))
+        {
+            hr = HRESULT_FROM_WIN32(GetLastError());
+            goto Failure;
+        }
+    }
+    else
+    {
+        hr = hrCompletionStatus;
+        *pfClientError = TRUE;
+        goto Failure;
+    }
+
+Failure:
+
+    return hr;
+}
+
+HRESULT
+FORWARDING_HANDLER::OnReceivingResponse(
+)
+{
+    HRESULT hr = S_OK;
+
+    if (m_cBytesBuffered >= m_cMinBufferLimit)
+    {
+        FreeResponseBuffers();
+    }
+
+    if (m_BytesToSend == 0)
+    {
+        //
+        // If response buffering is enabled, try to read large chunks
+        // at a time - also treat very small buffering limit as no
+        // buffering
+        //
+        m_BytesToSend = min(m_cMinBufferLimit, BUFFER_SIZE);
+        if (m_BytesToSend < BUFFER_SIZE / 2)
+        {
+            //
+            // Disable buffering.
+            //
+            m_BytesToSend = 0;
+        }
+    }
+
+    if (m_BytesToSend == 0)
+    {
+        //
+        // No buffering enabled.
+        //
+        if (!WinHttpQueryDataAvailable(m_hRequest, NULL))
+        {
+            hr = HRESULT_FROM_WIN32(GetLastError());
+            goto Failure;
+        }
+    }
+    else
+    {
+        //
+        // Buffering enabled.
+        //
+        if (m_pEntityBuffer == NULL)
+        {
+            m_pEntityBuffer = GetNewResponseBuffer(min(m_BytesToSend, BUFFER_SIZE));
+            if (m_pEntityBuffer == NULL)
+            {
+                hr = E_OUTOFMEMORY;
+                goto Failure;
+            }
+        }
+
+        if (!WinHttpReadData(m_hRequest,
+            m_pEntityBuffer,
+            min(m_BytesToSend, BUFFER_SIZE),
+            NULL))
+        {
+            hr = HRESULT_FROM_WIN32(GetLastError());
+            goto Failure;
+        }
+    }
+
+Failure:
+    return hr;
+}
+
+BYTE *
+FORWARDING_HANDLER::GetNewResponseBuffer(
+    DWORD   dwBufferSize
+)
+{
+    DWORD dwNeededSize = (m_cEntityBuffers + 1) * sizeof(BYTE *);
+    if (dwNeededSize > m_buffEntityBuffers.QuerySize() &&
+        !m_buffEntityBuffers.Resize(
+            max(dwNeededSize, m_buffEntityBuffers.QuerySize() * 2)))
+    {
+        return NULL;
+    }
+
+    BYTE *pBuffer = (BYTE *)HeapAlloc(GetProcessHeap(),
+        0, // dwFlags
+        dwBufferSize);
+    if (pBuffer == NULL)
+    {
+        return NULL;
+    }
+
+    m_buffEntityBuffers.QueryPtr()[m_cEntityBuffers] = pBuffer;
+    m_cEntityBuffers++;
+
+    return pBuffer;
+}
+
+VOID
+FORWARDING_HANDLER::FreeResponseBuffers()
+{
+    BYTE **pBuffers = m_buffEntityBuffers.QueryPtr();
+    for (DWORD i = 0; i<m_cEntityBuffers; i++)
+    {
+        HeapFree(GetProcessHeap(),
+            0, // dwFlags
+            pBuffers[i]);
+    }
+    m_cEntityBuffers = 0;
+    m_pEntityBuffer = NULL;
+    m_cBytesBuffered = 0;
+}
+
+HRESULT
+FORWARDING_HANDLER::SetStatusAndHeaders(
+    PCSTR           pszHeaders,
+    DWORD
+)
+{
+    HRESULT         hr;
+    IHttpResponse * pResponse = m_pW3Context->GetResponse();
+    IHttpRequest *  pRequest = m_pW3Context->GetRequest();
+    STACK_STRA(strHeaderName, 128);
+    STACK_STRA(strHeaderValue, 2048);
+    DWORD           index = 0;
+    PSTR            pchNewline;
+    PCSTR           pchEndofHeaderValue;
+    BOOL            fServerHeaderPresent = FALSE;
+
+    _ASSERT(pszHeaders != NULL);
+
+    //
+    // The first line is the status line
+    //
+    PSTR pchStatus = const_cast<PSTR>(strchr(pszHeaders, ' '));
+    if (pchStatus == NULL)
+    {
+        return HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
+    }
+    while (*pchStatus == ' ')
+    {
+        pchStatus++;
+    }
+    USHORT uStatus = static_cast<USHORT>(atoi(pchStatus));
+
+    if (m_fWebSocketEnabled && uStatus != 101)
+    {
+        //
+        // Expected 101 response.
+        //
+
+        m_fWebSocketEnabled = FALSE;
+    }
+
+    pchStatus = strchr(pchStatus, ' ');
+    if (pchStatus == NULL)
+    {
+        return HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
+    }
+    while (*pchStatus == ' ')
+    {
+        pchStatus++;
+    }
+    if (*pchStatus == '\r' || *pchStatus == '\n')
+    {
+        pchStatus--;
+    }
+
+    pchNewline = strchr(pchStatus, '\n');
+    if (pchNewline == NULL)
+    {
+        return HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
+    }
+
+    if (uStatus != 200)
+    {
+        //
+        // Skip over any spaces before the '\n'
+        //
+        for (pchEndofHeaderValue = pchNewline - 1;
+            (pchEndofHeaderValue > pchStatus) &&
+            ((*pchEndofHeaderValue == ' ') ||
+            (*pchEndofHeaderValue == '\r'));
+            pchEndofHeaderValue--)
+        {
+        }
+
+        //
+        // Copy the status description
+        //
+        if (FAILED(hr = strHeaderValue.Copy(
+            pchStatus,
+            (DWORD)(pchEndofHeaderValue - pchStatus) + 1)) ||
+            FAILED(hr = pResponse->SetStatus(uStatus,
+                strHeaderValue.QueryStr(),
+                0,
+                S_OK,
+                NULL,
+                TRUE)))
+        {
+            return hr;
+        }
+    }
+
+    for (index = static_cast<DWORD>(pchNewline - pszHeaders) + 1;
+        pszHeaders[index] != '\r' && pszHeaders[index] != '\n' && pszHeaders[index] != '\0';
+        index = static_cast<DWORD>(pchNewline - pszHeaders) + 1)
+    {
+        //
+        // Find the ':' in Header : Value\r\n
+        //
+        PCSTR pchColon = strchr(pszHeaders + index, ':');
+
+        //
+        // Find the '\n' in Header : Value\r\n
+        //
+        pchNewline = const_cast<PSTR>(strchr(pszHeaders + index, '\n'));
+
+        if (pchNewline == NULL)
+        {
+            return HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
+        }
+
+        //
+        // Take care of header continuation
+        //
+        while (pchNewline[1] == ' ' ||
+            pchNewline[1] == '\t')
+        {
+            pchNewline = strchr(pchNewline + 1, '\n');
+        }
+
+        DBG_ASSERT(
+            (pchColon != NULL) && (pchColon < pchNewline));
+        if ((pchColon == NULL) || (pchColon >= pchNewline))
+        {
+            return HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
+        }
+
+        //
+        // Skip over any spaces before the ':'
+        //
+        PCSTR pchEndofHeaderName;
+        for (pchEndofHeaderName = pchColon - 1;
+            (pchEndofHeaderName >= pszHeaders + index) &&
+            (*pchEndofHeaderName == ' ');
+            pchEndofHeaderName--)
+        {
+        }
+
+        pchEndofHeaderName++;
+
+        //
+        // Copy the header name
+        //
+        if (FAILED(hr = strHeaderName.Copy(
+            pszHeaders + index,
+            (DWORD)(pchEndofHeaderName - pszHeaders) - index)))
+        {
+            return hr;
+        }
+
+        //
+        // Skip over the ':' and any trailing spaces
+        //
+        for (index = static_cast<DWORD>(pchColon - pszHeaders) + 1;
+            pszHeaders[index] == ' ';
+            index++)
+        {
+        }
+
+        //
+        // Skip over any spaces before the '\n'
+        //
+        for (pchEndofHeaderValue = pchNewline - 1;
+            (pchEndofHeaderValue >= pszHeaders + index) &&
+            ((*pchEndofHeaderValue == ' ') ||
+            (*pchEndofHeaderValue == '\r'));
+            pchEndofHeaderValue--)
+        {
+        }
+
+        pchEndofHeaderValue++;
+
+        //
+        // Copy the header value
+        //
+        if (pchEndofHeaderValue == pszHeaders + index)
+        {
+            strHeaderValue.Reset();
+        }
+        else if (FAILED(hr = strHeaderValue.Copy(
+            pszHeaders + index,
+            (DWORD)(pchEndofHeaderValue - pszHeaders) - index)))
+        {
+            return hr;
+        }
+
+        //
+        // Do not pass the transfer-encoding:chunked, Connection, Date or
+        // Server headers along
+        //
+        DWORD headerIndex = sm_pResponseHeaderHash->GetIndex(strHeaderName.QueryStr());
+        if (headerIndex == UNKNOWN_INDEX)
+        {
+            hr = pResponse->SetHeader(strHeaderName.QueryStr(),
+                strHeaderValue.QueryStr(),
+                static_cast<USHORT>(strHeaderValue.QueryCCH()),
+                FALSE); // fReplace
+        }
+        else
+        {
+            switch (headerIndex)
+            {
+            case HttpHeaderTransferEncoding:
+                if (!strHeaderValue.Equals("chunked", TRUE))
+                {
+                    break;
+                }
+                __fallthrough;
+            case HttpHeaderConnection:
+            case HttpHeaderDate:
+                continue;
+
+            case HttpHeaderServer:
+                fServerHeaderPresent = TRUE;
+                break;
+
+            case HttpHeaderContentLength:
+                if (pRequest->GetRawHttpRequest()->Verb != HttpVerbHEAD)
+                {
+                    m_cContentLength = _atoi64(strHeaderValue.QueryStr());
+                }
+                break;
+            }
+
+            hr = pResponse->SetHeader(static_cast<HTTP_HEADER_ID>(headerIndex),
+                strHeaderValue.QueryStr(),
+                static_cast<USHORT>(strHeaderValue.QueryCCH()),
+                TRUE); // fReplace
+        }
+        if (FAILED(hr))
+        {
+            return hr;
+        }
+    }
+
+    //
+    // Explicitly remove the Server header if the back-end didn't set one.
+    //
+
+    if (!fServerHeaderPresent)
+    {
+        pResponse->DeleteHeader("Server");
+    }
+
+    if (m_fDoReverseRewriteHeaders)
+    {
+        hr = DoReverseRewrite(pResponse);
+        if (FAILED(hr))
+        {
+            return hr;
+        }
+    }
+
+    m_fResponseHeadersReceivedAndSet = TRUE;
+
+    return S_OK;
+}
+
+HRESULT
+FORWARDING_HANDLER::DoReverseRewrite(
+    _In_ IHttpResponse *pResponse
+)
+{
+    DBG_ASSERT(pResponse == m_pW3Context->GetResponse());
+    BOOL fSecure = (m_pW3Context->GetRequest()->GetRawHttpRequest()->pSslInfo != NULL);
+    STRA strTemp;
+    PCSTR pszHeader;
+    PCSTR pszStartHost;
+    PCSTR pszEndHost;
+    HTTP_RESPONSE_HEADERS *pHeaders;
+    HRESULT hr;
+
+    //
+    // Content-Location and Location are easy, one known header in
+    // http[s]://host/url format
+    //
+    pszHeader = pResponse->GetHeader(HttpHeaderContentLocation);
+    if (pszHeader != NULL)
+    {
+        if (_strnicmp(pszHeader, "http://", 7) == 0)
+        {
+            pszStartHost = pszHeader + 7;
+        }
+        else if (_strnicmp(pszHeader, "https://", 8) == 0)
+        {
+            pszStartHost = pszHeader + 8;
+        }
+        else
+        {
+            goto Location;
+        }
+
+        pszEndHost = strchr(pszStartHost, '/');
+
+        if (FAILED(hr = strTemp.Copy(fSecure ? "https://" : "http://")) ||
+            FAILED(hr = strTemp.Append(m_pszOriginalHostHeader)))
+        {
+            return hr;
+        }
+        if (pszEndHost != NULL &&
+            FAILED(hr = strTemp.Append(pszEndHost)))
+        {
+            return hr;
+        }
+        if (FAILED(hr = pResponse->SetHeader(HttpHeaderContentLocation,
+            strTemp.QueryStr(),
+            static_cast<USHORT>(strTemp.QueryCCH()),
+            TRUE)))
+        {
+            return hr;
+        }
+    }
+
+Location:
+
+    pszHeader = pResponse->GetHeader(HttpHeaderLocation);
+    if (pszHeader != NULL)
+    {
+        if (_strnicmp(pszHeader, "http://", 7) == 0)
+        {
+            pszStartHost = pszHeader + 7;
+        }
+        else if (_strnicmp(pszHeader, "https://", 8) == 0)
+        {
+            pszStartHost = pszHeader + 8;
+        }
+        else
+        {
+            goto SetCookie;
+        }
+
+        pszEndHost = strchr(pszStartHost, '/');
+
+        if (FAILED(hr = strTemp.Copy(fSecure ? "https://" : "http://")) ||
+            FAILED(hr = strTemp.Append(m_pszOriginalHostHeader)))
+        {
+            return hr;
+        }
+        if (pszEndHost != NULL &&
+            FAILED(hr = strTemp.Append(pszEndHost)))
+        {
+            return hr;
+        }
+        if (FAILED(hr = pResponse->SetHeader(HttpHeaderLocation,
+            strTemp.QueryStr(),
+            static_cast<USHORT>(strTemp.QueryCCH()),
+            TRUE)))
+        {
+            return hr;
+        }
+    }
+
+SetCookie:
+
+    //
+    // Set-Cookie is different - possibly multiple unknown headers with
+    // syntax name=value ; ... ; Domain=.host ; ...
+    //
+    pHeaders = &pResponse->GetRawHttpResponse()->Headers;
+    for (DWORD i = 0; i<pHeaders->UnknownHeaderCount; i++)
+    {
+        if (_stricmp(pHeaders->pUnknownHeaders[i].pName, "Set-Cookie") != 0)
+        {
+            continue;
+        }
+
+        pszHeader = pHeaders->pUnknownHeaders[i].pRawValue;
+        pszStartHost = strchr(pszHeader, ';');
+        while (pszStartHost != NULL)
+        {
+            pszStartHost++;
+            while (IsSpace(*pszStartHost))
+            {
+                pszStartHost++;
+            }
+
+            if (_strnicmp(pszStartHost, "Domain", 6) != 0)
+            {
+                pszStartHost = strchr(pszStartHost, ';');
+                continue;
+            }
+            pszStartHost += 6;
+
+            while (IsSpace(*pszStartHost))
+            {
+                pszStartHost++;
+            }
+            if (*pszStartHost != '=')
+            {
+                break;
+            }
+            pszStartHost++;
+            while (IsSpace(*pszStartHost))
+            {
+                pszStartHost++;
+            }
+            if (*pszStartHost == '.')
+            {
+                pszStartHost++;
+            }
+            pszEndHost = pszStartHost;
+            while (!IsSpace(*pszEndHost) &&
+                *pszEndHost != ';' &&
+                *pszEndHost != '\0')
+            {
+                pszEndHost++;
+            }
+
+            if (FAILED(hr = strTemp.Copy(pszHeader, static_cast<DWORD>(pszStartHost - pszHeader))) ||
+                FAILED(hr = strTemp.Append(m_pszOriginalHostHeader)) ||
+                FAILED(hr = strTemp.Append(pszEndHost)))
+            {
+                return hr;
+            }
+
+            pszHeader = (PCSTR)m_pW3Context->AllocateRequestMemory(strTemp.QueryCCH() + 1);
+            if (pszHeader == NULL)
+            {
+                return E_OUTOFMEMORY;
+            }
+            StringCchCopyA(const_cast<PSTR>(pszHeader), strTemp.QueryCCH() + 1, strTemp.QueryStr());
+            pHeaders->pUnknownHeaders[i].pRawValue = pszHeader;
+            pHeaders->pUnknownHeaders[i].RawValueLength = static_cast<USHORT>(strTemp.QueryCCH());
+
+            break;
+        }
+    }
+
+    return S_OK;
+}
+
+VOID
+FORWARDING_HANDLER::RemoveRequest(
+    VOID
+)
+{
+    ASYNC_DISCONNECT_CONTEXT *       pDisconnect;
+    pDisconnect = (ASYNC_DISCONNECT_CONTEXT *)InterlockedExchangePointer((PVOID*)&m_pDisconnect, NULL);
+    if (pDisconnect != NULL)
+    {
+        pDisconnect->ResetHandler();
+        pDisconnect = NULL;
+    }
+}
+
+VOID
+FORWARDING_HANDLER::TerminateRequest(
+    bool    fClientInitiated
+)
+{
+    UNREFERENCED_PARAMETER(fClientInitiated);
+
+    BOOL fLocked = FALSE;
+    if (TlsGetValue(g_dwTlsIndex) != this)
+    {
+        //
+        // Acquire exclusive lock as WinHTTP callback may happen on different thread
+        // We don't want two threads signal IIS pipeline simultaneously
+        //
+        AcquireLockExclusive();
+        fLocked = TRUE;
+    }
+
+    // Set tls as close winhttp handle will immediately trigger
+    // a winhttp callback on the same thread and we donot want to
+    // acquire the lock again
+
+#ifdef DEBUG
+    DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO,
+        "FORWARDING_HANDLER::TerminateRequest %d --%p\n", GetCurrentThreadId(), m_pW3Context);
+#endif // DEBUG
+
+    if (!m_fHttpHandleInClose)
+    {
+        m_fClientDisconnected = fClientInitiated;
+    }
+
+    if (fLocked)
+    {
+        ReleaseLockExclusive();
+    }
+}
+
+VOID
+FORWARDING_HANDLER::AcquireLockExclusive()
+{
+    DBG_ASSERT(TlsGetValue(g_dwTlsIndex) == NULL);
+    AcquireSRWLockExclusive(&m_RequestLock);
+    TlsSetValue(g_dwTlsIndex, this);
+    DBG_ASSERT(TlsGetValue(g_dwTlsIndex) == this);
+}
+
+VOID
+FORWARDING_HANDLER::ReleaseLockExclusive()
+{
+    DBG_ASSERT(TlsGetValue(g_dwTlsIndex) == this);
+    TlsSetValue(g_dwTlsIndex, NULL);
+    ReleaseSRWLockExclusive(&m_RequestLock);
+    DBG_ASSERT(TlsGetValue(g_dwTlsIndex) == NULL);
+}
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/RequestHandler/outofprocess/forwardinghandler.h b/src/IISIntegration/src/AspNetCoreModuleV2/RequestHandler/outofprocess/forwardinghandler.h
new file mode 100644
index 0000000000000000000000000000000000000000..427540f2d31fbe7c38a3eb0387a4d8d3d52dd8ee
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/RequestHandler/outofprocess/forwardinghandler.h
@@ -0,0 +1,233 @@
+#pragma once
+
+extern DWORD            g_OptionalWinHttpFlags;
+extern HINSTANCE        g_hWinHttpModule;
+extern HINSTANCE        g_hAspNetCoreModule;
+
+
+enum FORWARDING_REQUEST_STATUS
+{
+    FORWARDER_START,
+    FORWARDER_SENDING_REQUEST,
+    FORWARDER_RECEIVING_RESPONSE,
+    FORWARDER_RECEIVED_WEBSOCKET_RESPONSE,
+    FORWARDER_DONE,
+    FORWARDER_FINISH_REQUEST
+};
+
+
+class FORWARDING_HANDLER : public REQUEST_HANDLER
+{
+public:
+    FORWARDING_HANDLER(
+
+        _In_ IHttpContext     *pW3Context,
+        _In_  HTTP_MODULE_ID  *pModuleId,
+        _In_ APPLICATION      *pApplication);
+
+    ~FORWARDING_HANDLER();
+
+    __override
+    REQUEST_NOTIFICATION_STATUS
+    OnExecuteRequestHandler();
+
+    __override
+    REQUEST_NOTIFICATION_STATUS
+    OnAsyncCompletion(
+        DWORD       cbCompletion,
+        HRESULT     hrCompletionStatus
+    );
+
+    VOID
+    SetStatus(
+        FORWARDING_REQUEST_STATUS status
+    )
+    {
+        m_RequestStatus = status;
+    }
+
+    static
+    VOID
+    CALLBACK
+    FORWARDING_HANDLER::OnWinHttpCompletion(
+        HINTERNET   hRequest,
+        DWORD_PTR   dwContext,
+        DWORD       dwInternetStatus,
+        LPVOID      lpvStatusInformation,
+        DWORD       dwStatusInformationLength
+    );
+
+    static
+    HRESULT
+    StaticInitialize(
+        BOOL fEnableReferenceCountTracing
+    );
+
+    static
+    VOID
+    StaticTerminate();
+
+    VOID
+    TerminateRequest(
+        bool    fClientInitiated
+    );
+
+private:
+
+    VOID
+    AcquireLockExclusive();
+
+    VOID
+    ReleaseLockExclusive();
+
+    HRESULT
+    CreateWinHttpRequest(
+        _In_ const IHttpRequest *       pRequest,
+        _In_ const PROTOCOL_CONFIG *    pProtocol,
+        _In_ HINTERNET                  hConnect,
+        _Inout_ STRU *                  pstrUrl,
+        _In_ SERVER_PROCESS*                 pServerProcess
+    );
+
+    VOID
+    FORWARDING_HANDLER::OnWinHttpCompletionInternal(
+        _In_ HINTERNET   hRequest,
+        _In_ DWORD       dwInternetStatus,
+        _In_ LPVOID      lpvStatusInformation,
+        _In_ DWORD       dwStatusInformationLength
+    );
+
+    HRESULT
+    OnWinHttpCompletionSendRequestOrWriteComplete(
+        HINTERNET                   hRequest,
+        DWORD                       dwInternetStatus,
+        _Out_ BOOL *                pfClientError,
+        _Out_ BOOL *                pfAnotherCompletionExpected
+    );
+
+    HRESULT
+    OnWinHttpCompletionStatusHeadersAvailable(
+        HINTERNET                   hRequest,
+        _Out_ BOOL *                pfAnotherCompletionExpected
+    );
+
+    HRESULT
+    OnWinHttpCompletionStatusDataAvailable(
+        HINTERNET                   hRequest,
+        DWORD                       dwBytes,
+        _Out_ BOOL *                pfAnotherCompletionExpected
+    );
+
+    HRESULT
+    OnWinHttpCompletionStatusReadComplete(
+        _In_ IHttpResponse *        pResponse,
+        DWORD                       dwStatusInformationLength,
+        _Out_ BOOL *                pfAnotherCompletionExpected
+    );
+
+    HRESULT
+    OnSendingRequest(
+        DWORD                       cbCompletion,
+        HRESULT                     hrCompletionStatus,
+        _Out_ BOOL *                pfClientError
+    );
+
+    HRESULT
+    OnReceivingResponse();
+
+    BYTE *
+    GetNewResponseBuffer(
+        DWORD   dwBufferSize
+    );
+
+    VOID
+    FreeResponseBuffers();
+
+    HRESULT
+    SetStatusAndHeaders(
+        PCSTR               pszHeaders,
+        DWORD               cchHeaders
+    );
+
+    HRESULT
+    DoReverseRewrite(
+        _In_ IHttpResponse *pResponse
+    );
+
+    HRESULT
+    GetHeaders(
+        _In_ const PROTOCOL_CONFIG *    pProtocol,
+        _In_    BOOL                    fForwardWindowsAuthToken,
+        _In_    SERVER_PROCESS*         pServerProcess,
+        _Out_   PCWSTR *                ppszHeaders,
+        _Inout_ DWORD *                 pcchHeaders
+    );
+
+    VOID
+    RemoveRequest(
+        VOID
+    );
+
+    DWORD                               m_Signature;
+    //
+    // WinHTTP request handle is protected using a read-write lock.
+    //
+    SRWLOCK                             m_RequestLock;
+    HINTERNET                           m_hRequest;
+    FORWARDING_REQUEST_STATUS           m_RequestStatus;
+
+    BOOL                                m_fWebSocketEnabled;
+    BOOL                                m_fResponseHeadersReceivedAndSet;
+    BOOL                                m_fResetConnection;
+    BOOL                                m_fDoReverseRewriteHeaders;
+    BOOL                                m_fServerResetConn;
+    volatile  BOOL                      m_fClientDisconnected;
+    //
+    // A safety guard flag indicating no more IIS PostCompletion is allowed
+    //
+    volatile  BOOL                      m_fFinishRequest;
+    //
+    // A safety guard flag to prevent from unexpect callback which may signal IIS pipeline
+    // more than once with non-pending status
+    //
+    volatile  BOOL                      m_fDoneAsyncCompletion;
+    volatile  BOOL                      m_fHasError;
+    //
+    // WinHttp may hit AV under race if handle got closed more than once simultaneously 
+    // Use two bool variables to guard
+    //
+    volatile  BOOL                      m_fHttpHandleInClose;
+    volatile  BOOL                      m_fWebSocketHandleInClose;
+
+    PCSTR                               m_pszOriginalHostHeader;
+    PCWSTR                              m_pszHeaders;
+    //
+    // Record the number of winhttp handles in use
+    // release IIS pipeline only after all handles got closed
+    //
+    volatile  LONG                      m_dwHandlers;
+    DWORD                               m_cchHeaders;
+    DWORD                               m_BytesToReceive;
+    DWORD                               m_BytesToSend;
+    DWORD                               m_cchLastSend;
+    DWORD                               m_cEntityBuffers;
+    DWORD                               m_cBytesBuffered;
+    DWORD                               m_cMinBufferLimit;
+    ULONGLONG                           m_cContentLength;
+    WEBSOCKET_HANDLER *                 m_pWebSocket;
+    ASYNC_DISCONNECT_CONTEXT *          m_pDisconnect;
+
+    BYTE *                              m_pEntityBuffer;
+    static const SIZE_T                 INLINE_ENTITY_BUFFERS = 8;
+    BUFFER_T<BYTE*, INLINE_ENTITY_BUFFERS> m_buffEntityBuffers;
+
+    static ALLOC_CACHE_HANDLER *        sm_pAlloc;
+    static PROTOCOL_CONFIG              sm_ProtocolConfig;
+    static RESPONSE_HEADER_HASH *       sm_pResponseHeaderHash;
+    //
+    // Reference cout tracing for debugging purposes.
+    //
+    static TRACE_LOG *                  sm_pTraceLog;
+
+    static STRA                         sm_pStra502ErrorMsg;
+};
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/RequestHandler/outofprocess/outprocessapplication.cpp b/src/IISIntegration/src/AspNetCoreModuleV2/RequestHandler/outofprocess/outprocessapplication.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..e9222ba95e441ed458ba7870d798a559f66a44c0
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/RequestHandler/outofprocess/outprocessapplication.cpp
@@ -0,0 +1,78 @@
+#include "..\precomp.hxx"
+
+OUT_OF_PROCESS_APPLICATION::OUT_OF_PROCESS_APPLICATION(
+    IHttpServer*        pHttpServer,
+    ASPNETCORE_CONFIG*  pConfig) :
+    APPLICATION(pHttpServer, pConfig)
+{
+    m_status = APPLICATION_STATUS::RUNNING;
+    m_pProcessManager = NULL;
+    InitializeSRWLock(&rwlock);
+}
+
+OUT_OF_PROCESS_APPLICATION::~OUT_OF_PROCESS_APPLICATION()
+{
+    if (m_pProcessManager != NULL)
+    {
+        m_pProcessManager->ShutdownAllProcesses();
+        m_pProcessManager->DereferenceProcessManager();
+        m_pProcessManager = NULL;
+    }
+}
+
+HRESULT
+OUT_OF_PROCESS_APPLICATION::Initialize(
+)
+{
+    HRESULT hr = S_OK;
+    if (m_pProcessManager == NULL)
+    {
+        m_pProcessManager = new PROCESS_MANAGER;
+        if (m_pProcessManager == NULL)
+        {
+            hr = E_OUTOFMEMORY;
+            goto Finished;
+        }
+
+        hr = m_pProcessManager->Initialize();
+        if (FAILED(hr))
+        {
+            goto Finished;
+        }
+    }
+
+Finished:
+    return hr;
+}
+
+HRESULT
+OUT_OF_PROCESS_APPLICATION::GetProcess(
+    _Out_   SERVER_PROCESS       **ppServerProcess
+)
+{
+    return m_pProcessManager->GetProcess(m_pConfig, ppServerProcess);
+}
+
+__override
+VOID
+OUT_OF_PROCESS_APPLICATION::ShutDown()
+{
+    AcquireSRWLockExclusive(&rwlock);
+    {
+        if (m_pProcessManager != NULL)
+        {
+            m_pProcessManager->ShutdownAllProcesses();
+            m_pProcessManager->DereferenceProcessManager();
+            m_pProcessManager = NULL;
+        }
+    }
+    ReleaseSRWLockExclusive(&rwlock);
+}
+
+__override
+VOID
+OUT_OF_PROCESS_APPLICATION::Recycle()
+{
+    ShutDown();
+}
+
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/RequestHandler/outofprocess/outprocessapplication.h b/src/IISIntegration/src/AspNetCoreModuleV2/RequestHandler/outofprocess/outprocessapplication.h
new file mode 100644
index 0000000000000000000000000000000000000000..f8c30a69cc57bbb6aa891cd2563882b61783188e
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/RequestHandler/outofprocess/outprocessapplication.h
@@ -0,0 +1,30 @@
+#pragma once
+
+class OUT_OF_PROCESS_APPLICATION : public APPLICATION
+{
+
+public:
+    OUT_OF_PROCESS_APPLICATION(IHttpServer* pHttpServer, ASPNETCORE_CONFIG  *pConfig);
+
+    ~OUT_OF_PROCESS_APPLICATION();
+
+    HRESULT
+    Initialize();
+
+    HRESULT
+    GetProcess(
+        _Out_   SERVER_PROCESS       **ppServerProcess
+    );
+
+    __override
+    VOID
+    ShutDown();
+
+    __override
+    VOID
+    Recycle();
+
+private:
+    PROCESS_MANAGER * m_pProcessManager;
+    SRWLOCK           rwlock;
+};
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/RequestHandler/outofprocess/processmanager.cxx b/src/IISIntegration/src/AspNetCoreModuleV2/RequestHandler/outofprocess/processmanager.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..7e8c58462a56f321ace3ab1881d9579a769a7ac6
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/RequestHandler/outofprocess/processmanager.cxx
@@ -0,0 +1,274 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#include "..\precomp.hxx"
+
+volatile BOOL               PROCESS_MANAGER::sm_fWSAStartupDone = FALSE;
+
+HRESULT
+PROCESS_MANAGER::Initialize(
+    VOID
+)
+{
+    HRESULT                              hr       = S_OK;
+    WSADATA                              wsaData;
+    int                                  result;
+    BOOL                                 fLocked = FALSE;
+
+    if( !sm_fWSAStartupDone )
+    {
+        AcquireSRWLockExclusive( &m_srwLock );
+        fLocked = TRUE;
+
+        if( !sm_fWSAStartupDone )
+        {
+            if( (result = WSAStartup(MAKEWORD(2, 2), &wsaData)) != 0 )
+            {
+                hr = HRESULT_FROM_WIN32( result );
+                goto Finished;
+            }
+            sm_fWSAStartupDone = TRUE;
+        }
+
+        ReleaseSRWLockExclusive( &m_srwLock );
+        fLocked = FALSE;
+    }
+
+    m_dwRapidFailTickStart = GetTickCount();
+
+    if( m_hNULHandle == NULL )
+    {
+        SECURITY_ATTRIBUTES saAttr;
+        saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
+        saAttr.bInheritHandle = TRUE;
+        saAttr.lpSecurityDescriptor = NULL;
+
+        m_hNULHandle = CreateFileW( L"NUL",
+                                    FILE_WRITE_DATA,
+                                    FILE_SHARE_READ,
+                                    &saAttr,
+                                    CREATE_ALWAYS,
+                                    FILE_ATTRIBUTE_NORMAL,
+                                    NULL );
+        if( m_hNULHandle == INVALID_HANDLE_VALUE )
+        {
+            hr = HRESULT_FROM_WIN32(GetLastError());
+            goto Finished;
+        }
+    }
+
+Finished:
+
+    if(fLocked)
+    {
+        ReleaseSRWLockExclusive( &m_srwLock );
+    }
+
+    return hr;
+}
+
+PROCESS_MANAGER::~PROCESS_MANAGER()
+{
+    AcquireSRWLockExclusive(&m_srwLock);
+
+    //if( m_ppServerProcessList != NULL )
+    //{
+    //    for( DWORD i = 0; i < m_dwProcessesPerApplication; ++i )
+    //    {
+    //        if( m_ppServerProcessList[i] != NULL )
+    //        {
+    //            m_ppServerProcessList[i]->DereferenceServerProcess();
+    //            m_ppServerProcessList[i] = NULL;
+    //        }
+    //    }
+
+    //    delete[] m_ppServerProcessList;
+    //    m_ppServerProcessList = NULL;
+    //}
+
+    //if( m_hNULHandle != NULL )
+    //{
+    //    CloseHandle( m_hNULHandle );
+    //    m_hNULHandle = NULL;
+    //}
+
+    //if( sm_fWSAStartupDone )
+    //{
+    //    WSACleanup();
+    //    sm_fWSAStartupDone = FALSE;
+    //}
+
+    ReleaseSRWLockExclusive(&m_srwLock);
+}
+
+HRESULT
+PROCESS_MANAGER::GetProcess(
+    _In_    ASPNETCORE_CONFIG      *pConfig,
+    _Out_   SERVER_PROCESS        **ppServerProcess
+)
+{
+    HRESULT          hr = S_OK;
+    BOOL             fSharedLock = FALSE;
+    BOOL             fExclusiveLock = FALSE;
+    DWORD            dwProcessIndex = 0;
+    SERVER_PROCESS  *pSelectedServerProcess = NULL;
+
+    if (!m_fServerProcessListReady)
+    {
+        AcquireSRWLockExclusive(&m_srwLock);
+        fExclusiveLock = TRUE;
+
+        if (!m_fServerProcessListReady)
+        {
+            m_dwProcessesPerApplication = pConfig->QueryProcessesPerApplication();
+            m_ppServerProcessList = new SERVER_PROCESS*[m_dwProcessesPerApplication];
+            if (m_ppServerProcessList == NULL)
+            {
+                hr = E_OUTOFMEMORY;
+                goto Finished;
+            }
+
+            for (DWORD i = 0; i < m_dwProcessesPerApplication; ++i)
+            {
+                m_ppServerProcessList[i] = NULL;
+            }
+        }
+        m_fServerProcessListReady = TRUE;
+        ReleaseSRWLockExclusive(&m_srwLock);
+        fExclusiveLock = FALSE;
+    }
+
+    AcquireSRWLockShared(&m_srwLock);
+    fSharedLock = TRUE;
+
+    //
+    // round robin through to the next available process.
+    //
+    dwProcessIndex = (DWORD)InterlockedIncrement64((LONGLONG*)&m_dwRouteToProcessIndex);
+    dwProcessIndex = dwProcessIndex % m_dwProcessesPerApplication;
+
+    if (m_ppServerProcessList[dwProcessIndex] != NULL &&
+        m_ppServerProcessList[dwProcessIndex]->IsReady())
+    {
+        *ppServerProcess = m_ppServerProcessList[dwProcessIndex];
+        goto Finished;
+    }
+
+    ReleaseSRWLockShared(&m_srwLock);
+    fSharedLock = FALSE;
+
+    // should make the lock per process so that we can start processes simultaneously ?
+    if (m_ppServerProcessList[dwProcessIndex] == NULL ||
+        !m_ppServerProcessList[dwProcessIndex]->IsReady())
+    {
+        AcquireSRWLockExclusive(&m_srwLock);
+        fExclusiveLock = TRUE;
+
+        if (m_ppServerProcessList[dwProcessIndex] != NULL)
+        {
+            if (!m_ppServerProcessList[dwProcessIndex]->IsReady())
+            {
+                //
+                // terminate existing process that is not ready
+                // before creating new one.
+                //
+                ShutdownProcessNoLock( m_ppServerProcessList[dwProcessIndex] );
+            }
+            else
+            {
+                // server is already up and ready to serve requests.
+                //m_ppServerProcessList[dwProcessIndex]->ReferenceServerProcess();
+                *ppServerProcess = m_ppServerProcessList[dwProcessIndex];
+                goto Finished;
+            }
+        }
+
+        if (RapidFailsPerMinuteExceeded(pConfig->QueryRapidFailsPerMinute()))
+        {
+            //
+            // rapid fails per minute exceeded, do not create new process.
+            //
+            UTILITY::LogEventF(g_hEventLog,
+                EVENTLOG_INFORMATION_TYPE,
+                ASPNETCORE_EVENT_RAPID_FAIL_COUNT_EXCEEDED,
+                ASPNETCORE_EVENT_RAPID_FAIL_COUNT_EXCEEDED_MSG,
+                pConfig->QueryRapidFailsPerMinute());
+
+            hr = HRESULT_FROM_WIN32(ERROR_SERVER_DISABLED);
+            goto Finished;
+        }
+
+        if (m_ppServerProcessList[dwProcessIndex] == NULL)
+        {
+
+            pSelectedServerProcess = new SERVER_PROCESS();
+            if (pSelectedServerProcess == NULL)
+            {
+                hr = E_OUTOFMEMORY;
+                goto Finished;
+            }
+
+
+            hr = pSelectedServerProcess->Initialize(
+                    this,                                   //ProcessManager
+                    pConfig->QueryProcessPath(),            //
+                    pConfig->QueryArguments(),              //
+                    pConfig->QueryStartupTimeLimitInMS(),
+                    pConfig->QueryShutdownTimeLimitInMS(),
+                    pConfig->QueryWindowsAuthEnabled(),
+                    pConfig->QueryBasicAuthEnabled(),
+                    pConfig->QueryAnonymousAuthEnabled(),
+                    pConfig->QueryEnvironmentVariables(),
+                    pConfig->QueryStdoutLogEnabled(),
+                    pConfig->QueryWebSocketEnabled(),
+                    pConfig->QueryStdoutLogFile(),
+                    pConfig->QueryApplicationPhysicalPath(),   // physical path
+                    pConfig->QueryApplicationPath(),           // app path
+                    pConfig->QueryApplicationVirtualPath()     // App relative virtual path
+            );
+            if (FAILED(hr))
+            {
+                goto Finished;
+            }
+
+            hr = pSelectedServerProcess->StartProcess();
+            if (FAILED(hr))
+            {
+                goto Finished;
+            }
+        }
+
+        if (!pSelectedServerProcess->IsReady())
+        {
+            hr = HRESULT_FROM_WIN32(ERROR_CREATE_FAILED);
+            goto Finished;
+        }
+
+        m_ppServerProcessList[dwProcessIndex] = pSelectedServerProcess;
+        pSelectedServerProcess = NULL;
+
+    }
+    *ppServerProcess = m_ppServerProcessList[dwProcessIndex];
+
+Finished:
+
+    if (fSharedLock)
+    {
+        ReleaseSRWLockShared(&m_srwLock);
+        fSharedLock = FALSE;
+    }
+
+    if (fExclusiveLock)
+    {
+        ReleaseSRWLockExclusive(&m_srwLock);
+        fExclusiveLock = FALSE;
+    }
+
+    if (pSelectedServerProcess != NULL)
+    {
+        delete pSelectedServerProcess;
+        pSelectedServerProcess = NULL;
+    }
+
+    return hr;
+}
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/RequestHandler/outofprocess/processmanager.h b/src/IISIntegration/src/AspNetCoreModuleV2/RequestHandler/outofprocess/processmanager.h
new file mode 100644
index 0000000000000000000000000000000000000000..9523e8a819e41e0632eae474db7255db05e331af
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/RequestHandler/outofprocess/processmanager.h
@@ -0,0 +1,195 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#pragma once
+
+#define ONE_MINUTE_IN_MILLISECONDS 60000
+class SERVER_PROCESS;
+
+class PROCESS_MANAGER
+{
+public:
+
+    virtual 
+    ~PROCESS_MANAGER();
+
+    VOID
+    ReferenceProcessManager() const
+    {
+        InterlockedIncrement(&m_cRefs);
+    }
+
+    VOID
+    DereferenceProcessManager() const
+    {
+        if (InterlockedDecrement(&m_cRefs) == 0)
+        {
+            delete this;
+        }
+    }
+
+    HRESULT 
+    GetProcess(
+        _In_    ASPNETCORE_CONFIG      *pConfig,
+        _Out_   SERVER_PROCESS        **ppServerProcess
+    );
+
+    HANDLE
+    QueryNULHandle()
+    {
+        return m_hNULHandle;
+    }
+
+    HRESULT
+    Initialize(
+        VOID
+    );
+
+    VOID
+    SendShutdownSignal()
+    {
+        AcquireSRWLockExclusive( &m_srwLock );
+
+        for(DWORD i = 0; i < m_dwProcessesPerApplication; ++i )
+        {
+            if( m_ppServerProcessList != NULL && 
+                m_ppServerProcessList[i] != NULL )
+            {
+                m_ppServerProcessList[i]->SendSignal();
+                m_ppServerProcessList[i]->DereferenceServerProcess();
+                m_ppServerProcessList[i] = NULL;
+            }
+        }
+
+        ReleaseSRWLockExclusive( &m_srwLock );
+    }
+
+    VOID 
+    ShutdownProcess(
+        SERVER_PROCESS* pServerProcess
+    )
+    {
+        AcquireSRWLockExclusive( &m_srwLock );
+
+        ShutdownProcessNoLock( pServerProcess );
+
+        ReleaseSRWLockExclusive( &m_srwLock );
+    }
+
+    VOID 
+    ShutdownAllProcesses(
+    )
+    {
+        AcquireSRWLockExclusive( &m_srwLock );
+
+        ShutdownAllProcessesNoLock();
+
+        ReleaseSRWLockExclusive( &m_srwLock );
+    }
+
+    VOID 
+    IncrementRapidFailCount(
+        VOID
+    )
+    {
+        InterlockedIncrement(&m_cRapidFailCount);
+    }
+
+    PROCESS_MANAGER() : 
+        m_ppServerProcessList( NULL ),
+        m_hNULHandle( NULL ),
+        m_cRapidFailCount( 0 ),
+        m_dwProcessesPerApplication( 1 ),
+        m_dwRouteToProcessIndex( 0 ),
+        m_fServerProcessListReady(FALSE),
+        m_cRefs( 1 )
+    {
+        m_ppServerProcessList = NULL;
+        m_fServerProcessListReady = FALSE;
+        InitializeSRWLock( &m_srwLock );
+    }
+
+private:
+
+    BOOL 
+    RapidFailsPerMinuteExceeded(
+        LONG dwRapidFailsPerMinute
+    )
+    {
+        DWORD dwCurrentTickCount = GetTickCount();
+
+        if( (dwCurrentTickCount - m_dwRapidFailTickStart)
+             >= ONE_MINUTE_IN_MILLISECONDS )
+        {
+            //
+            // reset counters every minute.
+            //
+
+            InterlockedExchange(&m_cRapidFailCount, 0);
+            m_dwRapidFailTickStart = dwCurrentTickCount;
+        }
+
+        return m_cRapidFailCount > dwRapidFailsPerMinute;
+    }
+
+    VOID 
+    ShutdownProcessNoLock(
+        SERVER_PROCESS* pServerProcess
+    )
+    {
+        for(DWORD i = 0; i < m_dwProcessesPerApplication; ++i )
+        {
+            if( m_ppServerProcessList != NULL && 
+                m_ppServerProcessList[i] != NULL && 
+                m_ppServerProcessList[i]->GetPort() == pServerProcess->GetPort() )
+            {
+                // shutdown pServerProcess if not already shutdown.
+                m_ppServerProcessList[i]->StopProcess();
+                m_ppServerProcessList[i]->DereferenceServerProcess();
+                m_ppServerProcessList[i] = NULL;
+            }
+        }
+    }
+
+    VOID 
+    ShutdownAllProcessesNoLock(
+        VOID
+    )
+    {
+        for(DWORD i = 0; i < m_dwProcessesPerApplication; ++i )
+        {
+            if( m_ppServerProcessList != NULL &&
+                m_ppServerProcessList[i] != NULL )
+            {
+                // shutdown pServerProcess if not already shutdown.
+                m_ppServerProcessList[i]->SendSignal();
+                m_ppServerProcessList[i]->DereferenceServerProcess();
+                m_ppServerProcessList[i] = NULL;
+            }
+        }
+    }
+
+    volatile LONG                     m_cRapidFailCount;
+    DWORD                             m_dwRapidFailTickStart;
+    DWORD                             m_dwProcessesPerApplication;
+    volatile DWORD                    m_dwRouteToProcessIndex;
+
+    SRWLOCK                           m_srwLock;
+    SERVER_PROCESS                  **m_ppServerProcessList;
+
+    //
+    // m_hNULHandle is used to redirect stdout/stderr to NUL.
+    // If Createprocess is called to launch a batch file for example,
+    // it tries to write to the console buffer by default. It fails to 
+    // start if the console buffer is owned by the parent process i.e 
+    // in our case w3wp.exe. So we have to redirect the stdout/stderr
+    // of the child process to NUL or to a file (anything other than
+    // the console buffer of the parent process).
+    //
+
+    HANDLE                            m_hNULHandle;
+    mutable LONG                      m_cRefs;
+
+    volatile static BOOL              sm_fWSAStartupDone;
+    volatile BOOL                     m_fServerProcessListReady;
+};
\ No newline at end of file
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/RequestHandler/outofprocess/protocolconfig.cxx b/src/IISIntegration/src/AspNetCoreModuleV2/RequestHandler/outofprocess/protocolconfig.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..9faebab82a08055ca1c0c520bcc3b683757eec7b
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/RequestHandler/outofprocess/protocolconfig.cxx
@@ -0,0 +1,48 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#include "..\precomp.hxx"
+
+HRESULT
+PROTOCOL_CONFIG::Initialize()
+{
+    HRESULT hr;
+    STRU strTemp;
+
+    m_fKeepAlive = TRUE;
+    m_msTimeout = 120000;
+    m_fPreserveHostHeader = TRUE;
+    m_fReverseRewriteHeaders = FALSE;
+
+    if (FAILED(hr = m_strXForwardedForName.CopyW(L"X-Forwarded-For")))
+    {
+        goto Finished;
+    }
+
+    if (FAILED(hr = m_strSslHeaderName.CopyW(L"X-Forwarded-Proto")))
+    {
+        goto Finished;
+    }
+
+    if (FAILED(hr = m_strClientCertName.CopyW(L"MS-ASPNETCORE-CLIENTCERT")))
+    {
+        goto Finished;
+    }
+
+    m_fIncludePortInXForwardedFor = TRUE;
+    m_dwMinResponseBuffer = 0; // no response buffering
+    m_dwResponseBufferLimit = 4096*1024;
+    m_dwMaxResponseHeaderSize = 65536;
+
+Finished:
+
+    return hr;
+}
+
+VOID
+PROTOCOL_CONFIG::OverrideConfig(
+    ASPNETCORE_CONFIG *pAspNetCoreConfig
+)
+{
+    m_msTimeout = pAspNetCoreConfig->QueryRequestTimeoutInMS();
+}
\ No newline at end of file
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/RequestHandler/outofprocess/protocolconfig.h b/src/IISIntegration/src/AspNetCoreModuleV2/RequestHandler/outofprocess/protocolconfig.h
new file mode 100644
index 0000000000000000000000000000000000000000..0bb34aa53d7e171618569a9f5c89332a294f2d36
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/RequestHandler/outofprocess/protocolconfig.h
@@ -0,0 +1,103 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#pragma once
+
+class PROTOCOL_CONFIG
+{
+ public:
+
+    PROTOCOL_CONFIG()
+    {
+    }
+
+    HRESULT
+    Initialize();
+
+    VOID
+    OverrideConfig(
+        ASPNETCORE_CONFIG *pAspNetCoreConfig
+    );
+
+    BOOL
+    QueryDoKeepAlive() const
+    {
+        return m_fKeepAlive;
+    }
+
+    DWORD
+    QueryTimeout() const
+    {
+        return m_msTimeout;
+    }
+
+    BOOL
+    QueryPreserveHostHeader() const
+    {
+        return m_fPreserveHostHeader;
+    }
+
+    BOOL
+    QueryReverseRewriteHeaders() const
+    {
+        return m_fReverseRewriteHeaders;
+    }
+
+    const STRA *
+    QueryXForwardedForName() const
+    {
+        return &m_strXForwardedForName;
+    }
+
+    BOOL
+    QueryIncludePortInXForwardedFor() const
+    {
+        return m_fIncludePortInXForwardedFor;
+    }
+
+    DWORD
+    QueryMinResponseBuffer() const
+    {
+        return m_dwMinResponseBuffer;
+    }
+
+    DWORD
+    QueryResponseBufferLimit() const
+    {
+        return m_dwResponseBufferLimit;
+    }
+
+    DWORD
+    QueryMaxResponseHeaderSize() const
+    {
+        return m_dwMaxResponseHeaderSize;
+    }
+
+    const STRA*
+    QuerySslHeaderName() const
+    {
+        return &m_strSslHeaderName;
+    }
+
+    const STRA *
+    QueryClientCertName() const
+    {
+        return &m_strClientCertName;
+    }
+
+ private:
+    
+    BOOL            m_fKeepAlive;
+    BOOL            m_fPreserveHostHeader;
+    BOOL            m_fReverseRewriteHeaders;
+    BOOL            m_fIncludePortInXForwardedFor;
+
+    DWORD           m_msTimeout;
+    DWORD           m_dwMinResponseBuffer;
+    DWORD           m_dwResponseBufferLimit;
+    DWORD           m_dwMaxResponseHeaderSize;
+
+    STRA            m_strXForwardedForName;
+    STRA            m_strSslHeaderName;
+    STRA            m_strClientCertName;
+};
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/RequestHandler/outofprocess/responseheaderhash.cxx b/src/IISIntegration/src/AspNetCoreModuleV2/RequestHandler/outofprocess/responseheaderhash.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..f2fae274d536f5d3a7c8a8b05c193a3662437d99
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/RequestHandler/outofprocess/responseheaderhash.cxx
@@ -0,0 +1,98 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#include "..\precomp.hxx"
+
+HEADER_RECORD RESPONSE_HEADER_HASH::sm_rgHeaders[] = 
+{
+    { "Cache-Control",       HttpHeaderCacheControl       },
+    { "Connection",          HttpHeaderConnection         },
+    { "Date",                HttpHeaderDate               },
+    { "Keep-Alive",          HttpHeaderKeepAlive          },
+    { "Pragma",              HttpHeaderPragma             },
+    { "Trailer",             HttpHeaderTrailer            },
+    { "Transfer-Encoding",   HttpHeaderTransferEncoding   },
+    { "Upgrade",             HttpHeaderUpgrade            },
+    { "Via",                 HttpHeaderVia                },
+    { "Warning",             HttpHeaderWarning            },
+    { "Allow",               HttpHeaderAllow              },
+    { "Content-Length",      HttpHeaderContentLength      },
+    { "Content-Type",        HttpHeaderContentType        },
+    { "Content-Encoding",    HttpHeaderContentEncoding    },
+    { "Content-Language",    HttpHeaderContentLanguage    },
+    { "Content-Location",    HttpHeaderContentLocation    },
+    { "Content-MD5",         HttpHeaderContentMd5         },
+    { "Content-Range",       HttpHeaderContentRange       },
+    { "Expires",             HttpHeaderExpires            },
+    { "Last-Modified",       HttpHeaderLastModified       },
+    { "Accept-Ranges",       HttpHeaderAcceptRanges       },
+    { "Age",                 HttpHeaderAge                },
+    { "ETag",                HttpHeaderEtag               },
+    { "Location",            HttpHeaderLocation           },
+    { "Proxy-Authenticate",  HttpHeaderProxyAuthenticate  },
+    { "Retry-After",         HttpHeaderRetryAfter         },
+    { "Server",              HttpHeaderServer             },
+    // Set it to something which cannot be a header name, in effect
+    // making Server an unknown header. w:w is used to avoid collision with Keep-Alive.
+    { "w:w\r\n",             HttpHeaderServer             },
+    // Set it to something which cannot be a header name, in effect
+    // making Set-Cookie an unknown header
+    { "y:y\r\n",             HttpHeaderSetCookie          },
+    { "Vary",                HttpHeaderVary               },
+    // Set it to something which cannot be a header name, in effect
+    // making WWW-Authenticate an unknown header
+    { "z:z\r\n",             HttpHeaderWwwAuthenticate    }
+
+};
+
+HRESULT
+RESPONSE_HEADER_HASH::Initialize(
+    VOID
+)
+/*++
+
+Routine Description:
+
+    Initialize global header hash table
+
+Arguments:
+
+    None
+
+Return Value:
+
+    HRESULT
+
+--*/
+{
+    HRESULT hr;
+
+    //
+    // 31 response headers.
+    // Make sure to update the number of buckets it new headers
+    // are added. Test it to avoid collisions.
+    //
+    C_ASSERT(_countof(sm_rgHeaders) == 31);
+
+    //
+    // 79 buckets will have less collisions for the 31 response headers.
+    // Known collisions are "Age" colliding with "Expire" and "Location"
+    // colliding with both "Expire" and "Age".
+    //
+    hr = HASH_TABLE::Initialize(79);
+    if (FAILED(hr))
+    {
+        return hr;
+    }
+
+    for ( DWORD Index = 0; Index < _countof(sm_rgHeaders); ++Index )
+    {
+        if (FAILED(hr = InsertRecord(&sm_rgHeaders[Index])))
+        {
+            return hr;
+        }
+    }
+    
+    return S_OK;
+}
+
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/RequestHandler/outofprocess/responseheaderhash.h b/src/IISIntegration/src/AspNetCoreModuleV2/RequestHandler/outofprocess/responseheaderhash.h
new file mode 100644
index 0000000000000000000000000000000000000000..54f9c8295426c8ab6cdda7405018a8d49e3ede92
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/RequestHandler/outofprocess/responseheaderhash.h
@@ -0,0 +1,108 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#pragma once
+
+//
+// *_HEADER_HASH maps strings to UlHeader* values
+//
+
+#define UNKNOWN_INDEX           (0xFFFFFFFF)
+
+struct HEADER_RECORD
+{
+    PCSTR   _pszName;
+    ULONG   _ulHeaderIndex;
+};
+
+class RESPONSE_HEADER_HASH: public HASH_TABLE<HEADER_RECORD, PCSTR>
+{
+public:
+    RESPONSE_HEADER_HASH() 
+    {}
+    
+    VOID
+    ReferenceRecord(
+        HEADER_RECORD *
+    )
+    {}
+
+    VOID
+    DereferenceRecord(
+        HEADER_RECORD *
+    )
+    {}
+
+    PCSTR
+    ExtractKey(
+        HEADER_RECORD * pRecord
+    )
+    {
+        return pRecord->_pszName;
+    }
+
+    DWORD
+    CalcKeyHash(
+        PCSTR   key
+    )
+    {
+        return HashStringNoCase(key);
+    }
+
+    BOOL
+    EqualKeys(
+        PCSTR   key1,
+        PCSTR   key2
+    )
+    {
+        return (_stricmp(key1, key2) == 0);
+    }
+
+    HRESULT
+    Initialize(
+        VOID
+    );
+    
+    VOID
+    Terminate(
+        VOID
+    );
+    
+    DWORD
+    GetIndex(
+        PCSTR             pszName
+    )
+    {
+        HEADER_RECORD *       pRecord = NULL;
+
+        FindKey(pszName, &pRecord);
+        if (pRecord != NULL)
+        {
+            return pRecord->_ulHeaderIndex;
+        }
+
+        return UNKNOWN_INDEX;
+    }
+    
+    static
+    PCSTR
+    GetString(
+        ULONG               ulIndex
+    )
+    {
+        if (ulIndex < HttpHeaderResponseMaximum)
+        {
+            DBG_ASSERT(sm_rgHeaders[ulIndex]._ulHeaderIndex == ulIndex);
+            return sm_rgHeaders[ulIndex]._pszName;
+        }
+
+        return NULL;
+    }
+    
+private:
+
+    static HEADER_RECORD         sm_rgHeaders[];
+
+    RESPONSE_HEADER_HASH(const RESPONSE_HEADER_HASH &);
+    void operator=(const RESPONSE_HEADER_HASH &);
+};
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/RequestHandler/outofprocess/serverprocess.cxx b/src/IISIntegration/src/AspNetCoreModuleV2/RequestHandler/outofprocess/serverprocess.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..de309bf643f2aa0bd94e730787d39eca9693a540
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/RequestHandler/outofprocess/serverprocess.cxx
@@ -0,0 +1,2148 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#include "..\precomp.hxx"
+#include <IPHlpApi.h>
+//#include <share.h>
+
+//extern BOOL g_fNsiApiNotSupported;
+
+#define STARTUP_TIME_LIMIT_INCREMENT_IN_MILLISECONDS 5000
+
+
+HRESULT
+SERVER_PROCESS::Initialize(
+    PROCESS_MANAGER      *pProcessManager,
+    STRU                 *pszProcessExePath,
+    STRU                 *pszArguments,
+    DWORD                 dwStartupTimeLimitInMS,
+    DWORD                 dwShtudownTimeLimitInMS,
+    BOOL                  fWindowsAuthEnabled,
+    BOOL                  fBasicAuthEnabled,
+    BOOL                  fAnonymousAuthEnabled,
+    ENVIRONMENT_VAR_HASH *pEnvironmentVariables,
+    BOOL                  fStdoutLogEnabled,
+    BOOL                  fWebsocketsEnabled,
+    STRU                  *pstruStdoutLogFile,
+    STRU                  *pszAppPhysicalPath,
+    STRU                  *pszAppPath,
+    STRU                  *pszAppVirtualPath
+)
+{
+    HRESULT                                 hr = S_OK;
+
+    m_pProcessManager = pProcessManager;
+    m_dwStartupTimeLimitInMS = dwStartupTimeLimitInMS;
+    m_dwShutdownTimeLimitInMS = dwShtudownTimeLimitInMS;
+    m_fStdoutLogEnabled = fStdoutLogEnabled;
+    m_fWindowsAuthEnabled = fWindowsAuthEnabled;
+    m_fBasicAuthEnabled = fBasicAuthEnabled;
+    m_fAnonymousAuthEnabled = fAnonymousAuthEnabled;
+    m_fWebsocketsEnabled = fWebsocketsEnabled;
+    m_pProcessManager->ReferenceProcessManager();
+
+    if (FAILED(hr = m_ProcessPath.Copy(*pszProcessExePath)) ||
+        FAILED(hr = m_struLogFile.Copy(*pstruStdoutLogFile))||
+        FAILED(hr = m_struPhysicalPath.Copy(*pszAppPhysicalPath))||
+        FAILED(hr = m_struAppFullPath.Copy(*pszAppPath))||
+        FAILED(hr = m_struAppVirtualPath.Copy(*pszAppVirtualPath))||
+        FAILED(hr = m_Arguments.Copy(*pszArguments)) ||
+        FAILED(hr = SetupJobObject()))
+    {
+        goto Finished;
+    }
+
+    m_pEnvironmentVarTable = pEnvironmentVariables;
+
+Finished:
+    return hr;
+}
+
+HRESULT
+SERVER_PROCESS::SetupJobObject(VOID)
+{
+    HRESULT                                 hr = S_OK;
+    JOBOBJECT_EXTENDED_LIMIT_INFORMATION    jobInfo = { 0 };
+
+    if (m_hJobObject == NULL)
+    {
+        m_hJobObject = CreateJobObject(NULL,   // LPSECURITY_ATTRIBUTES
+            NULL); // LPCTSTR lpName
+#pragma warning( disable : 4312)
+        // 0xdeadbeef is used by Antares
+        if (m_hJobObject == NULL || m_hJobObject == (HANDLE)0xdeadbeef)
+        {
+            m_hJobObject = NULL;
+            // ignore job object creation error.
+        }
+#pragma warning( error : 4312)
+        if (m_hJobObject != NULL)
+        {
+            jobInfo.BasicLimitInformation.LimitFlags =
+                JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
+
+            if (!SetInformationJobObject(m_hJobObject,
+                JobObjectExtendedLimitInformation,
+                &jobInfo,
+                sizeof jobInfo))
+            {
+                hr = HRESULT_FROM_WIN32(GetLastError());
+            }
+        }
+    }
+
+    return hr;
+}
+
+HRESULT
+SERVER_PROCESS::GetRandomPort
+(
+    DWORD* pdwPickedPort,
+    DWORD  dwExcludedPort = 0
+)
+{
+    HRESULT hr = S_OK;
+    BOOL    fPortInUse = FALSE;
+    DWORD   dwActualProcessId = 0;
+
+    if (g_fNsiApiNotSupported)
+    {
+        //
+        // the default value for optional parameter dwExcludedPort is 0 which is reserved
+        // a random number between MIN_PORT and MAX_PORT
+        //
+        while ((*pdwPickedPort = (rand() % (MAX_PORT - MIN_PORT)) + MIN_PORT + 1) == dwExcludedPort);
+    }
+    else
+    {
+        DWORD cRetry = 0;
+        do
+        {
+            //
+            // ignore dwActualProcessId because here we are
+            // determing whether the randomly generated port is
+            // in use by any other process.
+            //
+            while ((*pdwPickedPort = (rand() % (MAX_PORT - MIN_PORT)) + MIN_PORT + 1) == dwExcludedPort);
+            hr = CheckIfServerIsUp(*pdwPickedPort, &dwActualProcessId, &fPortInUse);
+        } while (fPortInUse && ++cRetry < MAX_RETRY);
+
+        if (cRetry >= MAX_RETRY)
+        {
+            hr = HRESULT_FROM_WIN32(ERROR_PORT_NOT_SET);
+        }
+    }
+
+    return hr;
+}
+
+HRESULT
+SERVER_PROCESS::SetupListenPort(
+    ENVIRONMENT_VAR_HASH    *pEnvironmentVarTable,
+    BOOL*                    pfCriticalError
+)
+{
+    HRESULT hr = S_OK;
+    ENVIRONMENT_VAR_ENTRY *pEntry = NULL;
+    *pfCriticalError = FALSE;
+
+    pEnvironmentVarTable->FindKey(ASPNETCORE_PORT_ENV_STR, &pEntry);
+    if (pEntry != NULL)
+    {
+        if (pEntry->QueryValue() != NULL || pEntry->QueryValue()[0] != L'\0')
+        {
+            m_dwPort = (DWORD)_wtoi(pEntry->QueryValue());
+            if (m_dwPort >MAX_PORT || m_dwPort < MIN_PORT)
+            {
+                hr = E_INVALIDARG;
+                *pfCriticalError = TRUE;
+                goto Finished;
+                // need add log for this one
+            }
+            hr = m_struPort.Copy(pEntry->QueryValue());
+            goto Finished;
+        }
+        else
+        {
+            //
+            // user set the env variable but did not give value, let's set it up
+            //
+            pEnvironmentVarTable->DeleteKey(ASPNETCORE_PORT_ENV_STR);
+        }
+        pEntry->Dereference();
+        pEntry = NULL;
+    }
+
+    WCHAR buffer[15];
+    if (FAILED(hr = GetRandomPort(&m_dwPort)))
+    {
+        goto Finished;
+    }
+
+    if (swprintf_s(buffer, 15, L"%d", m_dwPort) <= 0)
+    {
+        hr = E_INVALIDARG;
+        goto Finished;
+    }
+
+    pEntry = new ENVIRONMENT_VAR_ENTRY();
+    if (pEntry == NULL)
+    {
+        hr = E_OUTOFMEMORY;
+        goto Finished;
+    }
+
+    if (FAILED(hr = pEntry->Initialize(ASPNETCORE_PORT_ENV_STR, buffer)) ||
+        FAILED(hr = pEnvironmentVarTable->InsertRecord(pEntry)) ||
+        FAILED(hr = m_struPort.Copy(buffer)))
+    {
+        goto Finished;
+    }
+
+Finished:
+    if (pEntry != NULL)
+    {
+        pEntry->Dereference();
+        pEntry = NULL;
+    }
+
+    if (FAILED(hr))
+    {
+        UTILITY::LogEventF(g_hEventLog,
+            EVENTLOG_ERROR_TYPE,
+            ASPNETCORE_EVENT_PROCESS_START_SUCCESS,
+            ASPNETCORE_EVENT_PROCESS_START_PORTSETUP_ERROR_MSG,
+            m_struAppFullPath.QueryStr(),
+            m_struPhysicalPath.QueryStr(),
+            m_dwPort,
+            MIN_PORT,
+            MAX_PORT,
+            hr);
+    }
+
+    return hr;
+}
+
+HRESULT
+SERVER_PROCESS::SetupAppPath(
+    ENVIRONMENT_VAR_HASH*    pEnvironmentVarTable
+)
+{
+    HRESULT      hr = S_OK;
+    ENVIRONMENT_VAR_ENTRY*  pEntry = NULL;
+
+    pEnvironmentVarTable->FindKey(ASPNETCORE_APP_PATH_ENV_STR, &pEntry);
+    if (pEntry != NULL)
+    {
+        // user should not set this environment variable in configuration
+        pEnvironmentVarTable->DeleteKey(ASPNETCORE_APP_PATH_ENV_STR);
+        pEntry->Dereference();
+        pEntry = NULL;
+    }
+
+    pEntry = new ENVIRONMENT_VAR_ENTRY();
+    if (pEntry == NULL)
+    {
+        hr = E_OUTOFMEMORY;
+        goto Finished;
+    }
+
+    if (FAILED(hr = pEntry->Initialize(ASPNETCORE_APP_PATH_ENV_STR, m_struAppVirtualPath.QueryStr())) ||
+        FAILED(hr = pEnvironmentVarTable->InsertRecord(pEntry)))
+    {
+        goto Finished;
+    }
+
+Finished:
+    if (pEntry != NULL)
+    {
+        pEntry->Dereference();
+        pEntry = NULL;
+    }
+    return hr;
+}
+
+HRESULT
+SERVER_PROCESS::SetupAppToken(
+    ENVIRONMENT_VAR_HASH    *pEnvironmentVarTable
+)
+{
+    HRESULT     hr = S_OK;
+    UUID        logUuid;
+    PSTR        pszLogUuid = NULL;
+    BOOL        fRpcStringAllocd = FALSE;
+    RPC_STATUS  rpcStatus;
+    STRU        strAppToken;
+    ENVIRONMENT_VAR_ENTRY*  pEntry = NULL;
+
+    pEnvironmentVarTable->FindKey(ASPNETCORE_APP_TOKEN_ENV_STR, &pEntry);
+    if (pEntry != NULL)
+    {
+        // user sets the environment variable
+        m_straGuid.Reset();
+        hr = m_straGuid.CopyW(pEntry->QueryValue());
+        pEntry->Dereference();
+        pEntry = NULL;
+        goto Finished;
+    }
+    else
+    {
+        if (m_straGuid.IsEmpty())
+        {
+            // the GUID has not been set yet
+            rpcStatus = UuidCreate(&logUuid);
+            if (rpcStatus != RPC_S_OK)
+            {
+                hr = rpcStatus;
+                goto Finished;
+            }
+
+            rpcStatus = UuidToStringA(&logUuid, (BYTE **)&pszLogUuid);
+            if (rpcStatus != RPC_S_OK)
+            {
+                hr = rpcStatus;
+                goto Finished;
+            }
+
+            fRpcStringAllocd = TRUE;
+
+            if (FAILED(hr = m_straGuid.Copy(pszLogUuid)))
+            {
+                goto Finished;
+            }
+        }
+
+        pEntry = new ENVIRONMENT_VAR_ENTRY();
+        if (pEntry == NULL)
+        {
+            hr = E_OUTOFMEMORY;
+            goto Finished;
+        }
+
+        if (FAILED(strAppToken.CopyA(m_straGuid.QueryStr())) ||
+            FAILED(hr = pEntry->Initialize(ASPNETCORE_APP_TOKEN_ENV_STR, strAppToken.QueryStr())) ||
+            FAILED(hr = pEnvironmentVarTable->InsertRecord(pEntry)))
+        {
+            goto Finished;
+        }
+    }
+
+Finished:
+
+    if (fRpcStringAllocd)
+    {
+        RpcStringFreeA((BYTE **)&pszLogUuid);
+        pszLogUuid = NULL;
+    }
+    if (pEntry != NULL)
+    {
+        pEntry->Dereference();
+        pEntry = NULL;
+    }
+    return hr;
+}
+
+HRESULT
+SERVER_PROCESS::OutputEnvironmentVariables
+(
+    MULTISZ*                pmszOutput,
+    ENVIRONMENT_VAR_HASH*   pEnvironmentVarTable
+)
+{
+    HRESULT    hr = S_OK;
+    LPWSTR     pszEnvironmentVariables = NULL;
+    LPWSTR     pszCurrentVariable = NULL;
+    LPWSTR     pszNextVariable = NULL;
+    LPWSTR     pszEqualChar = NULL;
+    STRU       strEnvVar;
+    ENVIRONMENT_VAR_ENTRY* pEntry = NULL;
+
+    DBG_ASSERT(pmszOutput);
+    DBG_ASSERT(pEnvironmentVarTable); // We added some startup variables
+    DBG_ASSERT(pEnvironmentVarTable->Count() >0);
+
+    // cleanup, as we may in retry logic
+    pmszOutput->Reset();
+
+    pszEnvironmentVariables = GetEnvironmentStringsW();
+    if (pszEnvironmentVariables == NULL)
+    {
+        hr = HRESULT_FROM_WIN32(ERROR_INVALID_ENVIRONMENT);
+        goto Finished;
+    }
+    pszCurrentVariable = pszEnvironmentVariables;
+    while (*pszCurrentVariable != L'\0')
+    {
+        pszNextVariable = pszCurrentVariable + wcslen(pszCurrentVariable) + 1;
+        pszEqualChar = wcschr(pszCurrentVariable, L'=');
+        if (pszEqualChar != NULL)
+        {
+            if (FAILED(hr = strEnvVar.Copy(pszCurrentVariable, (DWORD)(pszEqualChar - pszCurrentVariable) + 1)))
+            {
+                goto Finished;
+            }
+            pEnvironmentVarTable->FindKey(strEnvVar.QueryStr(), &pEntry);
+            if (pEntry != NULL)
+            {
+                // same env variable is defined in configuration, use it
+                if (FAILED(hr = strEnvVar.Append(pEntry->QueryValue())))
+                {
+                    goto Finished;
+                }
+                pmszOutput->Append(strEnvVar);  //should we check the returned bool
+                // remove the record from hash table as we already output it
+                pEntry->Dereference();
+                pEnvironmentVarTable->DeleteKey(pEntry->QueryName());
+                strEnvVar.Reset();
+                pEntry = NULL;
+            }
+            else
+            {
+                pmszOutput->Append(pszCurrentVariable);
+            }
+        }
+        else
+        {
+            // env varaible is not well formated
+            hr = HRESULT_FROM_WIN32(ERROR_INVALID_ENVIRONMENT);
+            goto Finished;
+        }
+        // move to next env variable
+        pszCurrentVariable = pszNextVariable;
+    }
+    // append the remaining env variable in hash table
+    pEnvironmentVarTable->Apply(ENVIRONMENT_VAR_HELPERS::CopyToMultiSz, pmszOutput);
+
+Finished:
+    if (pszEnvironmentVariables != NULL)
+    {
+        FreeEnvironmentStringsW(pszEnvironmentVariables);
+        pszEnvironmentVariables = NULL;
+    }
+    return hr;
+}
+
+HRESULT
+SERVER_PROCESS::SetupCommandLine(
+    STRU*      pstrCommandLine
+)
+{
+    HRESULT    hr = S_OK;
+    LPWSTR     pszPath = NULL;
+    LPWSTR     pszFullPath = NULL;
+    STRU       strRelativePath;
+    DWORD      dwBufferSize = 0;
+    FILE       *file = NULL;
+
+    DBG_ASSERT(pstrCommandLine);
+
+    if (!m_struCommandLine.IsEmpty() &&
+        pstrCommandLine == (&m_struCommandLine))
+    {
+        // already set up the commandline string, skip
+        goto Finished;
+    }
+
+    pszPath = m_ProcessPath.QueryStr();
+
+    if ((wcsstr(pszPath, L":") == NULL) && (wcsstr(pszPath, L"%") == NULL))
+    {
+        // let's check whether it is a relative path
+        if (FAILED(hr = strRelativePath.Copy(m_struPhysicalPath.QueryStr())) ||
+            FAILED(hr = strRelativePath.Append(L"\\")) ||
+            FAILED(hr = strRelativePath.Append(pszPath)))
+        {
+            goto Finished;
+        }
+
+        dwBufferSize = strRelativePath.QueryCCH() + 1;
+        pszFullPath = new WCHAR[dwBufferSize];
+        if (pszFullPath == NULL)
+        {
+            hr = E_OUTOFMEMORY;
+            goto Finished;
+        }
+
+        if (_wfullpath(pszFullPath,
+            strRelativePath.QueryStr(),
+            dwBufferSize) == NULL)
+        {
+            hr = HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
+            goto Finished;
+        }
+
+        if ((file = _wfsopen(pszFullPath, L"r", _SH_DENYNO)) != NULL)
+        {
+            fclose(file);
+            pszPath = pszFullPath;
+        }
+    }
+    if (FAILED(hr = pstrCommandLine->Copy(pszPath)) ||
+        FAILED(hr = pstrCommandLine->Append(L" ")) ||
+        FAILED(hr = pstrCommandLine->Append(m_Arguments.QueryStr())))
+    {
+        goto Finished;
+    }
+
+Finished:
+    if (pszFullPath != NULL)
+    {
+        delete pszFullPath;
+    }
+    return hr;
+}
+
+HRESULT
+SERVER_PROCESS::PostStartCheck(
+    VOID
+)
+{
+    HRESULT hr = S_OK;
+
+    BOOL    fReady = FALSE;
+    BOOL    fProcessMatch = FALSE;
+    BOOL    fDebuggerAttached = FALSE;
+    DWORD   dwTickCount = 0;
+    DWORD   dwTimeDifference = 0;
+    DWORD   dwActualProcessId = 0;
+    INT     iChildProcessIndex = -1;
+    STACK_STRU(strEventMsg, 256);
+
+    if (CheckRemoteDebuggerPresent(m_hProcessHandle, &fDebuggerAttached) == 0)
+    {
+        // some error occurred  - assume debugger is not attached;
+        fDebuggerAttached = FALSE;
+    }
+
+    dwTickCount = GetTickCount();
+    do
+    {
+        DWORD processStatus = 0;
+        if (GetExitCodeProcess(m_hProcessHandle, &processStatus))
+        {
+            // make sure the process is still running
+            if (processStatus != STILL_ACTIVE)
+            {
+                // double check
+                if (GetExitCodeProcess(m_hProcessHandle, &processStatus) && processStatus != STILL_ACTIVE)
+                {
+                    hr = E_APPLICATION_ACTIVATION_EXEC_FAILURE;
+                    strEventMsg.SafeSnwprintf(
+                        ASPNETCORE_EVENT_PROCESS_START_STATUS_ERROR_MSG,
+                        m_struAppFullPath.QueryStr(),
+                        m_struPhysicalPath.QueryStr(),
+                        m_struCommandLine.QueryStr(),
+                        hr,
+                        m_dwProcessId,
+                        processStatus);
+                    goto Finished;
+                }
+            }
+        }
+        //
+        // dwActualProcessId will be set only when NsiAPI(GetExtendedTcpTable) is supported
+        //
+        hr = CheckIfServerIsUp(m_dwPort, &dwActualProcessId, &fReady);
+        fDebuggerAttached = IsDebuggerIsAttached();
+
+        if (!fReady)
+        {
+            Sleep(250);
+        }
+
+        dwTimeDifference = (GetTickCount() - dwTickCount);
+    } while (fReady == FALSE &&
+        ((dwTimeDifference < m_dwStartupTimeLimitInMS) || fDebuggerAttached));
+
+    if (!fReady)
+    {
+        hr = E_APPLICATION_ACTIVATION_TIMED_OUT;
+        goto Finished;
+    }
+
+    // register call back with the created process
+    if (FAILED(hr = RegisterProcessWait(&m_hProcessWaitHandle, m_hProcessHandle)))
+    {
+        goto Finished;
+    }
+
+    //
+    // check if debugger is attached after startupTimeout.
+    //
+    if (!fDebuggerAttached &&
+        CheckRemoteDebuggerPresent(m_hProcessHandle, &fDebuggerAttached) == 0)
+    {
+        // some error occurred  - assume debugger is not attached;
+        fDebuggerAttached = FALSE;
+    }
+
+    if (!g_fNsiApiNotSupported)
+    {
+        //
+        // NsiAPI(GetExtendedTcpTable) is supported. we should check whether processIds matche
+        //
+        if (dwActualProcessId == m_dwProcessId)
+        {
+            m_dwListeningProcessId = m_dwProcessId;
+            fProcessMatch = TRUE;
+        }
+
+        if (!fProcessMatch)
+        {
+            // could be the scenario that backend creates child process
+            if (FAILED(hr = GetChildProcessHandles()))
+            {
+                goto Finished;
+            }
+
+            for (DWORD i = 0; i < m_cChildProcess; ++i)
+            {
+                // a child process listen on the assigned port
+                if (dwActualProcessId == m_dwChildProcessIds[i])
+                {
+                    m_dwListeningProcessId = m_dwChildProcessIds[i];
+                    fProcessMatch = TRUE;
+
+                    if (m_hChildProcessHandles[i] != NULL)
+                    {
+                        if (fDebuggerAttached == FALSE &&
+                            CheckRemoteDebuggerPresent(m_hChildProcessHandles[i], &fDebuggerAttached) == 0)
+                        {
+                            // some error occurred  - assume debugger is not attached;
+                            fDebuggerAttached = FALSE;
+                        }
+
+                        if (FAILED(hr = RegisterProcessWait(&m_hChildProcessWaitHandles[i],
+                            m_hChildProcessHandles[i])))
+                        {
+                            goto Finished;
+                        }
+                        iChildProcessIndex = i;
+                    }
+                    break;
+                }
+            }
+        }
+
+        if(!fProcessMatch)
+        {
+            //
+            // process that we created is not listening
+            // on the port we specified.
+            //
+            fReady = FALSE;
+            hr = HRESULT_FROM_WIN32(ERROR_CREATE_FAILED);
+            strEventMsg.SafeSnwprintf(
+                ASPNETCORE_EVENT_PROCESS_START_WRONGPORT_ERROR_MSG,
+                m_struAppFullPath.QueryStr(),
+                m_struPhysicalPath.QueryStr(),
+                m_struCommandLine.QueryStr(),
+                m_dwPort,
+                hr);
+            goto Finished;
+        }
+    }
+
+    if (!fReady)
+    {
+        //
+        // hr is already set by CheckIfServerIsUp
+        //
+        if (dwTimeDifference >= m_dwStartupTimeLimitInMS)
+        {
+            hr = HRESULT_FROM_WIN32(ERROR_TIMEOUT);
+            strEventMsg.SafeSnwprintf(
+                ASPNETCORE_EVENT_PROCESS_START_NOTREADY_ERROR_MSG,
+                m_struAppFullPath.QueryStr(),
+                m_struPhysicalPath.QueryStr(),
+                m_struCommandLine.QueryStr(),
+                m_dwPort,
+                hr);
+        }
+        goto Finished;
+    }
+
+    if (iChildProcessIndex >= 0)
+    {
+        //
+        // final check to make sure child process listening on HTTP is still UP
+        // This is needed because, the child process might have crashed/exited between
+        // the previous call to checkIfServerIsUp and RegisterProcessWait
+        // and we would not know about it.
+        //
+
+        hr = CheckIfServerIsUp(m_dwPort, &dwActualProcessId, &fReady);
+
+        if ((FAILED(hr) || fReady == FALSE))
+        {
+            strEventMsg.SafeSnwprintf(
+                ASPNETCORE_EVENT_PROCESS_START_NOTREADY_ERROR_MSG,
+                m_struAppFullPath.QueryStr(),
+                m_struPhysicalPath.QueryStr(),
+                m_struCommandLine.QueryStr(),
+                m_dwPort,
+                hr);
+            goto Finished;
+        }
+    }
+
+    //
+    // ready to mark the server process ready but before this,
+    // create and initialize the FORWARDER_CONNECTION
+    //
+    if (m_pForwarderConnection == NULL)
+    {
+        m_pForwarderConnection = new FORWARDER_CONNECTION();
+        if (m_pForwarderConnection == NULL)
+        {
+            hr = E_OUTOFMEMORY;
+            goto Finished;
+        }
+
+        hr = m_pForwarderConnection->Initialize(m_dwPort);
+        if (FAILED(hr))
+        {
+            goto Finished;
+        }
+    }
+
+    if (!g_fNsiApiNotSupported)
+    {
+        m_hListeningProcessHandle = OpenProcess(SYNCHRONIZE | PROCESS_TERMINATE | PROCESS_DUP_HANDLE,
+                                                FALSE,
+                                                m_dwListeningProcessId);
+    }
+
+    //
+    // mark server process as Ready
+    //
+    m_fReady = TRUE;
+
+Finished:
+    if (FAILED(hr))
+    {
+        if (m_pForwarderConnection != NULL)
+        {
+            m_pForwarderConnection->DereferenceForwarderConnection();
+            m_pForwarderConnection = NULL;
+        }
+
+        if (!strEventMsg.IsEmpty())
+        {
+            UTILITY::LogEvent(
+                g_hEventLog,
+                EVENTLOG_WARNING_TYPE,
+                ASPNETCORE_EVENT_PROCESS_START_ERROR,
+                strEventMsg.QueryStr());
+        }
+    }
+    return hr;
+}
+
+HRESULT
+SERVER_PROCESS::StartProcess(
+    VOID
+)
+{
+    HRESULT                 hr = S_OK;
+    PROCESS_INFORMATION     processInformation = {0};
+    STARTUPINFOW            startupInfo = {0};
+    DWORD                   dwRetryCount = 2; // should we allow customer to config it
+    DWORD                   dwCreationFlags = 0;
+    MULTISZ                 mszNewEnvironment;
+    ENVIRONMENT_VAR_HASH    *pHashTable = NULL;
+    PWSTR                   pStrStage = NULL;
+    BOOL                    fCriticalError = FALSE;
+    GetStartupInfoW(&startupInfo);
+
+    //
+    // setup stdout and stderr handles to our stdout handle only if
+    // the handle is valid.
+    //
+    SetupStdHandles(&startupInfo);
+
+    while (dwRetryCount > 0)
+    {
+        m_dwPort = 0;
+        dwRetryCount--;
+        //
+        // generate process command line.
+        //
+        if (FAILED(hr = SetupCommandLine(&m_struCommandLine)))
+        {
+            pStrStage = L"SetupCommandLine";
+            goto Failure;
+        }
+
+        if (FAILED(hr = ENVIRONMENT_VAR_HELPERS::InitEnvironmentVariablesTable(
+            m_pEnvironmentVarTable,
+            m_fWindowsAuthEnabled,
+            m_fBasicAuthEnabled,
+            m_fAnonymousAuthEnabled,
+            &pHashTable)))
+        {
+            pStrStage = L"InitEnvironmentVariablesTable";
+            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
+        //
+        if (FAILED(hr = SetupListenPort(pHashTable, &fCriticalError)))
+        {
+            pStrStage = L"SetupListenPort";
+            goto Failure;
+        }
+
+        //
+        // get app path
+        //
+        if (FAILED(hr = SetupAppPath(pHashTable)))
+        {
+            pStrStage = L"SetupAppPath";
+            goto Failure;
+        }
+
+        //
+        // generate new guid for each process
+        //
+        if (FAILED(hr = SetupAppToken(pHashTable)))
+        {
+            pStrStage = L"SetupAppToken";
+            goto Failure;
+        }
+
+        //
+        // setup environment variables for new process
+        //
+        if (FAILED(hr = OutputEnvironmentVariables(&mszNewEnvironment, pHashTable)))
+        {
+            pStrStage = L"OutputEnvironmentVariables";
+            goto Failure;
+        }
+
+        dwCreationFlags = CREATE_NO_WINDOW |
+            CREATE_UNICODE_ENVIRONMENT |
+            CREATE_SUSPENDED |
+            CREATE_NEW_PROCESS_GROUP;
+
+        if (!CreateProcessW(
+            NULL,                   // applicationName
+            m_struCommandLine.QueryStr(),
+            NULL,                   // processAttr
+            NULL,                   // threadAttr
+            TRUE,                   // inheritHandles
+            dwCreationFlags,
+            mszNewEnvironment.QueryStr(),
+            m_struPhysicalPath.QueryStr(), // currentDir
+            &startupInfo,
+            &processInformation))
+        {
+            pStrStage = L"CreateProcessW";
+            hr = HRESULT_FROM_WIN32(GetLastError());
+            goto Failure;
+        }
+
+        m_hProcessHandle = processInformation.hProcess;
+        m_dwProcessId = processInformation.dwProcessId;
+
+        if (FAILED(hr = SetupJobObject()))
+        {
+            pStrStage = L"SetupJobObject";
+            goto Failure;
+        }
+
+        if (m_hJobObject != NULL)
+        {
+            if (!AssignProcessToJobObject(m_hJobObject, m_hProcessHandle))
+            {
+                hr = HRESULT_FROM_WIN32(GetLastError());
+                if (hr != HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED))
+                {
+                    pStrStage = L"AssignProcessToJobObject";
+                    goto Failure;
+                }
+            }
+        }
+
+        if (ResumeThread(processInformation.hThread) == -1)
+        {
+            pStrStage = L"ResumeThread";
+            hr = HRESULT_FROM_WIN32(GetLastError());
+            goto Failure;
+        }
+
+        //
+        // need to make sure the server is up and listening on the port specified.
+        //
+        if (FAILED(hr = PostStartCheck()))
+        {
+            pStrStage = L"PostStartCheck";
+            goto Failure;
+        }
+
+        // Backend process starts successfully. Set retry counter to 0
+        dwRetryCount = 0;
+
+        UTILITY::LogEventF(g_hEventLog,
+            EVENTLOG_INFORMATION_TYPE,
+            ASPNETCORE_EVENT_PROCESS_START_SUCCESS,
+            ASPNETCORE_EVENT_PROCESS_START_SUCCESS_MSG,
+            m_struAppFullPath.QueryStr(),
+            m_dwProcessId,
+            m_dwListeningProcessId,
+            m_dwPort);
+
+        goto Finished;
+
+    Failure:
+        if (fCriticalError)
+        {
+            // Critical error, no retry need to avoid wasting resource and polluting log
+            dwRetryCount = 0;
+        }
+
+        UTILITY::LogEventF(g_hEventLog,
+            EVENTLOG_WARNING_TYPE,
+            ASPNETCORE_EVENT_PROCESS_START_ERROR,
+            ASPNETCORE_EVENT_PROCESS_START_ERROR_MSG,
+            m_struAppFullPath.QueryStr(),
+            m_struPhysicalPath.QueryStr(),
+            m_struCommandLine.QueryStr(),
+            pStrStage,
+            hr,
+            m_dwPort,
+            dwRetryCount);
+
+        if (processInformation.hThread != NULL)
+        {
+            CloseHandle(processInformation.hThread);
+            processInformation.hThread = NULL;
+        }
+
+        if (pHashTable != NULL)
+        {
+            pHashTable->Clear();
+            delete pHashTable;
+            pHashTable = NULL;
+        }
+
+        CleanUp();
+    }
+
+Finished:
+    if (FAILED(hr) || m_fReady == FALSE)
+    {
+        if (m_hStdoutHandle != NULL)
+        {
+            if (m_hStdoutHandle != INVALID_HANDLE_VALUE)
+            {
+                CloseHandle(m_hStdoutHandle);
+            }
+            m_hStdoutHandle = NULL;
+        }
+
+        if (m_fStdoutLogEnabled)
+        {
+            m_Timer.CancelTimer();
+        }
+
+        UTILITY::LogEventF(g_hEventLog,
+            EVENTLOG_ERROR_TYPE,
+            ASPNETCORE_EVENT_PROCESS_START_FAILURE,
+            ASPNETCORE_EVENT_PROCESS_START_FAILURE_MSG,
+            m_struAppFullPath.QueryStr(),
+            m_struPhysicalPath.QueryStr(),
+            m_struCommandLine.QueryStr(),
+            m_dwPort);
+    }
+    return hr;
+}
+
+HRESULT
+SERVER_PROCESS::SetWindowsAuthToken(
+    HANDLE hToken,
+    LPHANDLE pTargetTokenHandle
+)
+{
+    HRESULT hr = S_OK;
+
+    if (m_hListeningProcessHandle != NULL && m_hListeningProcessHandle != INVALID_HANDLE_VALUE)
+    {
+        if (!DuplicateHandle( GetCurrentProcess(),
+                             hToken,
+                             m_hListeningProcessHandle,
+                             pTargetTokenHandle,
+                             0,
+                             FALSE,
+                             DUPLICATE_SAME_ACCESS ))
+        {
+            hr = HRESULT_FROM_WIN32(GetLastError());
+            goto Finished;
+        }
+    }
+
+Finished:
+
+    return hr;
+}
+
+HRESULT
+SERVER_PROCESS::SetupStdHandles(
+    LPSTARTUPINFOW pStartupInfo
+)
+{
+    HRESULT                 hr = S_OK;
+    SYSTEMTIME              systemTime;
+    SECURITY_ATTRIBUTES     saAttr = { 0 };
+
+    STRU                    struPath;
+
+    DBG_ASSERT(pStartupInfo);
+
+    if (!m_fStdoutLogEnabled)
+    {
+        pStartupInfo->dwFlags = STARTF_USESTDHANDLES;
+        pStartupInfo->hStdInput = INVALID_HANDLE_VALUE;
+        pStartupInfo->hStdError = INVALID_HANDLE_VALUE;
+        pStartupInfo->hStdOutput = INVALID_HANDLE_VALUE;
+        return hr;
+    }
+    if (m_hStdoutHandle != NULL && m_hStdoutHandle != INVALID_HANDLE_VALUE)
+    {
+        if (!CloseHandle(m_hStdoutHandle))
+        {
+            hr = HRESULT_FROM_WIN32(GetLastError());
+            goto Finished;
+        }
+        m_hStdoutHandle = NULL;
+    }
+
+    hr = UTILITY::ConvertPathToFullPath(
+                 m_struLogFile.QueryStr(),
+                 m_struPhysicalPath.QueryStr(),
+                 &struPath);
+    if (FAILED(hr))
+    {
+        goto Finished;
+    }
+
+    GetSystemTime(&systemTime);
+    hr = m_struFullLogFile.SafeSnwprintf(L"%s_%d%02d%02d%02d%02d%02d_%d.log",
+        struPath.QueryStr(),
+        systemTime.wYear,
+        systemTime.wMonth,
+        systemTime.wDay,
+        systemTime.wHour,
+        systemTime.wMinute,
+        systemTime.wSecond,
+        GetCurrentProcessId());
+    if (FAILED(hr))
+    {
+        goto Finished;
+    }
+
+    hr = UTILITY::EnsureDirectoryPathExist(struPath.QueryStr());
+    if (FAILED(hr))
+    {
+        goto Finished;
+    }
+
+    saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
+    saAttr.bInheritHandle = TRUE;
+    saAttr.lpSecurityDescriptor = NULL;
+
+    m_hStdoutHandle = CreateFileW(m_struFullLogFile.QueryStr(),
+        FILE_WRITE_DATA,
+        FILE_SHARE_READ,
+        &saAttr,
+        CREATE_ALWAYS,
+        FILE_ATTRIBUTE_NORMAL,
+        NULL);
+
+    if (m_hStdoutHandle == INVALID_HANDLE_VALUE)
+    {
+        hr = HRESULT_FROM_WIN32(GetLastError());
+        goto Finished;
+    }
+
+    pStartupInfo->dwFlags = STARTF_USESTDHANDLES;
+    pStartupInfo->hStdInput = INVALID_HANDLE_VALUE;
+    pStartupInfo->hStdError = m_hStdoutHandle;
+    pStartupInfo->hStdOutput = m_hStdoutHandle;
+    // start timer to open and close handles regularly.
+    m_Timer.InitializeTimer(STTIMER::TimerCallback, &m_struFullLogFile, 3000, 3000);
+
+Finished:
+    if (FAILED(hr))
+    {
+        pStartupInfo->dwFlags = STARTF_USESTDHANDLES;
+        pStartupInfo->hStdInput = INVALID_HANDLE_VALUE;
+        pStartupInfo->hStdError = INVALID_HANDLE_VALUE;
+        pStartupInfo->hStdOutput = INVALID_HANDLE_VALUE;
+
+        if (m_fStdoutLogEnabled)
+        {
+            // Log the error
+            UTILITY::LogEventF(g_hEventLog,
+                EVENTLOG_WARNING_TYPE,
+                ASPNETCORE_EVENT_CONFIG_ERROR,
+                ASPNETCORE_EVENT_INVALID_STDOUT_LOG_FILE_MSG,
+                m_struFullLogFile.IsEmpty()? m_struLogFile.QueryStr() : m_struFullLogFile.QueryStr(),
+                hr);
+        }
+        // The log file was not created yet in case of failure. No need to clean it
+        m_struFullLogFile.Reset();
+    }
+    return hr;
+}
+
+HRESULT
+SERVER_PROCESS::CheckIfServerIsUp(
+    _In_  DWORD       dwPort,
+    _Out_ DWORD     * pdwProcessId,
+    _Out_ BOOL      * pfReady
+)
+{
+    HRESULT                 hr = S_OK;
+    DWORD                   dwResult = ERROR_INSUFFICIENT_BUFFER;
+    MIB_TCPTABLE_OWNER_PID *pTCPInfo = NULL;
+    MIB_TCPROW_OWNER_PID   *pOwner = NULL;
+    DWORD                   dwSize = 1000; // Initial size for pTCPInfo buffer
+    int                     iResult = 0;
+    SOCKADDR_IN             sockAddr;
+    SOCKET                  socketCheck = INVALID_SOCKET;
+
+    DBG_ASSERT(pfReady);
+    DBG_ASSERT(pdwProcessId);
+
+    *pfReady = FALSE;
+    //
+    // it's OK for us to return processID 0 in case we cannot detect the real one
+    //
+    *pdwProcessId = 0;
+
+    if (!g_fNsiApiNotSupported)
+    {
+        while (dwResult == ERROR_INSUFFICIENT_BUFFER)
+        {
+            // Increase the buffer size with additional space, MIB_TCPROW 20 bytes
+            // New entries may be added by other processes before calling GetExtendedTcpTable
+            dwSize += 200;
+
+            if (pTCPInfo != NULL)
+            {
+                HeapFree(GetProcessHeap(), 0, pTCPInfo);
+            }
+
+            pTCPInfo = (MIB_TCPTABLE_OWNER_PID*)HeapAlloc(GetProcessHeap(), 0, dwSize);
+            if (pTCPInfo == NULL)
+            {
+                hr = E_OUTOFMEMORY;
+                goto Finished;
+            }
+
+            dwResult = GetExtendedTcpTable(pTCPInfo,
+                &dwSize,
+                FALSE,
+                AF_INET,
+                TCP_TABLE_OWNER_PID_LISTENER,
+                0);
+
+            if (dwResult != NO_ERROR && dwResult != ERROR_INSUFFICIENT_BUFFER)
+            {
+                hr = HRESULT_FROM_WIN32(dwResult);
+                goto Finished;
+            }
+        }
+
+        // iterate pTcpInfo struct to find PID/PORT entry
+        for (DWORD dwLoop = 0; dwLoop < pTCPInfo->dwNumEntries; dwLoop++)
+        {
+            pOwner = &pTCPInfo->table[dwLoop];
+            if (ntohs((USHORT)pOwner->dwLocalPort) == dwPort)
+            {
+                *pdwProcessId = pOwner->dwOwningPid;
+                *pfReady = TRUE;
+                break;
+            }
+        }
+    }
+    else
+    {
+        //
+        // We have to open socket to ping the service
+        //
+        socketCheck = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+
+        if (socketCheck == INVALID_SOCKET)
+        {
+            hr = HRESULT_FROM_WIN32(WSAGetLastError());
+            goto Finished;
+        }
+
+        sockAddr.sin_family = AF_INET;
+        if (!inet_pton(AF_INET, LOCALHOST, &(sockAddr.sin_addr)))
+        {
+            hr = HRESULT_FROM_WIN32(WSAGetLastError());
+            goto Finished;
+        }
+
+        //sockAddr.sin_addr.s_addr = inet_addr( LOCALHOST );
+        sockAddr.sin_port = htons((u_short)dwPort);
+
+        //
+        // Connect to server.
+        // if connection fails, socket is not closed, we reuse the same socket
+        // while retrying
+        //
+        iResult = connect(socketCheck, (SOCKADDR *)&sockAddr, sizeof(sockAddr));
+        if (iResult == SOCKET_ERROR)
+        {
+            hr = HRESULT_FROM_WIN32(WSAGetLastError());
+            if (hr == HRESULT_FROM_WIN32(WSAECONNREFUSED))
+            {
+                // WSAECONNREFUSED means no application listen on the given port.
+                // This is not a failure. Reset the hresult to S_OK and return fReady to false
+                hr = S_OK;
+            }
+            goto Finished;
+        }
+        *pfReady = TRUE;
+    }
+
+Finished:
+
+    if (socketCheck != INVALID_SOCKET)
+    {
+        iResult = closesocket(socketCheck);
+        if (iResult == SOCKET_ERROR)
+        {
+            hr = HRESULT_FROM_WIN32(WSAGetLastError());
+        }
+        socketCheck = INVALID_SOCKET;
+    }
+
+    if (pTCPInfo != NULL)
+    {
+        HeapFree(GetProcessHeap(), 0, pTCPInfo);
+        pTCPInfo = NULL;
+    }
+
+    return hr;
+}
+
+// send signal to the process to let it gracefully shutdown
+// if the process cannot shutdown within given time, terminate it
+VOID
+SERVER_PROCESS::SendSignal(
+    VOID
+)
+{
+    HRESULT hr      = S_OK;
+    HANDLE  hThread = NULL;
+
+    ReferenceServerProcess();
+
+    m_hShutdownHandle = OpenProcess(SYNCHRONIZE | PROCESS_TERMINATE, FALSE, m_dwProcessId);
+
+    if (m_hShutdownHandle == NULL)
+    {
+        // since we cannot open the process. let's terminate the process
+        hr = HRESULT_FROM_WIN32(GetLastError());
+        goto Finished;
+    }
+
+    hThread = CreateThread(
+        NULL,       // default security attributes
+        0,          // default stack size
+        (LPTHREAD_START_ROUTINE)SendShutDownSignal,
+        this,       // thread function arguments
+        0,          // default creation flags
+        NULL);      // receive thread identifier
+
+    if (hThread == NULL)
+    {
+        hr = HRESULT_FROM_WIN32(GetLastError());
+        goto Finished;
+    }
+
+    if (WaitForSingleObject(m_hShutdownHandle, m_dwShutdownTimeLimitInMS) != WAIT_OBJECT_0)
+    {
+        hr = HRESULT_FROM_WIN32(ERROR_TIMEOUT);
+        goto Finished;
+    }
+    // thread should already exit
+    CloseHandle(hThread);
+    hThread = NULL;
+
+Finished:
+    if (hThread != NULL)
+    {
+        // if the send shutdown message thread is still running, terminate it
+        DWORD dwThreadStatus = 0;
+        if (GetExitCodeThread(hThread, &dwThreadStatus)!= 0 && dwThreadStatus == STILL_ACTIVE)
+        {
+            TerminateThread(hThread, STATUS_CONTROL_C_EXIT);
+        }
+        CloseHandle(hThread);
+        hThread = NULL;
+    }
+
+    if (FAILED(hr))
+    {
+        TerminateBackendProcess();
+    }
+
+    if (m_hShutdownHandle != NULL && m_hShutdownHandle != INVALID_HANDLE_VALUE)
+    {
+        CloseHandle(m_hShutdownHandle);
+        m_hShutdownHandle = NULL;
+    }
+
+    DereferenceServerProcess();
+}
+
+
+//
+// StopProcess is only called if process crashes OR if the process
+// creation failed and calling this counts towards RapidFailCounts.
+//
+VOID
+SERVER_PROCESS::StopProcess(
+    VOID
+)
+{
+    m_fReady = FALSE;
+
+    m_pProcessManager->IncrementRapidFailCount();
+
+    for (INT i=0; i<MAX_ACTIVE_CHILD_PROCESSES; ++i)
+    {
+        if (m_hChildProcessHandles[i] != NULL)
+        {
+            if (m_hChildProcessHandles[i] != INVALID_HANDLE_VALUE)
+            {
+                TerminateProcess(m_hChildProcessHandles[i], 0);
+                CloseHandle(m_hChildProcessHandles[i]);
+            }
+            m_hChildProcessHandles[i] = NULL;
+            m_dwChildProcessIds[i] = 0;
+        }
+    }
+
+    if (m_hProcessHandle != NULL)
+    {
+        if (m_hProcessHandle != INVALID_HANDLE_VALUE)
+        {
+            TerminateProcess(m_hProcessHandle, 0);
+            CloseHandle(m_hProcessHandle);
+        }
+        m_hProcessHandle = NULL;
+    }
+}
+
+BOOL
+SERVER_PROCESS::IsDebuggerIsAttached(
+    VOID
+)
+{
+    HRESULT                             hr = S_OK;
+    PJOBOBJECT_BASIC_PROCESS_ID_LIST    processList = NULL;
+    DWORD                               dwPid = 0;
+    DWORD                               dwWorkerProcessPid = 0;
+    DWORD                               cbNumBytes = 1024;
+    DWORD                               dwRetries = 0;
+    DWORD                               dwError = NO_ERROR;
+    BOOL                                fDebuggerPresent = FALSE;
+
+    dwWorkerProcessPid = GetCurrentProcessId();
+
+    do
+    {
+        dwError = NO_ERROR;
+
+        if (processList != NULL)
+        {
+            HeapFree(GetProcessHeap(), 0, processList);
+            processList = NULL;
+
+            // resize
+            cbNumBytes = cbNumBytes * 2;
+        }
+
+        processList = (PJOBOBJECT_BASIC_PROCESS_ID_LIST) HeapAlloc(
+                            GetProcessHeap(),
+                            0,
+                            cbNumBytes
+                            );
+        if (processList == NULL)
+        {
+            hr = E_OUTOFMEMORY;
+            goto Finished;
+        }
+
+        RtlZeroMemory(processList, cbNumBytes);
+
+        if (!QueryInformationJobObject(
+                m_hJobObject,
+                JobObjectBasicProcessIdList,
+                processList,
+                cbNumBytes,
+                NULL))
+        {
+            dwError = GetLastError();
+            if (dwError != ERROR_MORE_DATA)
+            {
+                hr = HRESULT_FROM_WIN32(dwError);
+                goto Finished;
+            }
+        }
+
+    } while (dwRetries++ < 5 &&
+             processList != NULL &&
+             (processList->NumberOfAssignedProcesses > processList->NumberOfProcessIdsInList ||
+              processList->NumberOfProcessIdsInList == 0));
+
+    if (dwError == ERROR_MORE_DATA)
+    {
+        hr = E_OUTOFMEMORY;
+        // some error
+        goto Finished;
+    }
+
+    if (processList == NULL ||
+        (processList->NumberOfAssignedProcesses > processList->NumberOfProcessIdsInList ||
+        processList->NumberOfProcessIdsInList == 0))
+    {
+        hr = HRESULT_FROM_WIN32(ERROR_PROCESS_ABORTED);
+        // some error
+        goto Finished;
+    }
+
+    if (processList->NumberOfProcessIdsInList > MAX_ACTIVE_CHILD_PROCESSES)
+    {
+        hr = HRESULT_FROM_WIN32(ERROR_CREATE_FAILED);
+        goto Finished;
+    }
+
+    for (DWORD i=0; i<processList->NumberOfProcessIdsInList; i++)
+    {
+        dwPid = (DWORD)processList->ProcessIdList[i];
+        if (dwPid != dwWorkerProcessPid)
+        {
+            HANDLE hProcess = OpenProcess(
+                    PROCESS_QUERY_INFORMATION | SYNCHRONIZE | PROCESS_TERMINATE | PROCESS_DUP_HANDLE,
+                    FALSE,
+                    dwPid);
+
+            BOOL returnValue = CheckRemoteDebuggerPresent(hProcess, &fDebuggerPresent);
+            if (hProcess != NULL)
+            {
+                CloseHandle(hProcess);
+                hProcess = NULL;
+            }
+
+            if (!returnValue)
+            {
+                goto Finished;
+            }
+
+            if (fDebuggerPresent)
+            {
+                break;
+            }
+        }
+    }
+
+Finished:
+
+    if (processList != NULL)
+    {
+        HeapFree(GetProcessHeap(), 0, processList);
+    }
+
+    return fDebuggerPresent;
+}
+
+HRESULT
+SERVER_PROCESS::GetChildProcessHandles(
+    VOID
+)
+{
+    HRESULT                             hr = S_OK;
+    PJOBOBJECT_BASIC_PROCESS_ID_LIST    processList = NULL;
+    DWORD                               dwPid = 0;
+    DWORD                               dwWorkerProcessPid = 0;
+    DWORD                               cbNumBytes = 1024;
+    DWORD                               dwRetries = 0;
+    DWORD                               dwError = NO_ERROR;
+
+    dwWorkerProcessPid = GetCurrentProcessId();
+
+    do
+    {
+        dwError = NO_ERROR;
+
+        if (processList != NULL)
+        {
+            HeapFree(GetProcessHeap(), 0, processList);
+            processList = NULL;
+
+            // resize
+            cbNumBytes = cbNumBytes * 2;
+        }
+
+        processList = (PJOBOBJECT_BASIC_PROCESS_ID_LIST) HeapAlloc(
+                            GetProcessHeap(),
+                            0,
+                            cbNumBytes
+                            );
+        if (processList == NULL)
+        {
+            hr = E_OUTOFMEMORY;
+            goto Finished;
+        }
+
+        RtlZeroMemory(processList, cbNumBytes);
+
+        if (!QueryInformationJobObject(
+                m_hJobObject,
+                JobObjectBasicProcessIdList,
+                processList,
+                cbNumBytes,
+                NULL))
+        {
+            dwError = GetLastError();
+            if (dwError != ERROR_MORE_DATA)
+            {
+                hr = HRESULT_FROM_WIN32(dwError);
+                goto Finished;
+            }
+        }
+
+    } while (dwRetries++ < 5 &&
+             processList != NULL &&
+             (processList->NumberOfAssignedProcesses > processList->NumberOfProcessIdsInList || processList->NumberOfProcessIdsInList == 0));
+
+    if (dwError == ERROR_MORE_DATA)
+    {
+        hr = E_OUTOFMEMORY;
+        // some error
+        goto Finished;
+    }
+
+    if (processList == NULL || (processList->NumberOfAssignedProcesses > processList->NumberOfProcessIdsInList || processList->NumberOfProcessIdsInList == 0))
+    {
+        hr = HRESULT_FROM_WIN32(ERROR_PROCESS_ABORTED);
+        // some error
+        goto Finished;
+    }
+
+    if (processList->NumberOfProcessIdsInList > MAX_ACTIVE_CHILD_PROCESSES)
+    {
+        hr = HRESULT_FROM_WIN32(ERROR_CREATE_FAILED);
+        goto Finished;
+    }
+
+    for (DWORD i=0; i<processList->NumberOfProcessIdsInList; i++)
+    {
+        dwPid = (DWORD)processList->ProcessIdList[i];
+        if (dwPid != m_dwProcessId &&
+            dwPid != dwWorkerProcessPid )
+        {
+            m_hChildProcessHandles[m_cChildProcess] = OpenProcess(
+                                            PROCESS_QUERY_INFORMATION | SYNCHRONIZE | PROCESS_TERMINATE | PROCESS_DUP_HANDLE,
+                                            FALSE,
+                                            dwPid
+                                        );
+            m_dwChildProcessIds[m_cChildProcess] = dwPid;
+            m_cChildProcess ++;
+        }
+    }
+
+Finished:
+
+    if (processList != NULL)
+    {
+        HeapFree(GetProcessHeap(), 0, processList);
+    }
+
+    return hr;
+}
+
+HRESULT
+SERVER_PROCESS::StopAllProcessesInJobObject(
+        VOID
+)
+{
+    HRESULT                             hr = S_OK;
+    PJOBOBJECT_BASIC_PROCESS_ID_LIST    processList = NULL;
+    HANDLE                              hProcess = NULL;
+    DWORD                               dwWorkerProcessPid = 0;
+    DWORD                               cbNumBytes = 1024;
+    DWORD                               dwRetries = 0;
+
+    dwWorkerProcessPid = GetCurrentProcessId();
+
+    do
+    {
+        if (processList != NULL)
+        {
+            HeapFree(GetProcessHeap(), 0, processList);
+            processList = NULL;
+
+            // resize
+            cbNumBytes = cbNumBytes * 2;
+        }
+
+        processList = (PJOBOBJECT_BASIC_PROCESS_ID_LIST) HeapAlloc(
+                            GetProcessHeap(),
+                            0,
+                            cbNumBytes
+                            );
+        if (processList == NULL)
+        {
+            hr = E_OUTOFMEMORY;
+            goto Finished;
+        }
+
+        RtlZeroMemory(processList, cbNumBytes);
+
+        if (!QueryInformationJobObject(
+                m_hJobObject,
+                JobObjectBasicProcessIdList,
+                processList,
+                cbNumBytes,
+                NULL))
+        {
+            DWORD dwError = GetLastError();
+            if (dwError != ERROR_MORE_DATA)
+            {
+                hr = HRESULT_FROM_WIN32(dwError);
+                goto Finished;
+            }
+        }
+
+    } while (dwRetries++ < 5 &&
+             processList != NULL &&
+             (processList->NumberOfAssignedProcesses > processList->NumberOfProcessIdsInList || processList->NumberOfProcessIdsInList == 0));
+
+    if (processList == NULL || (processList->NumberOfAssignedProcesses > processList->NumberOfProcessIdsInList || processList->NumberOfProcessIdsInList == 0))
+    {
+        hr = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
+        // some error
+        goto Finished;
+    }
+
+    for (DWORD i=0; i<processList->NumberOfProcessIdsInList; i++)
+    {
+        if (dwWorkerProcessPid != (DWORD)processList->ProcessIdList[i])
+        {
+            hProcess = OpenProcess(PROCESS_TERMINATE,
+                                   FALSE,
+                                   (DWORD)processList->ProcessIdList[i]);
+            if (hProcess != NULL)
+            {
+                if (!TerminateProcess(hProcess, 1))
+                {
+                    hr = HRESULT_FROM_WIN32(GetLastError());
+                }
+                else
+                {
+                    WaitForSingleObject(hProcess, INFINITE);
+                }
+
+                if (hProcess != NULL)
+                {
+                    CloseHandle(hProcess);
+                    hProcess = NULL;
+                }
+            }
+        }
+    }
+
+Finished:
+
+    if (processList != NULL)
+    {
+        HeapFree(GetProcessHeap(), 0, processList);
+    }
+
+    return hr;
+}
+
+SERVER_PROCESS::SERVER_PROCESS() :
+    m_cRefs(1),
+    m_hProcessHandle(NULL),
+    m_hProcessWaitHandle(NULL),
+    m_dwProcessId(0),
+    m_cChildProcess(0),
+    m_fReady(FALSE),
+    m_lStopping(0L),
+    m_hStdoutHandle(NULL),
+    m_fStdoutLogEnabled(FALSE),
+    m_hJobObject(NULL),
+    m_pForwarderConnection(NULL),
+    m_dwListeningProcessId(0),
+    m_hListeningProcessHandle(NULL),
+    m_hShutdownHandle(NULL)
+{
+    //InterlockedIncrement(&g_dwActiveServerProcesses);
+    srand(GetTickCount());
+
+    for (INT i=0; i<MAX_ACTIVE_CHILD_PROCESSES; ++i)
+    {
+        m_dwChildProcessIds[i] = 0;
+        m_hChildProcessHandles[i] = NULL;
+        m_hChildProcessWaitHandles[i] = NULL;
+    }
+}
+
+VOID
+SERVER_PROCESS::CleanUp()
+{
+    if (m_hProcessWaitHandle != NULL)
+    {
+        UnregisterWait(m_hProcessWaitHandle);
+        m_hProcessWaitHandle = NULL;
+    }
+
+    for (INT i = 0; i<MAX_ACTIVE_CHILD_PROCESSES; ++i)
+    {
+        if (m_hChildProcessWaitHandles[i] != NULL)
+        {
+            UnregisterWait(m_hChildProcessWaitHandles[i]);
+            m_hChildProcessWaitHandles[i] = NULL;
+        }
+    }
+
+    if (m_hProcessHandle != NULL)
+    {
+        if (m_hProcessHandle != INVALID_HANDLE_VALUE)
+        {
+            TerminateProcess(m_hProcessHandle, 1);
+            CloseHandle(m_hProcessHandle);
+        }
+        m_hProcessHandle = NULL;
+    }
+
+    if (m_hListeningProcessHandle != NULL)
+    {
+        if (m_hListeningProcessHandle != INVALID_HANDLE_VALUE)
+        {
+            CloseHandle(m_hListeningProcessHandle);
+        }
+        m_hListeningProcessHandle = NULL;
+    }
+
+    for (INT i = 0; i<MAX_ACTIVE_CHILD_PROCESSES; ++i)
+    {
+        if (m_hChildProcessHandles[i] != NULL)
+        {
+            if (m_hChildProcessHandles[i] != INVALID_HANDLE_VALUE)
+            {
+                TerminateProcess(m_hChildProcessHandles[i], 1);
+                CloseHandle(m_hChildProcessHandles[i]);
+            }
+            m_hChildProcessHandles[i] = NULL;
+            m_dwChildProcessIds[i] = 0;
+        }
+    }
+
+    if (m_hJobObject != NULL)
+    {
+        if (m_hJobObject != INVALID_HANDLE_VALUE)
+        {
+            CloseHandle(m_hJobObject);
+        }
+        m_hJobObject = NULL;
+    }
+
+    if (m_pForwarderConnection != NULL)
+    {
+        m_pForwarderConnection->DereferenceForwarderConnection();
+        m_pForwarderConnection = NULL;
+    }
+
+}
+
+SERVER_PROCESS::~SERVER_PROCESS()
+{
+
+    CleanUp();
+
+    m_pEnvironmentVarTable = NULL;
+    // no need to free m_pEnvironmentVarTable, as it references to
+    // the same hash table hold by configuration.
+    // the hashtable memory will be freed once onfiguration got recycled
+
+    if (m_pProcessManager != NULL)
+    {
+        m_pProcessManager->DereferenceProcessManager();
+        m_pProcessManager = NULL;
+    }
+
+    if (m_hStdoutHandle != NULL)
+    {
+        if (m_hStdoutHandle != INVALID_HANDLE_VALUE)
+        {
+            CloseHandle(m_hStdoutHandle);
+        }
+        m_hStdoutHandle = NULL;
+    }
+
+    if (m_fStdoutLogEnabled)
+    {
+        m_Timer.CancelTimer();
+    }
+
+    if (!m_fStdoutLogEnabled && !m_struFullLogFile.IsEmpty())
+    {
+        WIN32_FIND_DATA fileData;
+        HANDLE handle = FindFirstFile(m_struFullLogFile.QueryStr(), &fileData);
+        if (handle != INVALID_HANDLE_VALUE &&
+            fileData.nFileSizeHigh == 0 &&
+            fileData.nFileSizeLow == 0)
+        {
+            FindClose(handle);
+            // no need to check whether the deletion succeeds
+            // as nothing can be done
+            DeleteFile(m_struFullLogFile.QueryStr());
+        }
+    }
+}
+
+//static
+VOID
+CALLBACK
+SERVER_PROCESS::ProcessHandleCallback(
+    _In_ PVOID  pContext,
+    _In_ BOOL
+)
+{
+    SERVER_PROCESS *pServerProcess = (SERVER_PROCESS*) pContext;
+    pServerProcess->HandleProcessExit();
+}
+
+HRESULT
+SERVER_PROCESS::RegisterProcessWait(
+    PHANDLE                 phWaitHandle,
+    HANDLE                  hProcessToWaitOn
+)
+{
+    HRESULT     hr = S_OK;
+    NTSTATUS    status = 0;
+
+    _ASSERT(phWaitHandle != NULL && *phWaitHandle == NULL);
+
+    *phWaitHandle = NULL;
+
+    // wait thread will dereference.
+    ReferenceServerProcess();
+
+    status = RegisterWaitForSingleObject(
+                phWaitHandle,
+                hProcessToWaitOn,
+                (WAITORTIMERCALLBACKFUNC)&ProcessHandleCallback,
+                this,
+                INFINITE,
+                WT_EXECUTEONLYONCE | WT_EXECUTEINWAITTHREAD
+                );
+
+    if (status < 0)
+    {
+        hr = HRESULT_FROM_NT(status);
+        goto Finished;
+    }
+
+Finished:
+
+    if (FAILED(hr))
+    {
+        *phWaitHandle = NULL;
+        DereferenceServerProcess();
+    }
+
+    return hr;
+}
+
+VOID
+SERVER_PROCESS::HandleProcessExit( VOID )
+{
+    BOOL        fReady = FALSE;
+    DWORD       dwProcessId = 0;
+
+    if (InterlockedCompareExchange(&m_lStopping, 1L, 0L) == 0L)
+    {
+        CheckIfServerIsUp(m_dwPort, &dwProcessId, &fReady);
+
+        if (!fReady)
+        {
+            UTILITY::LogEventF(
+                g_hEventLog,
+                EVENTLOG_INFORMATION_TYPE,
+                ASPNETCORE_EVENT_PROCESS_SHUTDOWN,
+                ASPNETCORE_EVENT_PROCESS_SHUTDOWN_MSG,
+                m_struAppFullPath.QueryStr(),
+                m_struPhysicalPath.QueryStr(),
+                m_dwProcessId,
+                m_dwPort);
+
+            m_pProcessManager->ShutdownProcess(this);
+        }
+
+        DereferenceServerProcess();
+    }
+}
+
+HRESULT
+SERVER_PROCESS::SendShutdownHttpMessage( VOID )
+{
+    HRESULT    hr = S_OK;
+    HINTERNET  hSession = NULL;
+    HINTERNET  hConnect = NULL;
+    HINTERNET  hRequest = NULL;
+
+    STACK_STRU(strHeaders, 256);
+    STRU       strAppToken;
+    STRU       strUrl;
+    DWORD      dwStatusCode = 0;
+    DWORD      dwSize = sizeof(dwStatusCode);
+
+    hSession = WinHttpOpen(L"",
+        WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
+        WINHTTP_NO_PROXY_NAME,
+        WINHTTP_NO_PROXY_BYPASS,
+        0);
+
+    if (hSession == NULL)
+    {
+        hr = HRESULT_FROM_WIN32(GetLastError());
+        goto Finished;
+    }
+
+    hConnect = WinHttpConnect(hSession,
+        L"127.0.0.1",
+        (USHORT)m_dwPort,
+        0);
+
+    if (hConnect == NULL)
+    {
+        hr = HRESULT_FROM_WIN32(GetLastError());
+        goto Finished;
+    }
+    if (m_struAppVirtualPath.QueryCCH() > 1)
+    {
+        // app path size is 1 means site root, i.e., "/"
+        // we don't want to add duplicated '/' to the request url
+        // otherwise the request will fail
+        strUrl.Copy(m_struAppVirtualPath);
+    }
+    strUrl.Append(L"/iisintegration");
+
+    hRequest = WinHttpOpenRequest(hConnect,
+        L"POST",
+        strUrl.QueryStr(),
+        NULL,
+        WINHTTP_NO_REFERER,
+        NULL,
+        0);
+
+    if (hRequest == NULL)
+    {
+        hr = HRESULT_FROM_WIN32(GetLastError());
+        goto Finished;
+    }
+
+    // set timeout
+    if (!WinHttpSetTimeouts(hRequest,
+        m_dwShutdownTimeLimitInMS,  // dwResolveTimeout
+        m_dwShutdownTimeLimitInMS,  // dwConnectTimeout
+        m_dwShutdownTimeLimitInMS,  // dwSendTimeout
+        m_dwShutdownTimeLimitInMS)) // dwReceiveTimeout
+    {
+        hr = HRESULT_FROM_WIN32(GetLastError());
+        goto Finished;
+    }
+
+    // set up the shutdown headers
+    if (FAILED(hr = strHeaders.Append(L"MS-ASPNETCORE-EVENT:shutdown \r\n")) ||
+        FAILED(hr = strAppToken.Append(L"MS-ASPNETCORE-TOKEN:")) ||
+        FAILED(hr = strAppToken.AppendA(m_straGuid.QueryStr())) ||
+        FAILED(hr = strHeaders.Append(strAppToken.QueryStr())))
+    {
+        goto Finished;
+    }
+
+    if (!WinHttpSendRequest(hRequest,
+        strHeaders.QueryStr(),  // pwszHeaders
+        strHeaders.QueryCCH(),  // dwHeadersLength
+        WINHTTP_NO_REQUEST_DATA,
+        0,   // dwOptionalLength
+        0,   // dwTotalLength
+        0))  // dwContext
+    {
+        hr = HRESULT_FROM_WIN32(GetLastError());
+        goto Finished;
+    }
+
+    if (!WinHttpReceiveResponse(hRequest , NULL))
+    {
+        hr = HRESULT_FROM_WIN32(GetLastError());
+        goto Finished;
+    }
+
+    if (!WinHttpQueryHeaders(hRequest,
+        WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER,
+        WINHTTP_HEADER_NAME_BY_INDEX,
+        &dwStatusCode,
+        &dwSize,
+        WINHTTP_NO_HEADER_INDEX))
+    {
+        hr = HRESULT_FROM_WIN32(GetLastError());
+        goto Finished;
+    }
+
+    if (dwStatusCode != 202)
+    {
+        // not expected http status
+        hr = E_FAIL;
+    }
+
+    // log
+    UTILITY::LogEventF(g_hEventLog,
+        EVENTLOG_INFORMATION_TYPE,
+        ASPNETCORE_EVENT_SENT_SHUTDOWN_HTTP_REQUEST,
+        ASPNETCORE_EVENT_SENT_SHUTDOWN_HTTP_REQUEST_MSG,
+        m_dwProcessId,
+        dwStatusCode);
+
+Finished:
+    if (hRequest)
+    {
+        WinHttpCloseHandle(hRequest);
+        hRequest = NULL;
+    }
+    if (hConnect)
+    {
+        WinHttpCloseHandle(hConnect);
+        hConnect = NULL;
+    }
+    if (hSession)
+    {
+        WinHttpCloseHandle(hSession);
+        hSession = NULL;
+    }
+    return hr;
+}
+
+//static
+VOID
+SERVER_PROCESS::SendShutDownSignal(
+    LPVOID lpParam
+)
+{
+    SERVER_PROCESS* pThis = static_cast<SERVER_PROCESS *>(lpParam);
+    DBG_ASSERT(pThis);
+    pThis->SendShutDownSignalInternal();
+}
+
+//
+// send shutdown message first, if fail then send
+// ctrl-c to the backend process to let it gracefully shutdown
+//
+VOID
+SERVER_PROCESS::SendShutDownSignalInternal(
+    VOID
+)
+{
+    ReferenceServerProcess();
+
+    if (FAILED(SendShutdownHttpMessage()))
+    {
+        //
+        // failed to send shutdown http message
+        // try send ctrl signal
+        //
+        HWND  hCurrentConsole = NULL;
+        BOOL  fFreeConsole = FALSE;
+        hCurrentConsole = GetConsoleWindow();
+        if (hCurrentConsole)
+        {
+            // free current console first, as we may have one, e.g., hostedwebcore case
+            fFreeConsole = FreeConsole();
+        }
+
+        if (AttachConsole(m_dwProcessId))
+        {
+            // As we called CreateProcess with CREATE_NEW_PROCESS_GROUP
+            // call ctrl-break instead of ctrl-c as child process ignores ctrl-c
+            if (!GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, m_dwProcessId))
+            {
+                // failed to send the ctrl signal. terminate the backend process immediately instead of waiting for timeout
+                TerminateBackendProcess();
+            }
+            FreeConsole();
+
+            if (fFreeConsole)
+            {
+                // IISExpress and hostedwebcore w3wp run as background process
+                // have to attach console back to ensure post app_offline scenario still works
+                AttachConsole(ATTACH_PARENT_PROCESS);
+            }
+        }
+        else
+        {
+            // terminate the backend process immediately instead of waiting for timeout
+            TerminateBackendProcess();
+        }
+    }
+
+    DereferenceServerProcess();
+}
+
+VOID
+SERVER_PROCESS::TerminateBackendProcess(
+    VOID
+)
+{
+    if (InterlockedCompareExchange(&m_lStopping, 1L, 0L) == 0L)
+    {
+        // backend process will be terminated, remove the waitcallback
+        if (m_hProcessWaitHandle != NULL)
+        {
+            UnregisterWait(m_hProcessWaitHandle);
+
+            // as we skipped process exit callback (ProcessHandleCallback),
+            // need to dereference the object otherwise memory leak
+            DereferenceServerProcess();
+
+            m_hProcessWaitHandle = NULL;
+        }
+
+        // cannot gracefully shutdown or timeout, terminate the process
+        if (m_hProcessHandle != NULL && m_hProcessHandle != INVALID_HANDLE_VALUE)
+        {
+            TerminateProcess(m_hProcessHandle, 0);
+            m_hProcessHandle = NULL;
+        }
+
+        // log a warning for ungraceful shutdown
+        UTILITY::LogEventF(g_hEventLog,
+            EVENTLOG_WARNING_TYPE,
+            ASPNETCORE_EVENT_GRACEFUL_SHUTDOWN_FAILURE,
+            ASPNETCORE_EVENT_GRACEFUL_SHUTDOWN_FAILURE_MSG,
+            m_dwProcessId);
+    }
+}
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/RequestHandler/outofprocess/serverprocess.h b/src/IISIntegration/src/AspNetCoreModuleV2/RequestHandler/outofprocess/serverprocess.h
new file mode 100644
index 0000000000000000000000000000000000000000..ff76297a1cc2357c9859b4efbb31ade3fcebac6d
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/RequestHandler/outofprocess/serverprocess.h
@@ -0,0 +1,279 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#pragma once
+
+#define MIN_PORT                                    1025
+#define MAX_PORT                                    48000
+#define MAX_RETRY                                   10
+#define MAX_ACTIVE_CHILD_PROCESSES                  16
+#define LOCALHOST                                   "127.0.0.1"
+#define ASPNETCORE_PORT_STR                         L"ASPNETCORE_PORT"
+#define ASPNETCORE_PORT_ENV_STR                     L"ASPNETCORE_PORT="
+#define ASPNETCORE_APP_PATH_ENV_STR                 L"ASPNETCORE_APPL_PATH="
+#define ASPNETCORE_APP_TOKEN_ENV_STR                L"ASPNETCORE_TOKEN="
+#define ASPNETCORE_APP_PATH_ENV_STR                 L"ASPNETCORE_APPL_PATH="
+
+class PROCESS_MANAGER;
+
+class SERVER_PROCESS
+{
+public:
+    SERVER_PROCESS();
+
+    HRESULT
+        Initialize(
+        _In_ PROCESS_MANAGER      *pProcessManager,
+        _In_ STRU                 *pszProcessExePath,
+        _In_ STRU                 *pszArguments,
+        _In_ DWORD                 dwStartupTimeLimitInMS,
+        _In_ DWORD                 dwShtudownTimeLimitInMS,
+        _In_ BOOL                  fWindowsAuthEnabled,
+        _In_ BOOL                  fBasicAuthEnabled,
+        _In_ BOOL                  fAnonymousAuthEnabled,
+        _In_ ENVIRONMENT_VAR_HASH* pEnvironmentVariables,
+        _In_ BOOL                  fStdoutLogEnabled,
+        _In_ BOOL                  fWebsocketsEnabled,
+        _In_ STRU                 *pstruStdoutLogFile,
+        _In_ STRU                 *pszAppPhysicalPath,
+        _In_ STRU                 *pszAppPath,
+        _In_ STRU                 *pszAppVirtualPath
+        );
+
+    HRESULT
+    StartProcess( VOID );
+
+    HRESULT
+    SetWindowsAuthToken(
+        _In_ HANDLE hToken,
+        _Out_ LPHANDLE pTargeTokenHandle
+    );
+
+    BOOL
+    IsReady(
+        VOID
+    )
+    {
+        return m_fReady;
+    }
+
+    VOID
+    StopProcess(
+        VOID
+    );
+
+    DWORD
+    GetPort()
+    {
+        return m_dwPort;
+    }
+
+    VOID
+    ReferenceServerProcess(
+        VOID
+    )
+    {
+        InterlockedIncrement(&m_cRefs);
+    }
+
+    VOID
+    DereferenceServerProcess(
+        VOID
+    )
+    {
+        _ASSERT(m_cRefs != 0 );
+        if (InterlockedDecrement(&m_cRefs) == 0)
+        {
+            delete this;
+        }
+    }
+
+    virtual 
+    ~SERVER_PROCESS();
+
+    static
+    VOID
+    CALLBACK
+    ProcessHandleCallback(
+        _In_ PVOID  pContext,
+        _In_ BOOL
+    );
+
+    VOID
+    HandleProcessExit(
+        VOID
+    );
+
+    FORWARDER_CONNECTION*
+    QueryWinHttpConnection(
+        VOID
+    )
+    {
+        return m_pForwarderConnection;
+    }
+
+    LPCSTR
+    QueryGuid()
+    {
+        return m_straGuid.QueryStr();
+    };
+
+    VOID
+    SendSignal( 
+        VOID
+    );
+
+private:
+    VOID
+    CleanUp();
+
+    HRESULT
+    SetupJobObject(
+       VOID
+    );
+
+    BOOL 
+    IsDebuggerIsAttached(
+        VOID
+    );
+
+    HRESULT
+    StopAllProcessesInJobObject(
+        VOID
+    );
+
+    HRESULT
+    SetupStdHandles(
+        _Inout_ LPSTARTUPINFOW pStartupInfo
+    );
+
+    HRESULT
+    CheckIfServerIsUp(
+        _In_  DWORD       dwPort,
+        _Out_ DWORD     * pdwProcessId,
+        _Out_ BOOL      * pfReady
+    );
+
+    HRESULT 
+    RegisterProcessWait(
+        _In_ PHANDLE phWaitHandle,
+        _In_ HANDLE  hProcessToWaitOn
+    );
+
+    HRESULT 
+    GetChildProcessHandles(
+        VOID
+    );
+
+    HRESULT
+    SetupListenPort(
+        ENVIRONMENT_VAR_HASH    *pEnvironmentVarTable,
+        BOOL                    *pfCriticalError
+    );
+
+    HRESULT
+    SetupAppPath(
+        ENVIRONMENT_VAR_HASH*   pEnvironmentVarTable
+    );
+
+    HRESULT
+    SetupAppToken(
+        ENVIRONMENT_VAR_HASH*   pEnvironmentVarTable
+    );
+
+    HRESULT
+    OutputEnvironmentVariables(
+        MULTISZ*                pmszOutput,
+        ENVIRONMENT_VAR_HASH*   pEnvironmentVarTable
+    );
+
+    HRESULT
+    SetupCommandLine(
+        STRU*    pstrCommandLine
+    );
+
+    HRESULT
+    PostStartCheck(
+        VOID
+    );
+
+    HRESULT
+    GetRandomPort(
+        DWORD*    pdwPickedPort,
+        DWORD     dwExcludedPort
+    );
+
+    static
+    VOID
+    SendShutDownSignal(
+        LPVOID lpParam
+        );
+
+    VOID
+    SendShutDownSignalInternal(
+        VOID
+    );
+
+    HRESULT
+    SendShutdownHttpMessage(
+        VOID
+    );
+
+    VOID
+    TerminateBackendProcess(
+        VOID
+    );
+
+    FORWARDER_CONNECTION   *m_pForwarderConnection;
+    BOOL                    m_fStdoutLogEnabled;
+    BOOL                    m_fWindowsAuthEnabled;
+    BOOL                    m_fBasicAuthEnabled;
+    BOOL                    m_fAnonymousAuthEnabled;
+    BOOL                    m_fWebsocketsEnabled;
+
+    STTIMER                 m_Timer;
+    SOCKET                  m_socket;
+
+    STRU                    m_struLogFile;
+    STRU                    m_struFullLogFile;
+    STRU                    m_ProcessPath;
+    STRU                    m_Arguments;
+    STRU                    m_struAppVirtualPath;  // e.g., '/' for site
+    STRU                    m_struAppFullPath;     // e.g.,  /LM/W3SVC/4/ROOT/Inproc
+    STRU                    m_struPhysicalPath;    // e.g., c:/test/mysite
+    STRU                    m_struPort;
+    STRU                    m_struCommandLine;
+
+    volatile LONG           m_lStopping;
+    volatile BOOL           m_fReady;
+    mutable LONG            m_cRefs;
+
+    DWORD                   m_dwPort;
+    DWORD                   m_dwStartupTimeLimitInMS;
+    DWORD                   m_dwShutdownTimeLimitInMS;
+    DWORD                   m_cChildProcess;
+    DWORD                   m_dwChildProcessIds[MAX_ACTIVE_CHILD_PROCESSES];
+    DWORD                   m_dwProcessId;
+    DWORD                   m_dwListeningProcessId;
+
+    STRA                    m_straGuid;
+
+    HANDLE                  m_hJobObject;
+    HANDLE                  m_hStdoutHandle;
+    //
+    // m_hProcessHandle is the handle to process this object creates.
+    //
+    HANDLE                  m_hProcessHandle;
+    HANDLE                  m_hListeningProcessHandle;
+    HANDLE                  m_hProcessWaitHandle;
+    HANDLE                  m_hShutdownHandle;
+    //
+    // m_hChildProcessHandle is the handle to process created by 
+    // m_hProcessHandle process if it does.
+    //
+    HANDLE                  m_hChildProcessHandles[MAX_ACTIVE_CHILD_PROCESSES];
+    HANDLE                  m_hChildProcessWaitHandles[MAX_ACTIVE_CHILD_PROCESSES];
+
+    PROCESS_MANAGER         *m_pProcessManager;
+    ENVIRONMENT_VAR_HASH    *m_pEnvironmentVarTable ;
+};
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/RequestHandler/outofprocess/websockethandler.cxx b/src/IISIntegration/src/AspNetCoreModuleV2/RequestHandler/outofprocess/websockethandler.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..ae7ecf697e5808e623ceeb575527934fdc8dd17c
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/RequestHandler/outofprocess/websockethandler.cxx
@@ -0,0 +1,1151 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+/*++
+
+Abstract:
+
+    Main Handler for websocket requests.
+
+    Initiates websocket connection to backend.
+    Uses WinHttp API's for backend connections,
+    and IIS Websocket API's for sending/receiving
+    websocket traffic.
+
+    Transfers data between the two IO endpoints.
+
+-----------------
+Read Loop Design
+-----------------
+When a read IO completes successfully on any endpoints, Asp.Net Core Module doesn't
+immediately issue the next read. The next read is initiated only after
+the read data is sent to the other endpoint. As soon as this send completes,
+we initiate the next IO. It should be noted that the send complete merely
+indicates the API completion from HTTP, and not necessarily over the network.
+
+This prevents the need for data buffering at the Asp.Net Core Module level.
+
+--*/
+
+#include "..\precomp.hxx"
+
+SRWLOCK WEBSOCKET_HANDLER::sm_RequestsListLock;
+
+LIST_ENTRY WEBSOCKET_HANDLER::sm_RequestsListHead;
+
+TRACE_LOG * WEBSOCKET_HANDLER::sm_pTraceLog;
+
+WEBSOCKET_HANDLER::WEBSOCKET_HANDLER() :
+    _pHttpContext(NULL),
+    _pWebSocketContext(NULL),
+    _hWebSocketRequest(NULL),
+    _pHandler(NULL),
+    _dwOutstandingIo(0),
+    _fCleanupInProgress(FALSE),
+    _fIndicateCompletionToIis(FALSE),
+    _fHandleClosed(FALSE),
+    _fReceivedCloseMsg(FALSE)
+{
+    DebugPrintf (ASPNETCORE_DEBUG_FLAG_INFO, "WEBSOCKET_HANDLER::WEBSOCKET_HANDLER");
+
+    InitializeCriticalSectionAndSpinCount(&_RequestLock, 1000);
+    InsertRequest();
+}
+
+VOID
+WEBSOCKET_HANDLER::Terminate(
+    VOID
+    )
+{
+    DebugPrintf (ASPNETCORE_DEBUG_FLAG_INFO, "WEBSOCKET_HANDLER::Terminate");
+    if (!_fHandleClosed)
+    {
+    RemoveRequest();
+    _fCleanupInProgress = TRUE;
+
+    if (_pHttpContext != NULL)
+    {
+        _pHttpContext->CancelIo();
+        _pHttpContext = NULL;
+    }
+    if (_hWebSocketRequest)
+    {
+        WinHttpCloseHandle(_hWebSocketRequest);
+        _hWebSocketRequest = NULL;
+    }
+
+    _pWebSocketContext = NULL;
+    DeleteCriticalSection(&_RequestLock);
+
+    delete this;
+    }
+}
+
+//static
+HRESULT
+WEBSOCKET_HANDLER::StaticInitialize(
+    BOOL   fEnableReferenceCountTracing
+    )
+/*++ 
+
+    Routine Description:
+
+    Initialize structures required for idle connection cleanup.
+
+--*/
+{
+    if (!g_fWebSocketSupported)
+    {
+        return S_OK;
+    }
+
+    if (fEnableReferenceCountTracing)
+    {
+        //
+        // If tracing is enabled, keep track of all websocket requests
+        // for debugging purposes.
+        //
+        InitializeListHead (&sm_RequestsListHead);
+        sm_pTraceLog = CreateRefTraceLog( 10000, 0 );
+    }
+
+    InitializeSRWLock(&sm_RequestsListLock);
+
+    return S_OK;
+}
+
+//static
+VOID
+WEBSOCKET_HANDLER::StaticTerminate(
+    VOID
+    )
+{
+    if (!g_fWebSocketSupported)
+    {
+        return;
+    }
+
+    if (sm_pTraceLog)
+    {
+        DestroyRefTraceLog(sm_pTraceLog);
+        sm_pTraceLog = NULL;
+    }
+}
+
+VOID
+WEBSOCKET_HANDLER::InsertRequest(
+    VOID
+    )
+{
+    if (g_fEnableReferenceCountTracing)
+    {
+        AcquireSRWLockExclusive(&sm_RequestsListLock);
+        InsertTailList(&sm_RequestsListHead, &_listEntry);
+        ReleaseSRWLockExclusive( &sm_RequestsListLock);
+    }
+}
+
+//static 
+VOID
+WEBSOCKET_HANDLER::RemoveRequest(
+    VOID
+    )
+{
+    if (g_fEnableReferenceCountTracing)
+    {
+        AcquireSRWLockExclusive(&sm_RequestsListLock);
+        RemoveEntryList(&_listEntry);
+        ReleaseSRWLockExclusive( &sm_RequestsListLock);
+    }
+}
+
+VOID
+WEBSOCKET_HANDLER::IncrementOutstandingIo(
+    VOID
+    )
+{
+    LONG dwOutstandingIo = InterlockedIncrement(&_dwOutstandingIo);
+    if (sm_pTraceLog)
+    {
+        WriteRefTraceLog(sm_pTraceLog, dwOutstandingIo, this);
+    }
+}
+
+VOID
+WEBSOCKET_HANDLER::DecrementOutstandingIo(
+    VOID
+    )
+/*++
+    Routine Description:
+    Decrements outstanding IO count.
+
+    This indicates completion to IIS if all outstanding IO
+    has been completed, and a Cleanup was triggered for this
+    connection (denoted by _fIndicateCompletionToIis).
+
+--*/
+{
+    LONG dwOutstandingIo = InterlockedDecrement (&_dwOutstandingIo);
+
+    if (sm_pTraceLog)
+    {
+        WriteRefTraceLog(sm_pTraceLog, dwOutstandingIo, this);
+    }
+
+    if (dwOutstandingIo == 0 && _fIndicateCompletionToIis)
+    {
+        IndicateCompletionToIIS();
+    }
+}
+
+VOID
+WEBSOCKET_HANDLER::IndicateCompletionToIIS(
+    VOID
+    )
+/*++
+    Routine Description:
+    Indicates completion to IIS.
+
+    This returns a Pending Status, so that forwarding handler has a chance
+    to do book keeping when request is finally done.
+
+--*/
+{
+    DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO,
+        "WEBSOCKET_HANDLER::IndicateCompletionToIIS called %d", _dwOutstandingIo);
+
+    //
+    // close Websocket handle. This will triger a WinHttp callback
+    // on handle close, then let IIS pipeline continue.
+    // Make sure no pending IO as there is no IIS websocket cancelation,
+    // any unexpected callback will lead to AV. Revisit it once CanelOutGoingIO works
+    //
+    if (_hWebSocketRequest != NULL && _dwOutstandingIo == 0)
+    {
+        DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO,
+            "WEBSOCKET_HANDLER::IndicateCompletionToIIS");
+
+        _pHandler->SetStatus(FORWARDER_DONE);
+        _fHandleClosed = TRUE;
+        WinHttpCloseHandle(_hWebSocketRequest);
+        _hWebSocketRequest = NULL;
+    }
+}
+
+HRESULT
+WEBSOCKET_HANDLER::ProcessRequest(
+    FORWARDING_HANDLER *pHandler,
+    IHttpContext *pHttpContext,
+    HINTERNET     hRequest,
+    BOOL*         pfHandleCreated
+)
+/*++
+
+Routine Description:
+
+    Entry point to WebSocket Handler:
+    
+    This routine is called after the 101 response was successfully sent to
+    the client. 
+    This routine get's a websocket handle to winhttp, 
+    websocket handle to IIS's websocket context, and initiates IO 
+    in these two endpoints.
+
+
+--*/
+{
+    HRESULT hr = S_OK;
+    //DWORD dwBuffSize = RECEIVE_BUFFER_SIZE;
+
+    *pfHandleCreated = FALSE;
+    _pHandler = pHandler;
+
+    EnterCriticalSection(&_RequestLock);
+    DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO,
+        "WEBSOCKET_HANDLER::ProcessRequest");
+
+    //
+    // Cache the points to IHttpContext3
+    //
+    hr = HttpGetExtendedInterface(g_pHttpServer, 
+            pHttpContext, 
+            &_pHttpContext);
+    if (FAILED (hr))
+    {
+        goto Finished;
+    }
+
+    //
+    // Get pointer to IWebSocketContext for IIS websocket IO.
+    //
+
+     _pWebSocketContext = (IWebSocketContext *) _pHttpContext->
+        GetNamedContextContainer()->GetNamedContext(IIS_WEBSOCKET);
+    if ( _pWebSocketContext == NULL )
+    {
+        hr = HRESULT_FROM_WIN32( ERROR_FILE_NOT_FOUND );
+        goto Finished;
+    }
+
+    //
+    // Get Handle to Winhttp's websocket context.
+    //
+    _hWebSocketRequest = WINHTTP_HELPER::sm_pfnWinHttpWebSocketCompleteUpgrade(
+        hRequest,
+        (DWORD_PTR) pHandler);
+
+    if (_hWebSocketRequest == NULL)
+    {
+        hr = HRESULT_FROM_WIN32(GetLastError());
+        goto Finished;
+    }
+
+    *pfHandleCreated = TRUE;
+
+    //
+    // Resize the send & receive buffers to be more conservative (and avoid DoS attacks).
+    // NOTE: The two WinHTTP options below were added for WinBlue, so we can't
+    // rely on their existence.
+    //
+
+    //if (!WinHttpSetOption(_hWebSocketRequest,
+    //                      WINHTTP_OPTION_WEB_SOCKET_RECEIVE_BUFFER_SIZE,
+    //                      &dwBuffSize,
+    //                      sizeof(dwBuffSize)))
+    //{
+    //    DWORD dwRet = GetLastError();
+    //    if ( dwRet != ERROR_WINHTTP_INVALID_OPTION )
+    //    {
+    //        hr = HRESULT_FROM_WIN32(dwRet);
+    //        goto Finished;
+    //    }
+    //}
+
+    //if (!WinHttpSetOption(_hWebSocketRequest,
+    //                      WINHTTP_OPTION_WEB_SOCKET_SEND_BUFFER_SIZE,
+    //                      &dwBuffSize,
+    //                      sizeof(dwBuffSize)))
+    //{
+    //    DWORD dwRet = GetLastError();
+    //    if ( dwRet != ERROR_WINHTTP_INVALID_OPTION )
+    //    {
+    //        hr = HRESULT_FROM_WIN32(dwRet);
+    //        goto Finished;
+    //    }
+    //}
+
+    //
+    // Initiate Read on IIS
+    //
+    hr = DoIisWebSocketReceive();
+    if (FAILED(hr))
+    {
+        goto Finished;
+    }
+
+    //
+    // Initiate Read on WinHttp
+    //
+
+    hr = DoWinHttpWebSocketReceive();
+    if (FAILED(hr))
+    {
+        goto Finished;
+    }
+
+Finished:
+    LeaveCriticalSection(&_RequestLock);
+
+    if (FAILED (hr))
+    {
+        DebugPrintf (ASPNETCORE_DEBUG_FLAG_ERROR,
+            "Process Request Failed with HR=%08x", hr);
+    }
+
+    return hr;
+}
+
+HRESULT
+WEBSOCKET_HANDLER::DoIisWebSocketReceive(
+    VOID
+)
+/*++
+
+Routine Description:
+
+    Initiates a websocket receive on the IIS Websocket Context.
+
+
+--*/
+{
+    HRESULT hr = S_OK;
+    DWORD   dwBufferSize = RECEIVE_BUFFER_SIZE;
+    BOOL    fUtf8Encoded;
+    BOOL    fFinalFragment;
+    BOOL    fClose;
+
+    DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO,
+        "WEBSOCKET_HANDLER::DoIisWebSocketReceive");
+
+    IncrementOutstandingIo();
+
+    hr = _pWebSocketContext->ReadFragment(
+            &_IisReceiveBuffer,
+            &dwBufferSize,
+            TRUE,
+            &fUtf8Encoded,
+            &fFinalFragment,
+            &fClose,
+            OnReadIoCompletion,
+            this,
+            NULL);
+    if (FAILED(hr))
+    {
+        DecrementOutstandingIo();
+        DebugPrintf(ASPNETCORE_DEBUG_FLAG_ERROR,
+            "WEBSOCKET_HANDLER::DoIisWebSocketSend failed with %08x", hr);
+    }
+
+    return hr;
+}
+
+HRESULT
+WEBSOCKET_HANDLER::DoWinHttpWebSocketReceive(
+    VOID
+)
+/*++
+
+Routine Description:
+
+    Initiates a websocket receive on WinHttp
+
+
+--*/
+{
+    HRESULT hr = S_OK;
+    DWORD   dwError = NO_ERROR;
+
+    DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO,
+        "WEBSOCKET_HANDLER::DoWinHttpWebSocketReceive");
+
+    IncrementOutstandingIo();
+
+    dwError = WINHTTP_HELPER::sm_pfnWinHttpWebSocketReceive(
+                _hWebSocketRequest,
+                &_WinHttpReceiveBuffer,
+                RECEIVE_BUFFER_SIZE,
+                NULL,
+                NULL);
+
+    if (dwError != NO_ERROR)
+    {
+        DecrementOutstandingIo();
+        hr = HRESULT_FROM_WIN32(dwError);
+        DebugPrintf(ASPNETCORE_DEBUG_FLAG_ERROR,
+            "WEBSOCKET_HANDLER::DoWinHttpWebSocketReceive failed with %08x", hr);
+    }
+
+    return hr;
+}
+
+HRESULT
+WEBSOCKET_HANDLER::DoIisWebSocketSend(
+    DWORD cbData,
+    WINHTTP_WEB_SOCKET_BUFFER_TYPE  eBufferType
+)
+/*++
+
+Routine Description:
+
+    Initiates a websocket send on IIS
+
+--*/
+{
+    HRESULT hr = S_OK;
+    BOOL    fUtf8Encoded = FALSE;
+    BOOL    fFinalFragment = FALSE;
+    BOOL    fClose = FALSE;
+
+    DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO,
+        "WEBSOCKET_HANDLER::DoIisWebSocketSend %d", eBufferType);
+
+    if (eBufferType == WINHTTP_WEB_SOCKET_CLOSE_BUFFER_TYPE)
+    {
+        //
+        // Query Close Status from WinHttp
+        //
+
+        DWORD dwError = NO_ERROR;
+        USHORT uStatus;
+        DWORD  dwReceived = 0;
+        STACK_STRU(strCloseReason, 128);
+
+        dwError = WINHTTP_HELPER::sm_pfnWinHttpWebSocketQueryCloseStatus(
+                    _hWebSocketRequest,
+                    &uStatus,
+                    &_WinHttpReceiveBuffer,
+                    RECEIVE_BUFFER_SIZE,
+                    &dwReceived);
+
+        if (dwError != NO_ERROR)
+        {
+            hr = HRESULT_FROM_WIN32(dwError);
+            goto Finished;
+        }
+
+        //
+        // Convert close reason to WCHAR
+        //
+        hr = strCloseReason.CopyA((PCSTR)&_WinHttpReceiveBuffer,
+            dwReceived);
+        if (FAILED(hr))
+        {
+            goto Finished;
+        }
+
+        IncrementOutstandingIo();
+        //
+        // Backend end may start close hand shake first
+        // Need to indicate no more receive should be called on WinHttp connection
+        //
+        _fReceivedCloseMsg = TRUE;
+        _fIndicateCompletionToIis = TRUE;
+
+        //
+        // Send close to IIS.
+        //
+        hr = _pWebSocketContext->SendConnectionClose(
+            TRUE,
+            uStatus,
+            uStatus == 1005 ? NULL : strCloseReason.QueryStr(),
+            OnWriteIoCompletion,
+            this,
+            NULL);
+    }
+    else
+    {
+        //
+        // Get equivalant flags for IIS API from buffer type.
+        //
+
+        WINHTTP_HELPER::GetFlagsFromBufferType(eBufferType,
+            &fUtf8Encoded,
+            &fFinalFragment,
+            &fClose);
+
+        IncrementOutstandingIo();
+
+        //
+        // Do the Send.
+        //
+        hr = _pWebSocketContext->WriteFragment(
+                &_WinHttpReceiveBuffer,
+                &cbData,
+                TRUE,
+                fUtf8Encoded,
+                fFinalFragment,
+                OnWriteIoCompletion,
+                this,
+                NULL);
+    }
+
+    if (FAILED(hr))
+    {
+        DecrementOutstandingIo();
+    }
+
+Finished:
+    if (FAILED(hr))
+    {
+        DebugPrintf(ASPNETCORE_DEBUG_FLAG_ERROR,
+            "WEBSOCKET_HANDLER::DoIisWebSocketSend failed with %08x", hr);
+    }
+
+    return hr;
+}
+
+HRESULT
+WEBSOCKET_HANDLER::DoWinHttpWebSocketSend(
+    DWORD cbData,
+    WINHTTP_WEB_SOCKET_BUFFER_TYPE  eBufferType
+)
+/*++
+
+Routine Description:
+
+    Initiates a websocket send on WinHttp
+
+--*/
+{
+    DWORD       dwError = NO_ERROR;
+    HRESULT     hr = S_OK;
+
+    DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO,
+        "WEBSOCKET_HANDLER::DoWinHttpWebSocketSend, %d", eBufferType);
+
+    if (eBufferType == WINHTTP_WEB_SOCKET_CLOSE_BUFFER_TYPE)
+    {
+        USHORT  uStatus;
+        LPCWSTR pszReason;
+        STACK_STRA(strCloseReason, 128);
+
+        //
+        // Get Close status from IIS.
+        //
+        hr = _pWebSocketContext->GetCloseStatus(&uStatus, 
+                &pszReason);
+
+        if (FAILED(hr))
+        {
+            goto Finished;
+        }
+
+        //
+        // Convert status to UTF8
+        //
+        hr = strCloseReason.CopyWToUTF8Unescaped(pszReason);
+        if (FAILED(hr))
+        {
+            goto Finished;
+        }
+
+        IncrementOutstandingIo();
+
+        //
+        // Send Close.
+        //
+        dwError = WINHTTP_HELPER::sm_pfnWinHttpWebSocketShutdown(
+            _hWebSocketRequest,
+            uStatus,
+            strCloseReason.QueryCCH() == 0 ? NULL : (PVOID) strCloseReason.QueryStr(),
+            strCloseReason.QueryCCH());
+
+        if (dwError == ERROR_IO_PENDING)
+        {
+            //
+            // Call will complete asynchronously, return.
+            // ignore error.
+            //
+            DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO,
+                "WEBSOCKET_HANDLER::DoWinhttpWebSocketSend IO_PENDING");
+
+            dwError = NO_ERROR;
+        }
+        else
+        {
+            if (dwError == NO_ERROR)
+            {
+                //
+                // Call completed synchronously.
+                //
+                DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO,
+                "WEBSOCKET_HANDLER::DoWinhttpWebSocketSend Shutdown successful.");
+            }
+        }
+    }
+    else
+    {
+        IncrementOutstandingIo();
+
+        dwError = WINHTTP_HELPER::sm_pfnWinHttpWebSocketSend(
+                        _hWebSocketRequest,
+                        eBufferType,
+                        cbData == 0 ? NULL : &_IisReceiveBuffer,
+                        cbData
+                        );
+    }
+
+    if (dwError != NO_ERROR)
+    {
+        hr = HRESULT_FROM_WIN32(dwError);
+        DecrementOutstandingIo();
+        goto Finished;
+    }
+
+Finished:
+    if (FAILED(hr))
+    {
+        DebugPrintf(ASPNETCORE_DEBUG_FLAG_ERROR,
+            "WEBSOCKET_HANDLER::DoWinHttpWebSocketSend failed with %08x", hr);
+    }
+
+    return hr;
+}
+
+//static
+VOID
+WINAPI
+WEBSOCKET_HANDLER::OnReadIoCompletion(
+    HRESULT     hrError,
+    VOID *      pvCompletionContext,
+    DWORD       cbIO,
+    BOOL        fUTF8Encoded,
+    BOOL        fFinalFragment,
+    BOOL        fClose
+    )
+/*++
+
+ Routine Description:
+
+     Completion routine for Read's from IIS pipeline.
+
+--*/
+{
+    WEBSOCKET_HANDLER *     pHandler = (WEBSOCKET_HANDLER *) 
+                            pvCompletionContext;
+
+    pHandler->OnIisReceiveComplete(
+        hrError,
+        cbIO,
+        fUTF8Encoded,
+        fFinalFragment,
+        fClose
+        );
+}
+
+//static
+VOID
+WINAPI
+WEBSOCKET_HANDLER::OnWriteIoCompletion(
+    HRESULT     hrError,
+    VOID *      pvCompletionContext,
+    DWORD       cbIO,
+    BOOL        fUTF8Encoded,
+    BOOL        fFinalFragment,
+    BOOL        fClose
+    )
+/*++
+ Routine Description:
+
+     Completion routine for Write's from IIS pipeline.
+
+--*/
+{
+    WEBSOCKET_HANDLER *     pHandler = (WEBSOCKET_HANDLER *) 
+                            pvCompletionContext;
+
+    UNREFERENCED_PARAMETER(fUTF8Encoded);
+    UNREFERENCED_PARAMETER(fFinalFragment);
+    UNREFERENCED_PARAMETER(fClose);
+
+    pHandler->OnIisSendComplete(
+        hrError,
+        cbIO
+        );
+}
+
+
+HRESULT
+WEBSOCKET_HANDLER::OnWinHttpSendComplete(
+    WINHTTP_WEB_SOCKET_STATUS *
+    )
+/*++
+
+Routine Description:
+    Completion callback executed when a send to backend
+    server completes.
+
+    If the send was successful, issue the next read
+    on the client's endpoint.
+
+++*/
+{
+    HRESULT                 hr = S_OK;
+    BOOL                    fLocked = FALSE;
+    CleanupReason           cleanupReason = CleanupReasonUnknown;
+
+    DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO,
+        "WEBSOCKET_HANDLER::OnWinHttpSendComplete");
+
+    if (_fCleanupInProgress)
+    {
+        goto Finished;
+    }
+
+    EnterCriticalSection (&_RequestLock);
+
+    fLocked = TRUE;
+
+    if (_fCleanupInProgress)
+    {
+        goto Finished;
+    }
+    //
+    // Data was successfully sent to backend.
+    // Initiate next receive from IIS.
+    //
+
+    hr = DoIisWebSocketReceive();
+    if (FAILED(hr))
+    {
+        goto Finished;
+    }
+
+Finished:
+    if (fLocked) 
+    {
+        LeaveCriticalSection(&_RequestLock);
+    }
+
+    if (FAILED (hr))
+    {
+        Cleanup (cleanupReason);
+
+        DebugPrintf (ASPNETCORE_DEBUG_FLAG_ERROR,
+            "WEBSOCKET_HANDLER::OnWinsockSendComplete failed with HR=%08x", hr);
+    }
+
+    //
+    // The handler object can be gone after this call.
+    // do not reference it after this statement.
+    //
+    DecrementOutstandingIo();
+
+    return hr;
+}
+
+HRESULT
+WEBSOCKET_HANDLER::OnWinHttpShutdownComplete(
+    VOID
+    )
+{
+    DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO,
+        "WEBSOCKET_HANDLER::OnWinHttpShutdownComplete --%p", _pHandler);
+
+    DecrementOutstandingIo();
+
+    return S_OK;
+}
+
+HRESULT
+WEBSOCKET_HANDLER::OnWinHttpIoError(
+    WINHTTP_WEB_SOCKET_ASYNC_RESULT *pCompletionStatus
+)
+{
+    HRESULT hr = HRESULT_FROM_WIN32(pCompletionStatus->AsyncResult.dwError);
+
+    DebugPrintf(ASPNETCORE_DEBUG_FLAG_ERROR,
+        "WEBSOCKET_HANDLER::OnWinHttpIoError HR = %08x, Operation = %d",
+        hr, pCompletionStatus->AsyncResult.dwResult);
+
+    Cleanup(ServerDisconnect);
+    DecrementOutstandingIo();
+
+    return hr;
+}
+
+HRESULT
+WEBSOCKET_HANDLER::OnWinHttpReceiveComplete(
+    WINHTTP_WEB_SOCKET_STATUS * pCompletionStatus
+    )
+/*++
+
+Routine Description:
+
+    Completion callback executed when a receive completes
+    on the backend server winhttp endpoint.
+
+    Issue send on the Client(IIS) if the receive was
+    successful.
+
+    If the receive completed with zero bytes, that 
+    indicates that the server has disconnected the connection.
+    Issue cleanup for the websocket handler.
+--*/
+{
+    HRESULT  hr = S_OK;
+    BOOL     fLocked = FALSE;
+    CleanupReason cleanupReason = CleanupReasonUnknown;
+
+    DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO,
+        "WEBSOCKET_HANDLER::OnWinHttpReceiveComplete --%p", _pHandler);
+
+    if (_fCleanupInProgress)
+    {
+        goto Finished;
+    }
+
+    EnterCriticalSection(&_RequestLock);
+
+    fLocked = TRUE;
+    if (_fCleanupInProgress)
+    {
+        goto Finished;
+    }
+    hr = DoIisWebSocketSend(
+            pCompletionStatus->dwBytesTransferred,
+            pCompletionStatus->eBufferType
+            );
+
+    if (FAILED (hr))
+    {
+        cleanupReason = ClientDisconnect;
+        goto Finished;
+    }
+
+Finished:
+    if (fLocked) 
+    {
+        LeaveCriticalSection(&_RequestLock);
+    }
+    if (FAILED (hr))
+    {
+        Cleanup (cleanupReason);
+
+        DebugPrintf (ASPNETCORE_DEBUG_FLAG_ERROR,
+            "WEBSOCKET_HANDLER::OnWinsockReceiveComplete failed with HR=%08x", hr);
+    }
+
+    //
+    // The handler object can be gone after this call.
+    // do not reference it after this statement.
+    //
+
+    DecrementOutstandingIo();
+
+    return hr;
+}
+
+HRESULT
+WEBSOCKET_HANDLER::OnIisSendComplete(
+    HRESULT  hrCompletion,
+    DWORD    cbIo
+    )
+/*++
+Routine Description:
+
+    Completion callback executed when a send
+    completes from the client.
+
+    If send was successful,issue read on the 
+    server endpoint, to continue the readloop.
+
+--*/
+{
+    HRESULT         hr = S_OK;
+    BOOL            fLocked = FALSE;
+    CleanupReason   cleanupReason = CleanupReasonUnknown;
+
+    UNREFERENCED_PARAMETER(cbIo);
+
+    DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO, "WEBSOCKET_HANDLER::OnIisSendComplete");
+
+    if (FAILED(hrCompletion))
+    {
+        hr = hrCompletion;
+        cleanupReason = ClientDisconnect;
+        goto Finished;
+    }
+
+    if (_fCleanupInProgress)
+    {
+        goto Finished;
+    }
+    EnterCriticalSection(&_RequestLock);
+    fLocked = TRUE;
+    if (_fCleanupInProgress)
+    {
+        goto Finished;
+    }
+
+    //
+    // Only call read if no close hand shake was received from backend
+    //
+    if (!_fReceivedCloseMsg)
+    {
+        //
+        // Write Completed, initiate next read from backend server.
+        //
+        hr = DoWinHttpWebSocketReceive();
+        if (FAILED(hr))
+        {
+            cleanupReason = ServerDisconnect;
+            goto Finished;
+        }
+    }
+
+Finished:
+    if (fLocked)
+    {
+        LeaveCriticalSection(&_RequestLock);
+    }
+    if (FAILED (hr))
+    {
+        Cleanup (cleanupReason);
+
+        DebugPrintf (ASPNETCORE_DEBUG_FLAG_ERROR,
+            "WEBSOCKET_HANDLER::OnIisSendComplete failed with HR=%08x", hr);
+    }
+
+    //
+    // The handler object can be gone after this call.
+    // do not reference it after this statement.
+    //
+
+    DecrementOutstandingIo();
+
+    return hr;
+}
+
+HRESULT
+WEBSOCKET_HANDLER::OnIisReceiveComplete(
+    HRESULT     hrCompletion,
+    DWORD       cbIO,
+    BOOL        fUTF8Encoded,
+    BOOL        fFinalFragment,
+    BOOL        fClose
+    )
+/*++
+Routine Description:
+
+    Completion routine executed when a receive completes
+    from the client (IIS endpoint).
+
+    If the receive was successful, initiate a send on
+    the backend server (winhttp) endpoint.
+
+    If the receive failed, initiate cleanup.
+
+--*/
+{
+    HRESULT    hr = S_OK;
+    BOOL       fLocked = FALSE;
+    CleanupReason cleanupReason = CleanupReasonUnknown;
+    WINHTTP_WEB_SOCKET_BUFFER_TYPE  BufferType;
+
+    DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO,
+        "WEBSOCKET_HANDLER::OnIisReceiveComplete");
+
+    if (FAILED(hrCompletion))
+    {
+        cleanupReason = ClientDisconnect;
+        hr = hrCompletion;
+        goto Finished;
+    }
+
+    if (_fCleanupInProgress)
+    {
+        goto Finished;
+    }
+
+    EnterCriticalSection(&_RequestLock);
+    
+    fLocked = TRUE;
+    if (_fCleanupInProgress)
+    {
+        goto Finished;
+    }
+    //
+    // Get Buffer Type from flags.
+    //
+
+    WINHTTP_HELPER::GetBufferTypeFromFlags(fUTF8Encoded,
+        fFinalFragment,
+        fClose,
+        &BufferType);
+
+    //
+    // Initiate Send.
+    //
+
+    hr =  DoWinHttpWebSocketSend(cbIO, BufferType);
+    if (FAILED (hr))
+    {
+        cleanupReason = ServerDisconnect;
+        goto Finished;
+    }
+
+Finished:
+    if (fLocked)
+    {
+        LeaveCriticalSection(&_RequestLock);
+    }
+    if (FAILED (hr))
+    {
+        Cleanup (cleanupReason);
+
+        DebugPrintf (ASPNETCORE_DEBUG_FLAG_ERROR,
+            "WEBSOCKET_HANDLER::OnIisReceiveComplete failed with HR=%08x", hr);
+    }
+
+    //
+    // The handler object can be gone after this call.
+    // do not reference it after this statement.
+    //
+
+    DecrementOutstandingIo();
+
+    return hr;
+}
+
+VOID
+WEBSOCKET_HANDLER::Cleanup(
+    CleanupReason reason
+)
+/*++
+
+Routine Description:
+
+    Cleanup function for the websocket handler.
+
+    Initiates cancelIo on the two IO endpoints:
+    IIS, WinHttp client.
+
+Arguments:
+    CleanupReason
+--*/
+{
+    BOOL    fLocked = FALSE;
+    DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO,
+        "WEBSOCKET_HANDLER::Cleanup Initiated with reason %d", reason);
+
+    if (_fCleanupInProgress)
+    {
+        goto Finished;
+    }
+
+    EnterCriticalSection(&_RequestLock);
+
+    fLocked = TRUE;
+    if (_fCleanupInProgress)
+    {
+        goto Finished;
+    }
+
+    _fCleanupInProgress = TRUE;
+
+    _fIndicateCompletionToIis = TRUE;
+
+    //
+    // TODO:: Raise FREB event with cleanup reason.
+    //
+    if (reason == ClientDisconnect || reason == ServerStateUnavailable)
+    {
+        //
+        // Calling shutdown to notify the backend about disonnect
+        //
+        WINHTTP_HELPER::sm_pfnWinHttpWebSocketShutdown(
+            _hWebSocketRequest,
+            1011, // indicate that a server is terminating the connection because it encountered
+                  // an unexpected condition that prevent it from fulfilling the request
+            NULL, // Reason
+            0);   // length og Reason
+
+    }
+
+    if (reason == ServerDisconnect || reason == ServerStateUnavailable)
+    {
+        _pHttpContext->CancelIo();
+        //
+        // CancelIo sometime may not be able to cannel pending websocket IO
+        // ResetConnection to force IISWebsocket module to release the pipeline
+        //
+        _pHttpContext->GetResponse()->ResetConnection();
+    }
+
+Finished:
+    if (fLocked)
+    {
+        LeaveCriticalSection(&_RequestLock);
+    }
+}
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/RequestHandler/outofprocess/websockethandler.h b/src/IISIntegration/src/AspNetCoreModuleV2/RequestHandler/outofprocess/websockethandler.h
new file mode 100644
index 0000000000000000000000000000000000000000..2256e5d70e95c5df9761d1873b85fe9162bf833d
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/RequestHandler/outofprocess/websockethandler.h
@@ -0,0 +1,225 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#pragma once
+
+extern IHttpServer *    g_pHttpServer;
+class FORWARDING_HANDLER;
+
+class WEBSOCKET_HANDLER
+{
+public:
+    WEBSOCKET_HANDLER();
+
+    static
+    HRESULT
+    StaticInitialize(
+        BOOL fEnableReferenceTraceLogging
+        );
+
+    static
+    VOID
+    StaticTerminate(
+        VOID
+        );
+
+    VOID
+    Terminate(
+        VOID
+        );
+
+    VOID
+    TerminateRequest(
+        VOID
+        )
+    {
+        Cleanup(ServerStateUnavailable);
+    }
+
+    HRESULT
+    ProcessRequest(
+        FORWARDING_HANDLER *pHandler,
+        IHttpContext * pHttpContext,
+        HINTERNET      hRequest,
+        BOOL*          pfHandleCreated
+        );
+
+    REQUEST_NOTIFICATION_STATUS
+    OnAsyncCompletion(
+        VOID
+        );
+
+    HRESULT
+    OnWinHttpSendComplete(
+        WINHTTP_WEB_SOCKET_STATUS * pCompletionStatus
+    );
+
+    HRESULT
+    OnWinHttpShutdownComplete(
+        VOID
+    );
+
+    HRESULT
+    OnWinHttpReceiveComplete(
+        WINHTTP_WEB_SOCKET_STATUS * pCompletionStatus
+    );
+
+    HRESULT
+    OnWinHttpIoError(
+        WINHTTP_WEB_SOCKET_ASYNC_RESULT *pCompletionStatus
+    );
+
+
+private:
+    enum CleanupReason
+    {
+        CleanupReasonUnknown = 0,
+        IdleTimeout = 1,
+        ConnectFailed = 2,
+        ClientDisconnect = 3,
+        ServerDisconnect = 4,
+        ServerStateUnavailable = 5
+    };
+
+    virtual
+    ~WEBSOCKET_HANDLER()
+    {
+    }
+
+    WEBSOCKET_HANDLER(const WEBSOCKET_HANDLER &);
+    void operator=(const WEBSOCKET_HANDLER &);
+
+    VOID
+    InsertRequest(
+        VOID
+        );
+
+    VOID
+    RemoveRequest(
+        VOID
+        );
+
+    static
+    VOID
+    WINAPI
+    OnReadIoCompletion(
+        HRESULT     hrError,
+        VOID *      pvCompletionContext,
+        DWORD       cbIO,
+        BOOL        fUTF8Encoded,
+        BOOL        fFinalFragment,
+        BOOL        fClose
+        );
+
+    static
+    VOID
+    WINAPI
+    OnWriteIoCompletion(
+        HRESULT     hrError,
+        VOID *      pvCompletionContext,
+        DWORD       cbIO,
+        BOOL        fUTF8Encoded,
+        BOOL        fFinalFragment,
+        BOOL        fClose
+    );
+
+    VOID
+    Cleanup(
+        CleanupReason  reason
+        );
+
+    HRESULT
+    DoIisWebSocketReceive(
+        VOID
+    );
+
+    HRESULT
+    DoWinHttpWebSocketReceive(
+        VOID
+    );
+
+    HRESULT
+    DoIisWebSocketSend(
+        DWORD cbData,
+        WINHTTP_WEB_SOCKET_BUFFER_TYPE  eBufferType
+    );
+
+    HRESULT
+    DoWinHttpWebSocketSend(
+        DWORD cbData,
+        WINHTTP_WEB_SOCKET_BUFFER_TYPE  eBufferType
+    );
+
+    HRESULT
+    OnIisSendComplete(
+        HRESULT     hrError,
+        DWORD       cbIO
+    );
+
+    HRESULT
+    OnIisReceiveComplete(
+        HRESULT     hrError,
+        DWORD       cbIO,
+        BOOL        fUTF8Encoded,
+        BOOL        fFinalFragment,
+        BOOL        fClose
+    );
+
+    VOID
+    IncrementOutstandingIo(
+        VOID
+    );
+
+    VOID
+    DecrementOutstandingIo(
+        VOID
+    );
+
+    VOID
+    IndicateCompletionToIIS(
+        VOID
+    );
+
+private:
+    static const
+    DWORD               RECEIVE_BUFFER_SIZE = 4*1024;
+
+    LIST_ENTRY          _listEntry;
+
+    IHttpContext3 *     _pHttpContext;
+
+    IWebSocketContext * _pWebSocketContext;
+
+    FORWARDING_HANDLER *_pHandler;
+
+    HINTERNET           _hWebSocketRequest;
+
+    BYTE                _WinHttpReceiveBuffer[RECEIVE_BUFFER_SIZE];
+
+    BYTE                _IisReceiveBuffer[RECEIVE_BUFFER_SIZE];
+
+    CRITICAL_SECTION    _RequestLock;
+
+    LONG                _dwOutstandingIo;
+
+    volatile
+    BOOL                _fCleanupInProgress;
+
+    volatile
+    BOOL                _fIndicateCompletionToIis;
+
+    volatile
+    BOOL                _fHandleClosed;
+
+    volatile
+    BOOL                _fReceivedCloseMsg;
+
+    static
+    LIST_ENTRY          sm_RequestsListHead;
+
+    static
+    SRWLOCK             sm_RequestsListLock;
+
+    static
+    TRACE_LOG *         sm_pTraceLog;
+};
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/RequestHandler/outofprocess/winhttphelper.cxx b/src/IISIntegration/src/AspNetCoreModuleV2/RequestHandler/outofprocess/winhttphelper.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..ce4256a710bdee2418bc80a9fc58312104980c81
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/RequestHandler/outofprocess/winhttphelper.cxx
@@ -0,0 +1,176 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#include "..\precomp.hxx"
+
+PFN_WINHTTP_WEBSOCKET_COMPLETE_UPGRADE
+WINHTTP_HELPER::sm_pfnWinHttpWebSocketCompleteUpgrade;
+
+PFN_WINHTTP_WEBSOCKET_SEND
+WINHTTP_HELPER::sm_pfnWinHttpWebSocketSend;
+
+PFN_WINHTTP_WEBSOCKET_RECEIVE
+WINHTTP_HELPER::sm_pfnWinHttpWebSocketReceive;
+
+PFN_WINHTTP_WEBSOCKET_SHUTDOWN
+WINHTTP_HELPER::sm_pfnWinHttpWebSocketShutdown;
+
+PFN_WINHTTP_WEBSOCKET_QUERY_CLOSE_STATUS
+WINHTTP_HELPER::sm_pfnWinHttpWebSocketQueryCloseStatus;
+
+//static
+HRESULT
+WINHTTP_HELPER::StaticInitialize(
+    VOID
+)
+{
+    HRESULT hr = S_OK;
+
+    if (!g_fWebSocketSupported)
+    {
+        return S_OK;
+    }
+
+    //
+    // Initialize the function pointers for WinHttp Websocket API's.
+    //
+
+    HMODULE  hWinHttp = GetModuleHandleA("winhttp.dll");
+    if (hWinHttp == NULL)
+    {
+        hr = HRESULT_FROM_WIN32(GetLastError());
+        goto Finished;
+    }
+
+    sm_pfnWinHttpWebSocketCompleteUpgrade = (PFN_WINHTTP_WEBSOCKET_COMPLETE_UPGRADE) 
+        GetProcAddress(hWinHttp, "WinHttpWebSocketCompleteUpgrade");
+    if (sm_pfnWinHttpWebSocketCompleteUpgrade == NULL)
+    {
+        hr = HRESULT_FROM_WIN32(GetLastError());
+        goto Finished;
+    }
+
+    sm_pfnWinHttpWebSocketQueryCloseStatus = (PFN_WINHTTP_WEBSOCKET_QUERY_CLOSE_STATUS)
+        GetProcAddress(hWinHttp, "WinHttpWebSocketQueryCloseStatus");
+    if (sm_pfnWinHttpWebSocketQueryCloseStatus == NULL)
+    {
+        hr = HRESULT_FROM_WIN32(GetLastError());
+        goto Finished;
+    }
+
+    sm_pfnWinHttpWebSocketReceive = (PFN_WINHTTP_WEBSOCKET_RECEIVE)
+        GetProcAddress(hWinHttp, "WinHttpWebSocketReceive");
+    if (sm_pfnWinHttpWebSocketReceive == NULL)
+    {
+        hr = HRESULT_FROM_WIN32(GetLastError());
+        goto Finished;
+    }
+
+    sm_pfnWinHttpWebSocketSend = (PFN_WINHTTP_WEBSOCKET_SEND)
+        GetProcAddress(hWinHttp, "WinHttpWebSocketSend");
+    if (sm_pfnWinHttpWebSocketSend == NULL)
+    {
+        hr = HRESULT_FROM_WIN32(GetLastError());
+        goto Finished;
+    }
+
+    sm_pfnWinHttpWebSocketShutdown = (PFN_WINHTTP_WEBSOCKET_SHUTDOWN)
+        GetProcAddress(hWinHttp, "WinHttpWebSocketShutdown");
+    if (sm_pfnWinHttpWebSocketShutdown == NULL)
+    {
+        hr = HRESULT_FROM_WIN32(GetLastError());
+        goto Finished;
+    }
+
+Finished:
+    return hr;
+}
+
+
+//static
+VOID
+WINHTTP_HELPER::GetFlagsFromBufferType(
+    __in  WINHTTP_WEB_SOCKET_BUFFER_TYPE   BufferType,
+    __out BOOL *                           pfUtf8Encoded,
+    __out BOOL *                           pfFinalFragment,
+    __out BOOL *                           pfClose
+)
+{
+    switch (BufferType)
+    {
+    case WINHTTP_WEB_SOCKET_BINARY_MESSAGE_BUFFER_TYPE:
+        *pfUtf8Encoded = FALSE;
+        *pfFinalFragment = TRUE;
+        *pfClose = FALSE;
+
+        break;
+
+    case WINHTTP_WEB_SOCKET_BINARY_FRAGMENT_BUFFER_TYPE:
+        *pfUtf8Encoded = FALSE;
+        *pfFinalFragment = FALSE;
+        *pfClose = FALSE;
+
+        break;
+
+    case WINHTTP_WEB_SOCKET_UTF8_MESSAGE_BUFFER_TYPE:
+        *pfUtf8Encoded = TRUE;
+        *pfFinalFragment = TRUE;
+        *pfClose = FALSE;
+
+        break;
+
+    case WINHTTP_WEB_SOCKET_UTF8_FRAGMENT_BUFFER_TYPE:
+        *pfUtf8Encoded = TRUE;
+        *pfFinalFragment = FALSE;
+        *pfClose = FALSE;
+
+        break;
+
+    case WINHTTP_WEB_SOCKET_CLOSE_BUFFER_TYPE:
+        *pfUtf8Encoded = FALSE;
+        *pfFinalFragment = FALSE;
+        *pfClose = TRUE;
+
+        break;
+    }
+}
+
+//static
+VOID
+WINHTTP_HELPER::GetBufferTypeFromFlags(
+    __in  BOOL                             fUtf8Encoded,
+    __in  BOOL                             fFinalFragment,
+    __in  BOOL                             fClose,
+    __out WINHTTP_WEB_SOCKET_BUFFER_TYPE*  pBufferType
+)
+{
+    if (fClose)
+    {
+        *pBufferType = WINHTTP_WEB_SOCKET_CLOSE_BUFFER_TYPE;
+    }
+    else
+    if (fUtf8Encoded)
+    {
+        if (fFinalFragment)
+        {
+            *pBufferType = WINHTTP_WEB_SOCKET_UTF8_MESSAGE_BUFFER_TYPE;
+        }
+        else
+        {
+            *pBufferType = WINHTTP_WEB_SOCKET_UTF8_FRAGMENT_BUFFER_TYPE;
+        }
+    }
+    else
+    {
+        if (fFinalFragment)
+        {
+            *pBufferType = WINHTTP_WEB_SOCKET_BINARY_MESSAGE_BUFFER_TYPE;
+        }
+        else
+        {
+            *pBufferType = WINHTTP_WEB_SOCKET_BINARY_FRAGMENT_BUFFER_TYPE;
+        }
+    }
+
+    return;
+}
\ No newline at end of file
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/RequestHandler/outofprocess/winhttphelper.h b/src/IISIntegration/src/AspNetCoreModuleV2/RequestHandler/outofprocess/winhttphelper.h
new file mode 100644
index 0000000000000000000000000000000000000000..d583f6fb10328dba49d8a49187950fe1e1f2c1bd
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/RequestHandler/outofprocess/winhttphelper.h
@@ -0,0 +1,91 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#pragma once
+
+typedef
+HINTERNET
+(WINAPI * PFN_WINHTTP_WEBSOCKET_COMPLETE_UPGRADE)(
+    _In_ HINTERNET hRequest,
+    _In_opt_ DWORD_PTR pContext
+);
+
+
+typedef
+DWORD
+(WINAPI * PFN_WINHTTP_WEBSOCKET_SEND)(
+    _In_ HINTERNET hWebSocket,
+    _In_ WINHTTP_WEB_SOCKET_BUFFER_TYPE eBufferType,
+    _In_reads_opt_(dwBufferLength) PVOID pvBuffer,
+    _In_ DWORD dwBufferLength
+);
+
+typedef
+DWORD
+(WINAPI * PFN_WINHTTP_WEBSOCKET_RECEIVE)(
+    _In_ HINTERNET hWebSocket,
+    _Out_writes_bytes_to_(dwBufferLength, *pdwBytesRead) PVOID pvBuffer,
+    _In_ DWORD dwBufferLength,
+    _Out_range_(0, dwBufferLength) DWORD *pdwBytesRead,
+    _Out_ WINHTTP_WEB_SOCKET_BUFFER_TYPE *peBufferType
+);
+
+typedef
+DWORD
+(WINAPI * PFN_WINHTTP_WEBSOCKET_SHUTDOWN)(
+    _In_ HINTERNET hWebSocket,
+    _In_ USHORT usStatus,
+    _In_reads_bytes_opt_(dwReasonLength) PVOID pvReason,
+    _In_range_(0, WINHTTP_WEB_SOCKET_MAX_CLOSE_REASON_LENGTH) DWORD dwReasonLength
+);
+
+typedef
+DWORD
+(WINAPI * PFN_WINHTTP_WEBSOCKET_QUERY_CLOSE_STATUS)(
+    _In_ HINTERNET hWebSocket,
+    _Out_ USHORT *pusStatus,
+    _Out_writes_bytes_to_opt_(dwReasonLength, *pdwReasonLengthConsumed) PVOID pvReason,
+    _In_range_(0, WINHTTP_WEB_SOCKET_MAX_CLOSE_REASON_LENGTH) DWORD dwReasonLength,
+    _Out_range_(0, WINHTTP_WEB_SOCKET_MAX_CLOSE_REASON_LENGTH) DWORD *pdwReasonLengthConsumed
+);
+
+class WINHTTP_HELPER
+{
+public:
+    static
+    HRESULT
+    StaticInitialize();
+
+    static
+    VOID
+    GetFlagsFromBufferType(
+        __in  WINHTTP_WEB_SOCKET_BUFFER_TYPE   BufferType,
+        __out BOOL *                           pfUtf8Encoded,
+        __out BOOL *                           pfFinalFragment,
+        __out BOOL *                           pfClose
+    );
+
+    static
+    VOID
+    GetBufferTypeFromFlags(
+        __in  BOOL                             fUtf8Encoded,
+        __in  BOOL                             fFinalFragment,
+        __in  BOOL                             fClose,
+        __out WINHTTP_WEB_SOCKET_BUFFER_TYPE*  pBufferType
+    );
+
+    static
+    PFN_WINHTTP_WEBSOCKET_COMPLETE_UPGRADE      sm_pfnWinHttpWebSocketCompleteUpgrade;
+
+    static
+    PFN_WINHTTP_WEBSOCKET_SEND                  sm_pfnWinHttpWebSocketSend;
+
+    static
+    PFN_WINHTTP_WEBSOCKET_RECEIVE               sm_pfnWinHttpWebSocketReceive;
+
+    static
+    PFN_WINHTTP_WEBSOCKET_SHUTDOWN              sm_pfnWinHttpWebSocketShutdown;
+
+    static
+    PFN_WINHTTP_WEBSOCKET_QUERY_CLOSE_STATUS    sm_pfnWinHttpWebSocketQueryCloseStatus;
+};
\ No newline at end of file
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/RequestHandler/precomp.hxx b/src/IISIntegration/src/AspNetCoreModuleV2/RequestHandler/precomp.hxx
new file mode 100644
index 0000000000000000000000000000000000000000..2fa43aac17b26f00d8d1a53537f7b0d2e64f4532
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/RequestHandler/precomp.hxx
@@ -0,0 +1,120 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#pragma once
+#pragma warning( disable : 4091)
+
+//
+// System related headers
+//
+#define _WINSOCKAPI_
+
+#define NTDDI_VERSION 0x06010000
+#define WINVER 0x0601
+#define _WIN32_WINNT 0x0601
+
+#include <windows.h>
+#include <atlbase.h>
+#include <pdh.h>
+#include <vector>
+#include <Shlobj.h>
+#include <httpserv.h>
+#include <winhttp.h>
+#include <httptrace.h>
+#include <cstdlib>
+#include <reftrace.h>
+#include <wchar.h>
+#include <io.h>
+#include <stdio.h>
+// This should remove our issue of compiling for win7 without header files.
+// We  force the Windows 8 version check logic in iiswebsocket.h to succeed even though we're compiling for Windows 7.
+// Then, we set the version defines back to Windows 7 to for the remainder of the compilation.
+#undef NTDDI_VERSION
+#undef WINVER
+#undef _WIN32_WINNT
+#define NTDDI_VERSION 0x06020000
+#define WINVER 0x0602
+#define _WIN32_WINNT 0x0602
+#include <iiswebsocket.h>
+#undef NTDDI_VERSION
+#undef WINVER
+#undef _WIN32_WINNT
+
+#define NTDDI_VERSION 0x06010000
+#define WINVER 0x0601
+#define _WIN32_WINNT 0x0601
+
+#include "..\IISLib\acache.h"
+#include "..\IISLib\multisz.h"
+#include "..\IISLib\multisza.h"
+#include "..\IISLib\base64.h"
+#include "..\IISLib\listentry.h"
+#include "..\CommonLib\fx_ver.h"
+#include "..\CommonLib\debugutil.h"
+#include "..\CommonLib\requesthandler.h"
+#include "..\CommonLib\aspnetcoreconfig.h"
+#include "..\CommonLib\utility.h"
+#include "..\CommonLib\application.h"
+#include "..\CommonLib\resources.h"
+#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"
+#include ".\outofprocess\responseheaderhash.h"
+#include ".\outofprocess\protocolconfig.h"
+#include ".\outofprocess\forwarderconnection.h"
+#include ".\outofprocess\serverprocess.h"
+#include ".\outofprocess\processmanager.h"
+#include ".\outofprocess\websockethandler.h"
+#include ".\outofprocess\forwardinghandler.h"
+#include ".\outofprocess\outprocessapplication.h"
+#include ".\outofprocess\winhttphelper.h"
+
+#ifdef max
+#undef max
+template<typename T> inline T max(T a, T b)
+{
+    return a > b ? a : b;
+}
+#endif
+
+#ifdef min
+#undef min
+template<typename T> inline T min(T a, T b)
+{
+    return a < b ? a : b;
+}
+#endif
+
+
+inline bool IsSpace(char ch)
+{
+    switch (ch)
+    {
+    case 32: // ' '
+    case 9:  // '\t'
+    case 10: // '\n'
+    case 13: // '\r'
+    case 11: // '\v'
+    case 12: // '\f'
+        return true;
+    default:
+        return false;
+    }
+}
+
+extern BOOL       g_fAsyncDisconnectAvailable;
+extern BOOL       g_fWinHttpNonBlockingCallbackAvailable;
+extern BOOL       g_fWebSocketSupported;
+extern BOOL       g_fNsiApiNotSupported;
+extern BOOL       g_fEnableReferenceCountTracing;
+extern BOOL       g_fProcessDetach;
+extern DWORD      g_dwActiveServerProcesses;
+extern DWORD      g_OptionalWinHttpFlags;
+extern SRWLOCK    g_srwLockRH;
+extern HINTERNET  g_hWinhttpSession;
+extern DWORD      g_dwTlsIndex;
+extern HANDLE     g_hEventLog;
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/RequestHandler/requesthandler.rc b/src/IISIntegration/src/AspNetCoreModuleV2/RequestHandler/requesthandler.rc
new file mode 100644
index 0000000000000000000000000000000000000000..2cc99c23310c9cb03cd04cc173404cbafcb89400
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/RequestHandler/requesthandler.rc
@@ -0,0 +1,119 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include <windows.h>
+#include "version.h"
+#include "..\CommonLib\resources.h"
+/////////////////////////////////////////////////////////////////////////////
+// English (United States) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+
+#define FileDescription "IIS ASP.NET Core Module Request Handler. Commit: " CommitHash
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// 11
+//
+
+//1 11
+//BEGIN
+//    0x0001, 0x0000, 0x03e8, 0x0000, 0x03ed, 0x0000, 0x0010, 0x0000, 0x0010, 
+//    0x0001, 0x0025, 0x0031, 0x000d, 0x000a, 0x0000, 0x0000, 0x0010, 0x0001, 
+//    0x0025, 0x0031, 0x000d, 0x000a, 0x0000, 0x0000, 0x0010, 0x0001, 0x0025, 
+//    0x0031, 0x000d, 0x000a, 0x0000, 0x0000, 0x0010, 0x0001, 0x0025, 0x0031, 
+//    0x000d, 0x000a, 0x0000, 0x0000, 0x0010, 0x0001, 0x0025, 0x0031, 0x000d, 
+//    0x000a, 0x0000, 0x0000, 0x0010, 0x0001, 0x0025, 0x0031, 0x000d, 0x000a, 
+//    0x0000, 0x0000
+//END
+
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE 
+BEGIN
+    "..\CommonLib\resources.h\0"
+END
+
+2 TEXTINCLUDE 
+BEGIN
+    "\0"
+END
+
+3 TEXTINCLUDE 
+BEGIN
+    "\r\n"
+    "\0"
+END
+
+#endif    // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION FileVersion
+ PRODUCTVERSION ProductVersion
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x40004L
+ FILETYPE 0x2L
+ FILESUBTYPE 0x0L
+BEGIN
+    BLOCK "StringFileInfo"
+    BEGIN
+        BLOCK "040904b0"
+        BEGIN
+            VALUE "CompanyName", "Microsoft"
+            VALUE "FileDescription", FileDescription
+            VALUE "FileVersion", FileVersionStr
+            VALUE "InternalName", "aspnetcorerh.dll"
+            VALUE "LegalCopyright", "Copyright (C) Microsoft Corporation"
+            VALUE "OriginalFilename", "aspnetcorerh.dll"
+            VALUE "ProductName", "ASP.NET Core Module Request Handler"
+            VALUE "ProductVersion", ProductVersionStr
+        END
+    END
+    BLOCK "VarFileInfo"
+    BEGIN
+        VALUE "Translation", 0x409, 1200
+    END
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// String Table
+//
+
+STRINGTABLE
+BEGIN
+    IDS_INVALID_PROPERTY    "Property name '%s' in system.webServer/aspNetCore section has invalid value '%s' which does not conform to the prescribed format"
+    IDS_SERVER_ERROR        "There was a connection error while trying to route the request."
+END
+
+#endif    // English (United States) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif    // not APSTUDIO_INVOKED
diff --git a/src/IISIntegration/src/AspNetCoreModuleV2/RequestHandler/sttimer.h b/src/IISIntegration/src/AspNetCoreModuleV2/RequestHandler/sttimer.h
new file mode 100644
index 0000000000000000000000000000000000000000..dfb79e7a6a8adb638db5333b1978f13c69d55e91
--- /dev/null
+++ b/src/IISIntegration/src/AspNetCoreModuleV2/RequestHandler/sttimer.h
@@ -0,0 +1,279 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#pragma once
+
+#ifndef _STTIMER_H
+#define _STTIMER_H
+
+class STTIMER
+{
+public:
+
+    STTIMER()
+        : _pTimer( NULL )
+    {
+        fInCanel = FALSE;
+    }
+
+    virtual
+    ~STTIMER()
+    {
+        if ( _pTimer )
+        {
+            CancelTimer();
+            CloseThreadpoolTimer( _pTimer );
+            _pTimer = NULL;
+        }
+    }
+
+    HRESULT
+    InitializeTimer(
+        PTP_TIMER_CALLBACK   pfnCallback,
+        VOID               * pContext,
+        DWORD                dwInitialWait = 0,
+        DWORD                dwPeriod = 0
+        )
+    {
+        _pTimer = CreateThreadpoolTimer( pfnCallback,
+                                         pContext,
+                                         NULL );
+
+        if ( !_pTimer )
+        {
+            return HRESULT_FROM_WIN32( GetLastError() );
+        }
+
+        if ( dwInitialWait )
+        {
+            SetTimer( dwInitialWait,
+                      dwPeriod );
+        }
+
+        return S_OK;
+    }
+
+    VOID
+    SetTimer(
+        DWORD dwInitialWait,
+        DWORD dwPeriod = 0
+        )
+    {
+        FILETIME ftInitialWait;
+
+        if ( dwInitialWait == 0 && dwPeriod == 0 )
+        {
+            //
+            // Special case.  We are preventing new callbacks
+            // from being queued.  Any existing callbacks in the
+            // queue will still run.
+            //
+            // This effectively disables the timer.  It can be
+            // re-enabled by setting non-zero initial wait or
+            // period values.
+            //
+            if (_pTimer != NULL)
+            {
+                SetThreadpoolTimer(_pTimer, NULL, 0, 0);
+            }
+
+            return;
+        }
+
+        InitializeRelativeFileTime( &ftInitialWait, dwInitialWait );
+
+        SetThreadpoolTimer( _pTimer,
+                            &ftInitialWait,
+                            dwPeriod,
+                            0 );
+    }
+
+    VOID
+    CancelTimer()
+    {
+        //
+        // Disable the timer
+        //
+        if (fInCanel)
+            return;
+
+        fInCanel = TRUE;
+        SetTimer( 0 );
+
+        //
+        // Wait until any callbacks queued prior to disabling
+        // have completed.
+        //
+        if (_pTimer != NULL)
+        {
+            WaitForThreadpoolTimerCallbacks(_pTimer, TRUE);
+        }
+
+        fInCanel = FALSE;
+    }
+
+    static
+    VOID
+    CALLBACK
+    TimerCallback(
+        _In_ PTP_CALLBACK_INSTANCE Instance,
+        _In_ PVOID Context,
+        _In_ PTP_TIMER Timer
+    )
+    {
+        Instance;
+        Timer;
+        STRU*                   pstruLogFilePath = (STRU*)Context;
+        HANDLE                  hStdoutHandle = NULL;
+        SECURITY_ATTRIBUTES     saAttr = { 0 };
+        HRESULT                 hr = S_OK;
+
+        saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
+        saAttr.bInheritHandle = TRUE;
+        saAttr.lpSecurityDescriptor = NULL;
+
+        hStdoutHandle = CreateFileW(pstruLogFilePath->QueryStr(),
+                                    FILE_READ_DATA,
+                                    FILE_SHARE_WRITE,
+                                    &saAttr,
+                                    OPEN_ALWAYS,
+                                    FILE_ATTRIBUTE_NORMAL,
+                                    NULL);
+        if (hStdoutHandle == INVALID_HANDLE_VALUE)
+        {
+            hr = HRESULT_FROM_WIN32(GetLastError());
+        }
+
+        CloseHandle(hStdoutHandle);
+    }
+
+private:
+
+    VOID
+    InitializeRelativeFileTime(
+        FILETIME * pft,
+        DWORD      dwMilliseconds
+        )
+    {
+        LARGE_INTEGER li;
+
+        //
+        // The pftDueTime parameter expects the time to be
+        // expressed as the number of 100 nanosecond intervals
+        // times -1.
+        //
+        // To convert from milliseconds, we'll multiply by
+        // -10000
+        //
+
+        li.QuadPart = (LONGLONG)dwMilliseconds * -10000;
+
+        pft->dwHighDateTime = li.HighPart;
+        pft->dwLowDateTime = li.LowPart;
+    };
+
+    TP_TIMER * _pTimer;
+    BOOL       fInCanel;
+};
+
+class STELAPSED
+{
+public:
+
+    STELAPSED()
+        : _dwInitTime( 0 ),
+          _dwInitTickCount( 0 ),
+          _dwPerfCountsPerMillisecond( 0 ),
+          _fUsingHighResolution( FALSE )
+    {
+        LARGE_INTEGER li;
+        BOOL          fResult;
+
+        _dwInitTickCount = GetTickCount64();
+
+        fResult = QueryPerformanceFrequency( &li );
+
+        if ( !fResult )
+        {
+            goto Finished;
+        }
+
+        _dwPerfCountsPerMillisecond = li.QuadPart / 1000;
+
+        fResult = QueryPerformanceCounter( &li );
+
+        if ( !fResult )
+        {
+            goto Finished;
+        }
+
+        _dwInitTime = li.QuadPart / _dwPerfCountsPerMillisecond;
+
+        _fUsingHighResolution = TRUE;
+
+Finished:
+
+        return;
+    }
+
+    virtual
+    ~STELAPSED()
+    {
+    }
+
+    LONGLONG
+    QueryElapsedTime()
+    {
+        LARGE_INTEGER li;
+
+        if ( _fUsingHighResolution && QueryPerformanceCounter( &li ) )
+        {
+            DWORD64 dwCurrentTime = li.QuadPart / _dwPerfCountsPerMillisecond;
+
+            if ( dwCurrentTime < _dwInitTime )
+            {
+                //
+                // It's theoretically possible that QueryPerformanceCounter
+                // may return slightly different values on different CPUs.
+                // In this case, we don't want to return an unexpected value
+                // so we'll return zero.  This is acceptable because
+                // presumably such a case would only happen for a very short
+                // time window.
+                //
+                // It would be possible to prevent this by ensuring processor
+                // affinity for all calls to QueryPerformanceCounter, but that
+                // would be undesirable in the general case because it could
+                // introduce unnecessary context switches and potentially a
+                // CPU bottleneck.
+                //
+                // Note that this issue also applies to callers doing rapid
+                // calls to this function.  If a caller wants to mitigate
+                // that, they could enforce the affinitization, or they
+                // could implement a similar sanity check when comparing
+                // returned values from this function.
+                //
+
+                return 0;
+            }
+
+            return dwCurrentTime - _dwInitTime;
+        }
+
+        return GetTickCount64() - _dwInitTickCount;
+    }
+
+    BOOL
+    QueryUsingHighResolution()
+    {
+        return _fUsingHighResolution;
+    }
+
+private:
+
+    DWORD64 _dwInitTime;
+    DWORD64 _dwInitTickCount;
+    DWORD64 _dwPerfCountsPerMillisecond;
+    BOOL    _fUsingHighResolution;
+};
+
+#endif // _STTIMER_H
\ No newline at end of file
diff --git a/src/IISIntegration/src/Directory.Build.props b/src/IISIntegration/src/Directory.Build.props
new file mode 100644
index 0000000000000000000000000000000000000000..4b89a431e7f239398aec95bc914cccb5c59e3d3e
--- /dev/null
+++ b/src/IISIntegration/src/Directory.Build.props
@@ -0,0 +1,7 @@
+<Project>
+  <Import Project="..\Directory.Build.props" />
+
+  <ItemGroup>
+    <PackageReference Include="Internal.AspNetCore.Sdk" PrivateAssets="All" Version="$(InternalAspNetCoreSdkPackageVersion)" />
+  </ItemGroup>
+</Project>
diff --git a/src/IISIntegration/src/Microsoft.AspNetCore.Server.IIS/Microsoft.AspNetCore.Server.IIS.csproj b/src/IISIntegration/src/Microsoft.AspNetCore.Server.IIS/Microsoft.AspNetCore.Server.IIS.csproj
new file mode 100644
index 0000000000000000000000000000000000000000..51cc16d9582f01604c98895366d115ac0a5f0821
--- /dev/null
+++ b/src/IISIntegration/src/Microsoft.AspNetCore.Server.IIS/Microsoft.AspNetCore.Server.IIS.csproj
@@ -0,0 +1,56 @@
+<Project>
+
+  <Import Project="Sdk.props" Sdk="Microsoft.NET.Sdk" />
+
+  <PropertyGroup>
+    <TargetFramework>netcoreapp2.1</TargetFramework>
+    <PackageId>Microsoft.AspNetCore.Server.IIS</PackageId>
+    <Description>Provides support for hosting ASP.NET Core in IIS using the AspNetCoreModule.</Description>
+    <IsPackable Condition="'$(OS)' != 'Windows_NT'">false</IsPackable>
+    <IncludeSource>false</IncludeSource>
+    <IncludeSymbols>false</IncludeSymbols>
+    <IncludeBuildOutput>false</IncludeBuildOutput>
+    <EnableApiCheck>false</EnableApiCheck>
+    <NoPackageAnalysis>true</NoPackageAnalysis>
+    <NuspecFile>$(PackageId).nuspec</NuspecFile>
+    <DisableImplicitFrameworkReferences>true</DisableImplicitFrameworkReferences>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <SignedPackageFile Include="aspnetcorerh_x86" PackagePath="runtimes/win-x86/nativeassets/$(TargetFramework)/aspnetcorerh.dll" Certificate="Microsoft" />
+    <SignedPackageFile Include="aspnetcorerh_x64" PackagePath="runtimes/win-x64/nativeassets/$(TargetFramework)/aspnetcorerh.dll" Certificate="Microsoft" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <ProjectReference Include="..\Microsoft.AspNetCore.Server.IISIntegration\Microsoft.AspNetCore.Server.IISIntegration.csproj" />
+  </ItemGroup>
+
+  <Target Name="SetPackageProperties" BeforeTargets="GenerateNuspec">
+    <PropertyGroup>
+      <NuspecProperties>
+        id=$(PackageId);
+        tfm=$(TargetFramework);
+        tfmGroup=$(TargetFrameworkIdentifier)$(_TargetFrameworkVersionWithoutV);
+        configuration=$(Configuration);
+        copyright=$(Copyright);
+        author=$(Authors);
+        licenseUrl=$(PackageLicenseUrl);
+        iconUrl=$(PackageIconUrl);
+        projectUrl=$(PackageProjectUrl);
+        repositoryUrl=$(RepositoryUrl);
+        repositoryType=$(RepositoryType);
+        repositoryCommit=$(RepositoryCommit);
+        version=$(PackageVersion);
+        description=$(Description);
+        serviceable=$([MSBuild]::ValueOrDefault('$(Serviceable)', 'false'));
+      </NuspecProperties>
+    </PropertyGroup>
+  </Target>
+
+  <Import Project="Sdk.targets" Sdk="Microsoft.NET.Sdk" />
+
+  <!-- This project doesn't actually compile anything. It's a shim into packing a nuspec -->
+  <Target Name="Compile" />
+  <Target Name="CopyFilesToOutputDirectory" />
+
+</Project>
diff --git a/src/IISIntegration/src/Microsoft.AspNetCore.Server.IIS/Microsoft.AspNetCore.Server.IIS.nuspec b/src/IISIntegration/src/Microsoft.AspNetCore.Server.IIS/Microsoft.AspNetCore.Server.IIS.nuspec
new file mode 100644
index 0000000000000000000000000000000000000000..3124aad25f62a8448b38b85e8064a05282e8e76a
--- /dev/null
+++ b/src/IISIntegration/src/Microsoft.AspNetCore.Server.IIS/Microsoft.AspNetCore.Server.IIS.nuspec
@@ -0,0 +1,32 @@
+<?xml version="1.0"?>
+<package xmlns="http://schemas.microsoft.com/packaging/2013/05/nuspec.xsd">
+  <metadata>
+    <id>Microsoft.AspNetCore.Server.IIS</id>
+    <version>$version$</version>
+    <authors>$author$</authors>
+    <licenseUrl>$licenseUrl$</licenseUrl>
+    <copyright>$copyright$</copyright>
+    <projectUrl>$projectUrl$</projectUrl>
+    <iconUrl>$iconUrl$</iconUrl>
+    <requireLicenseAcceptance>true</requireLicenseAcceptance>
+    <description>$description$</description>
+    <language>en-US</language>
+    <tags>aspnetcore iis</tags>
+    <serviceable>$serviceable$</serviceable>
+    <repository type="$repositoryType$" url="$repositoryUrl$" commit="$repositoryCommit$" />
+    <dependencies>
+      <group targetFramework="$tfmGroup$">
+        <dependency id="Microsoft.AspNetCore.Server.IISIntegration" version="[$version$ , )" />
+      </group>
+    </dependencies>
+  </metadata>
+  <files>
+    <!-- The _._ placeholder file will instruct NuGet to treat this package as only being compatible with $tfm$ -->
+    <file src="_._" target="lib/$tfm$/" />
+
+    <file src="Microsoft.AspNetCore.Server.IIS.targets" target="build/$tfm$/Microsoft.AspNetCore.Server.IIS.targets" />
+
+    <file src="..\AspNetCoreModuleV2\RequestHandler\bin\$Configuration$\Win32\aspnetcorerh.dll" target="runtimes\win-x86\nativeassets\$tfm$\aspnetcorerh.dll" />
+    <file src="..\AspNetCoreModuleV2\RequestHandler\bin\$Configuration$\x64\aspnetcorerh.dll" target="runtimes\win-x64\nativeassets\$tfm$\aspnetcorerh.dll" />
+  </files>
+</package>
diff --git a/src/IISIntegration/src/Microsoft.AspNetCore.Server.IIS/Microsoft.AspNetCore.Server.IIS.targets b/src/IISIntegration/src/Microsoft.AspNetCore.Server.IIS/Microsoft.AspNetCore.Server.IIS.targets
new file mode 100644
index 0000000000000000000000000000000000000000..fe0dbb05d580c1bb7b2cbe376d58243292459ce0
--- /dev/null
+++ b/src/IISIntegration/src/Microsoft.AspNetCore.Server.IIS/Microsoft.AspNetCore.Server.IIS.targets
@@ -0,0 +1,9 @@
+<Project>
+  <!--
+    Capability that enables Visual Studio support for hosting Asp.Net Core applications in the IIS process
+  -->
+  <ItemGroup>
+    <ProjectCapability Include="AspNetInProcessHosting" />
+  </ItemGroup>
+
+</Project>
diff --git a/src/IISIntegration/src/Microsoft.AspNetCore.Server.IIS/_._ b/src/IISIntegration/src/Microsoft.AspNetCore.Server.IIS/_._
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/src/IISIntegration/src/Microsoft.AspNetCore.Server.IISIntegration/AuthenticationHandler.cs b/src/IISIntegration/src/Microsoft.AspNetCore.Server.IISIntegration/AuthenticationHandler.cs
new file mode 100644
index 0000000000000000000000000000000000000000..1139969004e45a451d735fdb3738b7361a565f59
--- /dev/null
+++ b/src/IISIntegration/src/Microsoft.AspNetCore.Server.IISIntegration/AuthenticationHandler.cs
@@ -0,0 +1,95 @@
+// 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.Security.Claims;
+using System.Globalization;
+using System.Security.Principal;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Authentication;
+using Microsoft.AspNetCore.Http;
+using Microsoft.Extensions.Primitives;
+
+namespace Microsoft.AspNetCore.Server.IISIntegration
+{
+    internal class AuthenticationHandler : IAuthenticationHandler
+    {
+        private const string MSAspNetCoreWinAuthToken = "MS-ASPNETCORE-WINAUTHTOKEN";
+        private static readonly Func<object, Task> ClearUserDelegate = ClearUser;
+        private WindowsPrincipal _user;
+        private HttpContext _context;
+
+        internal AuthenticationScheme Scheme { get; private set; }
+
+        public Task<AuthenticateResult> AuthenticateAsync() 
+        {
+            var user = GetUser();
+            if (user != null)
+            {
+                return Task.FromResult(AuthenticateResult.Success(new AuthenticationTicket(user, Scheme.Name)));
+            }
+            else
+            {
+                return Task.FromResult(AuthenticateResult.NoResult());
+            }
+        }
+
+        private WindowsPrincipal GetUser()
+        {
+            if (_user == null)
+            {
+                var tokenHeader = _context.Request.Headers[MSAspNetCoreWinAuthToken];
+
+                int hexHandle;
+                if (!StringValues.IsNullOrEmpty(tokenHeader)
+                    && int.TryParse(tokenHeader, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out hexHandle))
+                {
+                    // Always create the identity if the handle exists, we need to dispose it so it does not leak.
+                    var handle = new IntPtr(hexHandle);
+                    var winIdentity = new WindowsIdentity(handle);
+
+                    // WindowsIdentity just duplicated the handle so we need to close the original.
+                    NativeMethods.CloseHandle(handle);
+
+                    _context.Response.RegisterForDispose(winIdentity);
+                    // We don't want loggers accessing a disposed identity.
+                    // https://github.com/aspnet/Logging/issues/543#issuecomment-321907828
+                    _context.Response.OnCompleted(ClearUserDelegate, _context);
+                    _user = new WindowsPrincipal(winIdentity);
+                }
+            }
+
+            return _user;
+        }
+
+        private static Task ClearUser(object arg)
+        {
+            var context = (HttpContext)arg;
+            if (context.User is WindowsPrincipal)
+            {
+                context.User = null;
+            }
+            return Task.CompletedTask;
+        }
+
+        public Task ChallengeAsync(AuthenticationProperties properties)
+        {
+            // We would normally set the www-authenticate header here, but IIS does that for us.
+            _context.Response.StatusCode = 401;
+            return Task.CompletedTask;
+        }
+
+        public Task ForbidAsync(AuthenticationProperties properties)
+        {
+            _context.Response.StatusCode = 403;
+            return Task.CompletedTask;
+        }
+
+        public Task InitializeAsync(AuthenticationScheme scheme, HttpContext context)
+        {
+            Scheme = scheme;
+            _context = context;
+            return Task.CompletedTask;
+        }
+    }
+}
diff --git a/src/IISIntegration/src/Microsoft.AspNetCore.Server.IISIntegration/ForwardedTlsConnectionFeature.cs b/src/IISIntegration/src/Microsoft.AspNetCore.Server.IISIntegration/ForwardedTlsConnectionFeature.cs
new file mode 100644
index 0000000000000000000000000000000000000000..c40ab415c7727e8d909a6473fdc04b83f187ae89
--- /dev/null
+++ b/src/IISIntegration/src/Microsoft.AspNetCore.Server.IISIntegration/ForwardedTlsConnectionFeature.cs
@@ -0,0 +1,56 @@
+// 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.Security.Cryptography.X509Certificates;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Http.Features;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Primitives;
+
+namespace Microsoft.AspNetCore.Server.IISIntegration
+{
+    internal class ForwardedTlsConnectionFeature : ITlsConnectionFeature
+    {
+        private StringValues _header;
+        private X509Certificate2 _certificate;
+        private ILogger _logger;
+
+        public ForwardedTlsConnectionFeature(ILogger logger, StringValues header)
+        {
+            _logger = logger;
+            _header = header;
+        }
+
+        public X509Certificate2 ClientCertificate
+        {
+            get
+            {
+                if (_certificate == null && _header != StringValues.Empty)
+                {
+                    try
+                    {
+                        var bytes = Convert.FromBase64String(_header);
+                        _certificate = new X509Certificate2(bytes);
+                    }
+                    catch (Exception ex)
+                    {
+                        _logger.LogWarning(0, ex, "Failed to read the client certificate.");
+                    }
+                }
+                return _certificate;
+            }
+            set
+            {
+                _certificate = value;
+                _header = StringValues.Empty;
+            }
+        }
+
+        public Task<X509Certificate2> GetClientCertificateAsync(CancellationToken cancellationToken)
+        {
+            return Task.FromResult(ClientCertificate);
+        }
+    }
+}
diff --git a/src/IISIntegration/src/Microsoft.AspNetCore.Server.IISIntegration/IISDefaults.cs b/src/IISIntegration/src/Microsoft.AspNetCore.Server.IISIntegration/IISDefaults.cs
new file mode 100644
index 0000000000000000000000000000000000000000..957273c0940d1c99e1bebf70ec3b97949e5bea6a
--- /dev/null
+++ b/src/IISIntegration/src/Microsoft.AspNetCore.Server.IISIntegration/IISDefaults.cs
@@ -0,0 +1,12 @@
+// 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.
+
+namespace Microsoft.AspNetCore.Server.IISIntegration
+{
+    public class IISDefaults
+    {
+        public static readonly string AuthenticationScheme = "Windows";
+        public const string Negotiate = "Negotiate";
+        public const string Ntlm = "NTLM";
+    }
+}
diff --git a/src/IISIntegration/src/Microsoft.AspNetCore.Server.IISIntegration/IISHostingStartup.cs b/src/IISIntegration/src/Microsoft.AspNetCore.Server.IISIntegration/IISHostingStartup.cs
new file mode 100644
index 0000000000000000000000000000000000000000..d701dc3181158b4f9ab32ebb1bc037a911f37ce5
--- /dev/null
+++ b/src/IISIntegration/src/Microsoft.AspNetCore.Server.IISIntegration/IISHostingStartup.cs
@@ -0,0 +1,17 @@
+// 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 Microsoft.AspNetCore.Hosting;
+
+[assembly: HostingStartup(typeof(Microsoft.AspNetCore.Server.IISIntegration.IISHostingStartup))]
+
+namespace Microsoft.AspNetCore.Server.IISIntegration
+{
+    public class IISHostingStartup : IHostingStartup
+    {
+        public void Configure(IWebHostBuilder builder)
+        {
+            builder.UseIISIntegration();
+        }
+    }
+}
diff --git a/src/IISIntegration/src/Microsoft.AspNetCore.Server.IISIntegration/IISMiddleware.cs b/src/IISIntegration/src/Microsoft.AspNetCore.Server.IISIntegration/IISMiddleware.cs
new file mode 100644
index 0000000000000000000000000000000000000000..013b15adfc23c72f2c726ac20d1c5a4a7b641ae1
--- /dev/null
+++ b/src/IISIntegration/src/Microsoft.AspNetCore.Server.IISIntegration/IISMiddleware.cs
@@ -0,0 +1,150 @@
+// 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.Diagnostics;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Authentication;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Http.Features;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Options;
+using Microsoft.Extensions.Primitives;
+
+namespace Microsoft.AspNetCore.Server.IISIntegration
+{
+    public class IISMiddleware
+    {
+        private const string MSAspNetCoreClientCert = "MS-ASPNETCORE-CLIENTCERT";
+        private const string MSAspNetCoreToken = "MS-ASPNETCORE-TOKEN";
+        private const string MSAspNetCoreEvent = "MS-ASPNETCORE-EVENT";
+        private const string ANCMShutdownEventHeaderValue = "shutdown";
+        private static readonly PathString ANCMRequestPath = new PathString("/iisintegration");
+
+        private readonly RequestDelegate _next;
+        private readonly IISOptions _options;
+        private readonly ILogger _logger;
+        private readonly string _pairingToken;
+        private readonly IApplicationLifetime _applicationLifetime;
+        private readonly bool _isWebsocketsSupported;
+
+        // 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)
+            {
+                throw new ArgumentNullException(nameof(next));
+            }
+            if (loggerFactory == null)
+            {
+                throw new ArgumentNullException(nameof(loggerFactory));
+            }
+            if (options == null)
+            {
+                throw new ArgumentNullException(nameof(options));
+            }
+            if (applicationLifetime == null)
+            {
+                throw new ArgumentNullException(nameof(applicationLifetime));
+            }
+            if (string.IsNullOrEmpty(pairingToken))
+            {
+                throw new ArgumentException("Missing or empty pairing token.");
+            }
+
+            _next = next;
+            _options = options.Value;
+
+            if (_options.ForwardWindowsAuthentication)
+            {
+                authentication.AddScheme(new AuthenticationScheme(IISDefaults.AuthenticationScheme, _options.AuthenticationDisplayName, typeof(AuthenticationHandler)));
+            }
+
+            _pairingToken = pairingToken;
+            _applicationLifetime = applicationLifetime;
+            _logger = loggerFactory.CreateLogger<IISMiddleware>();
+            _isWebsocketsSupported = isWebsocketsSupported;
+        }
+
+        public async Task Invoke(HttpContext httpContext)
+        {
+            if (!string.Equals(_pairingToken, httpContext.Request.Headers[MSAspNetCoreToken], StringComparison.Ordinal))
+            {
+                _logger.LogError($"'{MSAspNetCoreToken}' does not match the expected pairing token '{_pairingToken}', request rejected.");
+                httpContext.Response.StatusCode = StatusCodes.Status400BadRequest;
+                return;
+            }
+
+            // Handle shutdown from ANCM
+            if (HttpMethods.IsPost(httpContext.Request.Method) &&
+                httpContext.Request.Path.Equals(ANCMRequestPath) &&
+                string.Equals(ANCMShutdownEventHeaderValue, httpContext.Request.Headers[MSAspNetCoreEvent], StringComparison.OrdinalIgnoreCase))
+            {
+                // Execute shutdown task on background thread without waiting for completion
+                var shutdownTask = Task.Run(() => _applicationLifetime.StopApplication());
+                httpContext.Response.StatusCode = StatusCodes.Status202Accepted;
+                return;
+            }
+
+            if (Debugger.IsAttached && string.Equals("DEBUG", httpContext.Request.Method, StringComparison.OrdinalIgnoreCase))
+            {
+                // The Visual Studio debugger tooling sends a DEBUG request to make IIS & AspNetCoreModule launch the process
+                // so the debugger can attach. Filter out this request from the app.
+                return;
+            }
+
+            var bodySizeFeature = httpContext.Features.Get<IHttpMaxRequestBodySizeFeature>();
+            if (bodySizeFeature != null && !bodySizeFeature.IsReadOnly)
+            {
+                // IIS already limits this, no need to do it twice.
+                bodySizeFeature.MaxRequestBodySize = null;
+            }
+
+            if (_options.ForwardClientCertificate)
+            {
+                var header = httpContext.Request.Headers[MSAspNetCoreClientCert];
+                if (!StringValues.IsNullOrEmpty(header))
+                {
+                    httpContext.Features.Set<ITlsConnectionFeature>(new ForwardedTlsConnectionFeature(_logger, header));
+                }
+            }
+
+            if (_options.ForwardWindowsAuthentication)
+            {
+                // We must always process and clean up the windows identity, even if we don't assign the User.
+                var result = await httpContext.AuthenticateAsync(IISDefaults.AuthenticationScheme);
+                if (result.Succeeded && _options.AutomaticAuthentication)
+                {
+                    httpContext.User = result.Principal;
+                }
+            }
+
+            // 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);
+        }
+    }
+}
diff --git a/src/IISIntegration/src/Microsoft.AspNetCore.Server.IISIntegration/IISOptions.cs b/src/IISIntegration/src/Microsoft.AspNetCore.Server.IISIntegration/IISOptions.cs
new file mode 100644
index 0000000000000000000000000000000000000000..efd9eec1f3d3c66f324bea4d4c8bf5a29e062cee
--- /dev/null
+++ b/src/IISIntegration/src/Microsoft.AspNetCore.Server.IISIntegration/IISOptions.cs
@@ -0,0 +1,31 @@
+// 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.
+
+namespace Microsoft.AspNetCore.Builder
+{
+    public class IISOptions
+    {
+        /// <summary>
+        /// If true the middleware should set HttpContext.User. If false the middleware will only provide an
+        /// identity when explicitly requested by the AuthenticationScheme.
+        /// Note Windows Authentication must also be enabled in IIS for this to work.
+        /// </summary>
+        public bool AutomaticAuthentication { get; set; } = true;
+
+        /// <summary>
+        /// Sets the display name shown to users on login pages. The default is null.
+        /// </summary>
+        public string AuthenticationDisplayName { get; set; }
+
+        /// <summary>
+        /// Used to indicate if the authentication handler should be registered. This is only done if ANCM indicates
+        /// IIS has a non-anonymous authentication enabled, or for back compat with ANCMs that did not provide this information.
+        /// </summary>
+        internal bool ForwardWindowsAuthentication { get; set; } = true;
+
+        /// <summary>
+        /// Populates the ITLSConnectionFeature if the MS-ASPNETCORE-CLIENTCERT request header is present.
+        /// </summary>
+        public bool ForwardClientCertificate { get; set; } = true;
+    }
+}
diff --git a/src/IISIntegration/src/Microsoft.AspNetCore.Server.IISIntegration/IISSetupFilter.cs b/src/IISIntegration/src/Microsoft.AspNetCore.Server.IISIntegration/IISSetupFilter.cs
new file mode 100644
index 0000000000000000000000000000000000000000..cb2d97f0f7bdb38638a28db27bda9b8dd8444cdb
--- /dev/null
+++ b/src/IISIntegration/src/Microsoft.AspNetCore.Server.IISIntegration/IISSetupFilter.cs
@@ -0,0 +1,35 @@
+// 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 Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.AspNetCore.Http;
+
+namespace Microsoft.AspNetCore.Server.IISIntegration
+{
+    internal class IISSetupFilter : IStartupFilter
+    {
+        private readonly string _pairingToken;
+        private readonly PathString _pathBase;
+        private readonly bool _isWebsocketsSupported;
+
+        internal IISSetupFilter(string pairingToken, PathString pathBase, bool isWebsocketsSupported)
+        {
+            _pairingToken = pairingToken;
+            _pathBase = pathBase;
+            _isWebsocketsSupported = isWebsocketsSupported;
+        }
+
+        public Action<IApplicationBuilder> Configure(Action<IApplicationBuilder> next)
+        {
+            return app =>
+            {
+                app.UsePathBase(_pathBase);
+                app.UseForwardedHeaders();
+                app.UseMiddleware<IISMiddleware>(_pairingToken, _isWebsocketsSupported);
+                next(app);
+            };
+        }
+    }
+}
diff --git a/src/IISIntegration/src/Microsoft.AspNetCore.Server.IISIntegration/Microsoft.AspNetCore.Server.IISIntegration.csproj b/src/IISIntegration/src/Microsoft.AspNetCore.Server.IISIntegration/Microsoft.AspNetCore.Server.IISIntegration.csproj
new file mode 100644
index 0000000000000000000000000000000000000000..9ec5253b3937343d2dccd167b23c8e10517ad6b2
--- /dev/null
+++ b/src/IISIntegration/src/Microsoft.AspNetCore.Server.IISIntegration/Microsoft.AspNetCore.Server.IISIntegration.csproj
@@ -0,0 +1,29 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <Description>ASP.NET Core components for working with the IIS AspNetCoreModule.</Description>
+    <TargetFramework>netstandard2.0</TargetFramework>
+    <NoWarn>$(NoWarn);CS1591</NoWarn>
+    <GenerateDocumentationFile>true</GenerateDocumentationFile>
+    <PackageTags>aspnetcore;iis</PackageTags>
+    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <PackageReference Include="System.Numerics.Vectors" Version="$(SystemNumericsVectorsPackageVersion)" />
+    <PackageReference Include="System.Buffers" Version="$(SystemBuffersPackageVersion)" />
+    <PackageReference Include="System.IO.Pipelines" Version="$(SystemIOPipelinesPackageVersion)" />
+    <PackageReference Include="System.Memory" Version="$(SystemMemoryPackageVersion)" />
+    <PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="$(SystemRuntimeCompilerServicesUnsafePackageVersion)" />
+    <PackageReference Include="System.Security.Principal.Windows" Version="$(SystemSecurityPrincipalWindowsPackageVersion)" />
+    <PackageReference Include="Microsoft.AspNetCore.Authentication.Core" Version="$(MicrosoftAspNetCoreAuthenticationCorePackageVersion)" />
+    <PackageReference Include="Microsoft.AspNetCore.Hosting.Abstractions" Version="$(MicrosoftAspNetCoreHostingAbstractionsPackageVersion)" />
+    <PackageReference Include="Microsoft.AspNetCore.Http" Version="$(MicrosoftAspNetCoreHttpPackageVersion)" />
+    <PackageReference Include="Microsoft.AspNetCore.Http.Extensions" Version="$(MicrosoftAspNetCoreHttpExtensionsPackageVersion)" />
+    <PackageReference Include="Microsoft.AspNetCore.HttpOverrides" Version="$(MicrosoftAspNetCoreHttpOverridesPackageVersion)" />
+    <PackageReference Include="Microsoft.AspNetCore.HttpSys.Sources" PrivateAssets="All" Version="$(MicrosoftAspNetCoreHttpSysSourcesPackageVersion)" />
+    <PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="$(MicrosoftExtensionsLoggingAbstractionsPackageVersion)" />
+    <PackageReference Include="Microsoft.Extensions.Options" Version="$(MicrosoftExtensionsOptionsPackageVersion)" />
+  </ItemGroup>
+
+</Project>
diff --git a/src/IISIntegration/src/Microsoft.AspNetCore.Server.IISIntegration/NativeMethods.cs b/src/IISIntegration/src/Microsoft.AspNetCore.Server.IISIntegration/NativeMethods.cs
new file mode 100644
index 0000000000000000000000000000000000000000..4ecb5018a27e26e37b17de8421c3a1f1fce20799
--- /dev/null
+++ b/src/IISIntegration/src/Microsoft.AspNetCore.Server.IISIntegration/NativeMethods.cs
@@ -0,0 +1,18 @@
+// 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.Runtime.InteropServices;
+using Microsoft.AspNetCore.HttpSys.Internal;
+
+namespace Microsoft.AspNetCore.Server.IISIntegration
+{
+    internal static class NativeMethods
+    {
+        private const string KERNEL32 = "kernel32.dll";
+
+        [DllImport(KERNEL32, ExactSpelling = true, SetLastError = true)]
+
+        public static extern bool CloseHandle(IntPtr handle);
+    }
+}
diff --git a/src/IISIntegration/src/Microsoft.AspNetCore.Server.IISIntegration/Properties/AssemblyInfo.cs b/src/IISIntegration/src/Microsoft.AspNetCore.Server.IISIntegration/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000000000000000000000000000000000000..f08839f8425d443e2049174260e66d12a9737165
--- /dev/null
+++ b/src/IISIntegration/src/Microsoft.AspNetCore.Server.IISIntegration/Properties/AssemblyInfo.cs
@@ -0,0 +1,7 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System.Runtime.CompilerServices;
+
+[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Server.IISIntegration.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
+
diff --git a/src/IISIntegration/src/Microsoft.AspNetCore.Server.IISIntegration/WebHostBuilderIISExtensions.cs b/src/IISIntegration/src/Microsoft.AspNetCore.Server.IISIntegration/WebHostBuilderIISExtensions.cs
new file mode 100644
index 0000000000000000000000000000000000000000..b57ad38b009414ade6ebcf721052d674d718906c
--- /dev/null
+++ b/src/IISIntegration/src/Microsoft.AspNetCore.Server.IISIntegration/WebHostBuilderIISExtensions.cs
@@ -0,0 +1,104 @@
+// 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.Runtime.InteropServices;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.HttpOverrides;
+using Microsoft.AspNetCore.Server.IISIntegration;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.AspNetCore.Hosting.Server;
+
+namespace Microsoft.AspNetCore.Hosting
+{
+    public static class WebHostBuilderIISExtensions
+    {
+        // These are defined as ASPNETCORE_ environment variables by IIS's AspNetCoreModule.
+        private static readonly string ServerPort = "PORT";
+        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.
+        /// The app will also be configured to capture startup errors.
+        /// </summary>
+        /// <param name="hostBuilder"></param>
+        /// <returns></returns>
+        public static IWebHostBuilder UseIISIntegration(this IWebHostBuilder hostBuilder)
+        {
+            if (hostBuilder == null)
+            {
+                throw new ArgumentNullException(nameof(hostBuilder));
+            }
+
+            // Check if `UseIISIntegration` was called already
+            if (hostBuilder.GetSetting(nameof(UseIISIntegration)) != null)
+            {
+                return hostBuilder;
+            }
+
+            var port = hostBuilder.GetSetting(ServerPort) ?? Environment.GetEnvironmentVariable($"ASPNETCORE_{ServerPort}");
+            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))
+            {
+                // Set flag to prevent double service configuration
+                hostBuilder.UseSetting(nameof(UseIISIntegration), true.ToString());
+
+                var enableAuth = false;
+                if (string.IsNullOrEmpty(iisAuth))
+                {
+                    // back compat with older ANCM versions
+                    enableAuth = true;
+                }
+                else
+                {
+                    // Lightup a new ANCM variable that tells us if auth is enabled.
+                    foreach (var authType in iisAuth.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries))
+                    {
+                        if (!string.Equals(authType, "anonymous", StringComparison.OrdinalIgnoreCase))
+                        {
+                            enableAuth = true;
+                            break;
+                        }
+                    }
+                }
+
+                var address = "http://127.0.0.1:" + port;
+                hostBuilder.CaptureStartupErrors(true);
+
+                hostBuilder.ConfigureServices(services =>
+                {
+                    // 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), isWebSocketsSupported));
+                    services.Configure<ForwardedHeadersOptions>(options =>
+                    {
+                        options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
+                    });
+                    services.Configure<IISOptions>(options =>
+                    {
+                        options.ForwardWindowsAuthentication = enableAuth;
+                    });
+                    services.AddAuthenticationCore();
+                });
+            }
+
+            return hostBuilder;
+        }
+    }
+}
diff --git a/src/IISIntegration/src/Microsoft.AspNetCore.Server.IISIntegration/baseline.netcore.json b/src/IISIntegration/src/Microsoft.AspNetCore.Server.IISIntegration/baseline.netcore.json
new file mode 100644
index 0000000000000000000000000000000000000000..8cb928a411ce3d638f08f4b177367156ce548947
--- /dev/null
+++ b/src/IISIntegration/src/Microsoft.AspNetCore.Server.IISIntegration/baseline.netcore.json
@@ -0,0 +1,247 @@
+{
+  "AssemblyIdentity": "Microsoft.AspNetCore.Server.IISIntegration, Version=2.0.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60",
+  "Types": [
+    {
+      "Name": "Microsoft.AspNetCore.Hosting.WebHostBuilderIISExtensions",
+      "Visibility": "Public",
+      "Kind": "Class",
+      "Abstract": true,
+      "Static": true,
+      "Sealed": true,
+      "ImplementedInterfaces": [],
+      "Members": [
+        {
+          "Kind": "Method",
+          "Name": "UseIISIntegration",
+          "Parameters": [
+            {
+              "Name": "hostBuilder",
+              "Type": "Microsoft.AspNetCore.Hosting.IWebHostBuilder"
+            }
+          ],
+          "ReturnType": "Microsoft.AspNetCore.Hosting.IWebHostBuilder",
+          "Static": true,
+          "Extension": true,
+          "Visibility": "Public",
+          "GenericParameter": []
+        }
+      ],
+      "GenericParameters": []
+    },
+    {
+      "Name": "Microsoft.AspNetCore.Builder.IISOptions",
+      "Visibility": "Public",
+      "Kind": "Class",
+      "ImplementedInterfaces": [],
+      "Members": [
+        {
+          "Kind": "Method",
+          "Name": "get_AutomaticAuthentication",
+          "Parameters": [],
+          "ReturnType": "System.Boolean",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "set_AutomaticAuthentication",
+          "Parameters": [
+            {
+              "Name": "value",
+              "Type": "System.Boolean"
+            }
+          ],
+          "ReturnType": "System.Void",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "get_AuthenticationDisplayName",
+          "Parameters": [],
+          "ReturnType": "System.String",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "set_AuthenticationDisplayName",
+          "Parameters": [
+            {
+              "Name": "value",
+              "Type": "System.String"
+            }
+          ],
+          "ReturnType": "System.Void",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "get_ForwardClientCertificate",
+          "Parameters": [],
+          "ReturnType": "System.Boolean",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "set_ForwardClientCertificate",
+          "Parameters": [
+            {
+              "Name": "value",
+              "Type": "System.Boolean"
+            }
+          ],
+          "ReturnType": "System.Void",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Constructor",
+          "Name": ".ctor",
+          "Parameters": [],
+          "Visibility": "Public",
+          "GenericParameter": []
+        }
+      ],
+      "GenericParameters": []
+    },
+    {
+      "Name": "Microsoft.AspNetCore.Server.IISIntegration.IISDefaults",
+      "Visibility": "Public",
+      "Kind": "Class",
+      "ImplementedInterfaces": [],
+      "Members": [
+        {
+          "Kind": "Constructor",
+          "Name": ".ctor",
+          "Parameters": [],
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Field",
+          "Name": "AuthenticationScheme",
+          "Parameters": [],
+          "ReturnType": "System.String",
+          "Static": true,
+          "ReadOnly": true,
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Field",
+          "Name": "Negotiate",
+          "Parameters": [],
+          "ReturnType": "System.String",
+          "Static": true,
+          "Visibility": "Public",
+          "GenericParameter": [],
+          "Constant": true,
+          "Literal": "\"Negotiate\""
+        },
+        {
+          "Kind": "Field",
+          "Name": "Ntlm",
+          "Parameters": [],
+          "ReturnType": "System.String",
+          "Static": true,
+          "Visibility": "Public",
+          "GenericParameter": [],
+          "Constant": true,
+          "Literal": "\"NTLM\""
+        }
+      ],
+      "GenericParameters": []
+    },
+    {
+      "Name": "Microsoft.AspNetCore.Server.IISIntegration.IISHostingStartup",
+      "Visibility": "Public",
+      "Kind": "Class",
+      "ImplementedInterfaces": [
+        "Microsoft.AspNetCore.Hosting.IHostingStartup"
+      ],
+      "Members": [
+        {
+          "Kind": "Method",
+          "Name": "Configure",
+          "Parameters": [
+            {
+              "Name": "builder",
+              "Type": "Microsoft.AspNetCore.Hosting.IWebHostBuilder"
+            }
+          ],
+          "ReturnType": "System.Void",
+          "Sealed": true,
+          "Virtual": true,
+          "ImplementedInterface": "Microsoft.AspNetCore.Hosting.IHostingStartup",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Constructor",
+          "Name": ".ctor",
+          "Parameters": [],
+          "Visibility": "Public",
+          "GenericParameter": []
+        }
+      ],
+      "GenericParameters": []
+    },
+    {
+      "Name": "Microsoft.AspNetCore.Server.IISIntegration.IISMiddleware",
+      "Visibility": "Public",
+      "Kind": "Class",
+      "ImplementedInterfaces": [],
+      "Members": [
+        {
+          "Kind": "Method",
+          "Name": "Invoke",
+          "Parameters": [
+            {
+              "Name": "httpContext",
+              "Type": "Microsoft.AspNetCore.Http.HttpContext"
+            }
+          ],
+          "ReturnType": "System.Threading.Tasks.Task",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Constructor",
+          "Name": ".ctor",
+          "Parameters": [
+            {
+              "Name": "next",
+              "Type": "Microsoft.AspNetCore.Http.RequestDelegate"
+            },
+            {
+              "Name": "loggerFactory",
+              "Type": "Microsoft.Extensions.Logging.ILoggerFactory"
+            },
+            {
+              "Name": "options",
+              "Type": "Microsoft.Extensions.Options.IOptions<Microsoft.AspNetCore.Builder.IISOptions>"
+            },
+            {
+              "Name": "pairingToken",
+              "Type": "System.String"
+            },
+            {
+              "Name": "authentication",
+              "Type": "Microsoft.AspNetCore.Authentication.IAuthenticationSchemeProvider"
+            },
+            {
+              "Name": "applicationLifetime",
+              "Type": "Microsoft.AspNetCore.Hosting.IApplicationLifetime"
+            }
+          ],
+          "Visibility": "Public",
+          "GenericParameter": []
+        }
+      ],
+      "GenericParameters": []
+    }
+  ]
+}
\ No newline at end of file
diff --git a/src/IISIntegration/test/AspNetCoreModuleTests/AspNetCoreModuleTests.vcxproj b/src/IISIntegration/test/AspNetCoreModuleTests/AspNetCoreModuleTests.vcxproj
new file mode 100644
index 0000000000000000000000000000000000000000..8f12548e9f977341575a6c5ea32873269e08922b
--- /dev/null
+++ b/src/IISIntegration/test/AspNetCoreModuleTests/AspNetCoreModuleTests.vcxproj
@@ -0,0 +1,184 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|Win32">
+      <Configuration>Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Debug|x64">
+      <Configuration>Debug</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|x64">
+      <Configuration>Release</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <VCProjectVersion>15.0</VCProjectVersion>
+    <ProjectGuid>{0692D963-DB10-4387-B3EA-460FBB9BD9A3}</ProjectGuid>
+    <Keyword>Win32Proj</Keyword>
+    <RootNamespace>AspNetCoreModuleTests</RootNamespace>
+    <WindowsTargetPlatformVersion>10.0.15063.0</WindowsTargetPlatformVersion>
+    <ProjectSubType>NativeUnitTestProject</ProjectSubType>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+    <ConfigurationType>DynamicLibrary</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <PlatformToolset>v141</PlatformToolset>
+    <CharacterSet>Unicode</CharacterSet>
+    <UseOfMfc>false</UseOfMfc>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+    <ConfigurationType>DynamicLibrary</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <PlatformToolset>v141</PlatformToolset>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+    <UseOfMfc>false</UseOfMfc>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+    <ConfigurationType>DynamicLibrary</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <PlatformToolset>v141</PlatformToolset>
+    <CharacterSet>Unicode</CharacterSet>
+    <UseOfMfc>false</UseOfMfc>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+    <ConfigurationType>DynamicLibrary</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <PlatformToolset>v141</PlatformToolset>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+    <UseOfMfc>false</UseOfMfc>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Label="Shared">
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <LinkIncremental>true</LinkIncremental>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <LinkIncremental>true</LinkIncremental>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <LinkIncremental>true</LinkIncremental>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <LinkIncremental>true</LinkIncremental>
+  </PropertyGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <ClCompile>
+      <PrecompiledHeader>Use</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <AdditionalIncludeDirectories>$(VCInstallDir)UnitTest\include;%(AdditionalIncludeDirectories);..\..\src\AspNetCoreModuleV2\CommonLib;..\..\src\AspNetCoreModuleV2\IISLib</AdditionalIncludeDirectories>
+      <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <UseFullPaths>true</UseFullPaths>
+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <AdditionalLibraryDirectories>$(VCInstallDir)UnitTest\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>Use</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <AdditionalIncludeDirectories>$(VCInstallDir)UnitTest\include;%(AdditionalIncludeDirectories);..\..\src\AspNetCoreModuleV2\CommonLib;..\..\src\AspNetCoreModuleV2\IISLib</AdditionalIncludeDirectories>
+      <PreprocessorDefinitions>WIN32;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <UseFullPaths>true</UseFullPaths>
+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <AdditionalLibraryDirectories>$(VCInstallDir)UnitTest\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <PrecompiledHeader>Use</PrecompiledHeader>
+      <Optimization>MaxSpeed</Optimization>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <AdditionalIncludeDirectories>$(VCInstallDir)UnitTest\include;%(AdditionalIncludeDirectories);..\..\src\AspNetCoreModuleV2\CommonLib;..\..\src\AspNetCoreModuleV2\IISLib</AdditionalIncludeDirectories>
+      <PreprocessorDefinitions>WIN32;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <UseFullPaths>true</UseFullPaths>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+      <AdditionalLibraryDirectories>$(VCInstallDir)UnitTest\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <PrecompiledHeader>Use</PrecompiledHeader>
+      <Optimization>MaxSpeed</Optimization>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <AdditionalIncludeDirectories>$(VCInstallDir)UnitTest\include;%(AdditionalIncludeDirectories);..\..\src\AspNetCoreModuleV2\CommonLib;..\..\src\AspNetCoreModuleV2\IISLib</AdditionalIncludeDirectories>
+      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <UseFullPaths>true</UseFullPaths>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+      <AdditionalLibraryDirectories>$(VCInstallDir)UnitTest\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemGroup>
+    <ClInclude Include="stdafx.h" />
+    <ClInclude Include="targetver.h" />
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="stdafx.cpp">
+      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
+      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
+      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
+      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
+    </ClCompile>
+    <ClCompile Include="hostfxr_utility_tests.cpp" />
+    <ClCompile Include="utility_tests.cpp" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\..\src\AspNetCoreModuleV2\CommonLib\CommonLib.vcxproj">
+      <Project>{55494e58-e061-4c4c-a0a8-837008e72f85}</Project>
+    </ProjectReference>
+    <ProjectReference Include="..\..\src\AspNetCoreModuleV2\IISLib\IISLib.vcxproj">
+      <Project>{4787a64f-9a3e-4867-a55a-70cb4b2b2ffe}</Project>
+    </ProjectReference>
+  </ItemGroup>
+  <Import Project=".\NativeTests.targets" />
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  </ImportGroup>
+</Project>
\ No newline at end of file
diff --git a/src/IISIntegration/test/AspNetCoreModuleTests/stdafx.h b/src/IISIntegration/test/AspNetCoreModuleTests/stdafx.h
new file mode 100644
index 0000000000000000000000000000000000000000..67bd5aa27b8217ff585757c6ac9337fed2f091fb
--- /dev/null
+++ b/src/IISIntegration/test/AspNetCoreModuleTests/stdafx.h
@@ -0,0 +1,56 @@
+// 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 "targetver.h"
+
+#define WIN32_LEAN_AND_MEAN
+
+#include <Windows.h>
+#include <atlbase.h>
+#include <pdh.h>
+#include <vector>
+#include <Shlobj.h>
+#include <httpserv.h>
+#include <winhttp.h>
+#include <httptrace.h>
+#include <cstdlib>
+#include <wchar.h>
+#include <io.h>
+#include <stdio.h>
+
+#include <hashfn.h>
+#include <hashtable.h>
+#include "stringa.h"
+#include "stringu.h"
+#include "dbgutil.h"
+#include "ahutil.h"
+#include "multisz.h"
+#include "multisza.h"
+#include "base64.h"
+#include <listentry.h>
+#include <datetime.h>
+#include <reftrace.h>
+#include <acache.h>
+#include <time.h>
+
+#include "..\..\src\AspNetCoreModuleV2\IISLib\hashtable.h"
+#include "..\..\src\AspNetCoreModuleV2\IISLib\stringu.h"
+#include "..\..\src\AspNetCoreModuleV2\IISLib\stringa.h"
+#include "..\..\src\AspNetCoreModuleV2\IISLib\multisz.h"
+#include "..\..\src\AspNetCoreModuleV2\IISLib\dbgutil.h"
+#include "..\..\src\AspNetCoreModuleV2\IISLib\ahutil.h"
+#include "..\..\src\AspNetCoreModuleV2\IISLib\hashfn.h"
+
+#include "..\..\src\AspNetCoreModuleV2\CommonLib\hostfxr_utility.h"
+#include "..\..\src\AspNetCoreModuleV2\CommonLib\environmentvariablehash.h"
+#include "..\..\src\AspNetCoreModuleV2\CommonLib\aspnetcoreconfig.h"
+#include "..\..\src\AspNetCoreModuleV2\CommonLib\application.h"
+#include "..\..\src\AspNetCoreModuleV2\CommonLib\utility.h"
+#include "..\..\src\AspNetCoreModuleV2\CommonLib\debugutil.h"
+#include "..\..\src\AspNetCoreModuleV2\CommonLib\requesthandler.h"
+#include "..\..\src\AspNetCoreModuleV2\CommonLib\resources.h"
+#include "..\..\src\AspNetCoreModuleV2\CommonLib\aspnetcore_msg.h"
+
+#include "CppUnitTest.h"
diff --git a/src/IISIntegration/test/Directory.Build.props b/src/IISIntegration/test/Directory.Build.props
new file mode 100644
index 0000000000000000000000000000000000000000..3a74fe4d2a7d959684dac438a78fe1741bce4b2a
--- /dev/null
+++ b/src/IISIntegration/test/Directory.Build.props
@@ -0,0 +1,14 @@
+<Project>
+  <Import Project="..\Directory.Build.props" />
+
+  <PropertyGroup>
+    <DeveloperBuildTestTfms>netcoreapp2.1</DeveloperBuildTestTfms>
+    <StandardTestTfms>$(DeveloperBuildTestTfms)</StandardTestTfms>
+    <StandardTestTfms Condition=" '$(DeveloperBuild)' != 'true' ">$(StandardTestTfms);netcoreapp2.0</StandardTestTfms>
+    <StandardTestTfms Condition=" '$(DeveloperBuild)' != 'true' AND '$(OS)' == 'Windows_NT' ">$(StandardTestTfms);net461</StandardTestTfms>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <PackageReference Include="Internal.AspNetCore.Sdk" PrivateAssets="All" Version="$(InternalAspNetCoreSdkPackageVersion)" />
+  </ItemGroup>
+</Project>
diff --git a/src/IISIntegration/test/IISIntegration.FunctionalTests/AppHostConfig/Http.config b/src/IISIntegration/test/IISIntegration.FunctionalTests/AppHostConfig/Http.config
new file mode 100644
index 0000000000000000000000000000000000000000..18a1aa2e22077ad137768da4e08891ac21b402c0
--- /dev/null
+++ b/src/IISIntegration/test/IISIntegration.FunctionalTests/AppHostConfig/Http.config
@@ -0,0 +1,1040 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    IIS configuration sections.
+
+    For schema documentation, see
+    %IIS_BIN%\config\schema\IIS_schema.xml.
+    
+    Please make a backup of this file before making any changes to it.
+
+    NOTE: The following environment variables are available to be used
+          within this file and are understood by the IIS Express.
+
+          %IIS_USER_HOME% - The IIS Express home directory for the user
+          %IIS_SITES_HOME% - The default home directory for sites
+          %IIS_BIN% - The location of the IIS Express binaries
+          %SYSTEMDRIVE% - The drive letter of %IIS_BIN%
+
+-->
+
+<configuration>
+
+  <!--
+
+        The <configSections> section controls the registration of sections.
+        Section is the basic unit of deployment, locking, searching and
+        containment for configuration settings.
+        
+        Every section belongs to one section group.
+        A section group is a container of logically-related sections.
+        
+        Sections cannot be nested.
+        Section groups may be nested.
+        
+        <section
+            name=""  [Required, Collection Key] [XML name of the section]
+            allowDefinition="Everywhere" [MachineOnly|MachineToApplication|AppHostOnly|Everywhere] [Level where it can be set]
+            overrideModeDefault="Allow"  [Allow|Deny] [Default delegation mode]
+            allowLocation="true"  [true|false] [Allowed in location tags]
+        />
+        
+        The recommended way to unlock sections is by using a location tag:
+        <location path="Default Web Site" overrideMode="Allow">
+            <system.webServer>
+                <asp />
+            </system.webServer>
+        </location>
+
+    -->
+  <configSections>
+    <sectionGroup name="system.applicationHost">
+      <section name="applicationPools" allowDefinition="AppHostOnly" overrideModeDefault="Deny" />
+      <section name="configHistory" allowDefinition="AppHostOnly" overrideModeDefault="Deny" />
+      <section name="customMetadata" allowDefinition="AppHostOnly" overrideModeDefault="Deny" />
+      <section name="listenerAdapters" allowDefinition="AppHostOnly" overrideModeDefault="Deny" />
+      <section name="log" allowDefinition="AppHostOnly" overrideModeDefault="Deny" />
+      <section name="preloadProviders" allowDefinition="AppHostOnly" overrideModeDefault="Deny" />
+      <section name="sites" allowDefinition="AppHostOnly" overrideModeDefault="Deny" />
+      <section name="webLimits" allowDefinition="AppHostOnly" overrideModeDefault="Deny" />
+    </sectionGroup>
+
+    <sectionGroup name="system.webServer">
+      <section name="asp" overrideModeDefault="Deny" />
+      <section name="caching" overrideModeDefault="Allow" />
+      <section name="cgi" overrideModeDefault="Deny" />
+      <section name="defaultDocument" overrideModeDefault="Allow" />
+      <section name="directoryBrowse" overrideModeDefault="Allow" />
+      <section name="fastCgi" allowDefinition="AppHostOnly" overrideModeDefault="Deny" />
+      <section name="globalModules" allowDefinition="AppHostOnly" overrideModeDefault="Deny" />
+      <section name="handlers" overrideModeDefault="Deny" />
+      <section name="httpCompression" allowDefinition="AppHostOnly" overrideModeDefault="Deny" />
+      <section name="httpErrors" overrideModeDefault="Allow" />
+      <section name="httpLogging" overrideModeDefault="Deny" />
+      <section name="httpProtocol" overrideModeDefault="Allow" />
+      <section name="httpRedirect" overrideModeDefault="Allow" />
+      <section name="httpTracing" overrideModeDefault="Deny" />
+      <section name="isapiFilters" allowDefinition="MachineToApplication" overrideModeDefault="Deny" />
+      <section name="modules" allowDefinition="MachineToApplication" overrideModeDefault="Deny" />
+      <section name="odbcLogging" overrideModeDefault="Deny" />
+      <sectionGroup name="security">
+        <section name="access" overrideModeDefault="Deny" />
+        <section name="applicationDependencies" overrideModeDefault="Deny" />
+        <sectionGroup name="authentication">
+          <section name="anonymousAuthentication" overrideModeDefault="Deny" />
+          <section name="basicAuthentication" overrideModeDefault="Deny" />
+          <section name="clientCertificateMappingAuthentication" overrideModeDefault="Deny" />
+          <section name="digestAuthentication" overrideModeDefault="Deny" />
+          <section name="iisClientCertificateMappingAuthentication" overrideModeDefault="Deny" />
+          <section name="windowsAuthentication" overrideModeDefault="Deny" />
+        </sectionGroup>
+        <section name="authorization" overrideModeDefault="Allow" />
+        <section name="ipSecurity" overrideModeDefault="Deny" />
+        <section name="dynamicIpSecurity" overrideModeDefault="Deny" />
+        <section name="isapiCgiRestriction" allowDefinition="AppHostOnly" overrideModeDefault="Deny" />
+        <section name="requestFiltering" overrideModeDefault="Allow" />
+      </sectionGroup>
+      <section name="serverRuntime" overrideModeDefault="Deny" />
+      <section name="serverSideInclude" overrideModeDefault="Deny" />
+      <section name="staticContent" overrideModeDefault="Allow" />
+      <sectionGroup name="tracing">
+        <section name="traceFailedRequests" overrideModeDefault="Allow" />
+        <section name="traceProviderDefinitions" overrideModeDefault="Deny" />
+      </sectionGroup>
+      <section name="urlCompression" overrideModeDefault="Allow" />
+      <section name="validation" overrideModeDefault="Allow" />
+      <sectionGroup name="webdav">
+        <section name="globalSettings" overrideModeDefault="Deny" />
+        <section name="authoring" overrideModeDefault="Deny" />
+        <section name="authoringRules" overrideModeDefault="Deny" />
+      </sectionGroup>
+      <sectionGroup name="rewrite">
+        <section name="allowedServerVariables" overrideModeDefault="Deny" />
+        <section name="rules" overrideModeDefault="Allow" />
+        <section name="outboundRules" overrideModeDefault="Allow" />
+        <section name="globalRules" overrideModeDefault="Deny" allowDefinition="AppHostOnly" />
+        <section name="providers" overrideModeDefault="Allow" />
+        <section name="rewriteMaps" overrideModeDefault="Allow" />
+      </sectionGroup>
+      <section name="applicationInitialization" allowDefinition="MachineToApplication" overrideModeDefault="Allow" />
+      <section name="webSocket" overrideModeDefault="Deny" />
+      <section name="aspNetCore" overrideModeDefault="Allow" />
+    </sectionGroup>
+  </configSections>
+
+  <configProtectedData>
+    <providers>
+      <add name="IISWASOnlyRsaProvider" type="" description="Uses RsaCryptoServiceProvider to encrypt and decrypt" keyContainerName="iisWasKey" cspProviderName="" useMachineContainer="true" useOAEP="false" />
+      <add name="AesProvider" type="Microsoft.ApplicationHost.AesProtectedConfigurationProvider" description="Uses an AES session key to encrypt and decrypt" keyContainerName="iisConfigurationKey" cspProviderName="" useOAEP="false" useMachineContainer="true" sessionKey="AQIAAA5mAAAApAAAKmFQvWHDEETRz8l2bjZlRxIkwcqTFaCUnCLljn3Q1OkesrhEO9YyLyx4bUhsj1/DyShAv7OAFFhXlrlomaornnk5PLeyO4lIXxaiT33yOFUUgxDx4GSaygkqghVV0tO5yQ/XguUBp2juMfZyztnsNa4pLcz7ZNZQ6p4yn9hxwNs=" />
+      <add name="IISWASOnlyAesProvider" type="Microsoft.ApplicationHost.AesProtectedConfigurationProvider" description="Uses an AES session key to encrypt and decrypt" keyContainerName="iisWasKey" cspProviderName="" useOAEP="false" useMachineContainer="true" sessionKey="AQIAAA5mAAAApAAA4WoiRJ8KHwzAG8AgejPxEOO4/2Vhkolbwo/8gZeNdUDSD36m55hWv4uC9tr/MlKdnwRLL0NhT50Gccyftqz5xTZ0dg5FtvQhTw/he1NwexTKbV+I4Zrd+sZUqHZTsr7JiEr6OHGXL70qoISW5G2m9U8wKT3caPiDPNj2aAaYPLo=" />
+    </providers>
+  </configProtectedData>
+
+  <system.applicationHost>
+
+    <applicationPools>
+      <add name="Clr4IntegratedAppPool" managedRuntimeVersion="v4.0" managedPipelineMode="Integrated" CLRConfigFile="%IIS_BIN%\config\templates\PersonalWebServer\aspnet.config" autoStart="true" />
+      <add name="Clr4ClassicAppPool" managedRuntimeVersion="v4.0" managedPipelineMode="Classic" CLRConfigFile="%IIS_BIN%\config\templates\PersonalWebServer\aspnet.config" autoStart="true" />
+      <add name="Clr2IntegratedAppPool" managedRuntimeVersion="v2.0" managedPipelineMode="Integrated" CLRConfigFile="%IIS_BIN%\config\templates\PersonalWebServer\aspnet.config" autoStart="true" />
+      <add name="Clr2ClassicAppPool" managedRuntimeVersion="v2.0" managedPipelineMode="Classic" CLRConfigFile="%IIS_BIN%\config\templates\PersonalWebServer\aspnet.config" autoStart="true" />
+      <add name="UnmanagedClassicAppPool" managedRuntimeVersion="" managedPipelineMode="Classic" autoStart="true" />
+      <add name="IISExpressAppPool" managedRuntimeVersion="v4.0" managedPipelineMode="Integrated" CLRConfigFile="%IIS_BIN%\config\templates\PersonalWebServer\aspnet.config" autoStart="true" />
+      <applicationPoolDefaults managedRuntimeLoader="v4.0">
+        <processModel />
+      </applicationPoolDefaults>
+    </applicationPools>
+
+    <!--
+
+          The <listenerAdapters> section defines the protocols with which the
+          Windows Process Activation Service (WAS) binds.
+
+        -->
+    <listenerAdapters>
+      <add name="http" />
+    </listenerAdapters>
+
+    <sites>
+      <site name="HttpTestSite" id="1" serverAutoStart="true">
+        <application path="/">
+          <virtualDirectory path="/" physicalPath="[ApplicationPhysicalPath]" />
+        </application>
+        <bindings>
+          <binding protocol="http" bindingInformation=":[PORT]:localhost" />
+        </bindings>
+      </site>
+      <siteDefaults>
+        <logFile logFormat="W3C" directory="%IIS_USER_HOME%\Logs" />
+        <traceFailedRequestsLogging directory="%IIS_USER_HOME%\TraceLogFiles" enabled="true" maxLogFileSizeKB="1024" />
+      </siteDefaults>
+      <applicationDefaults applicationPool="IISExpressAppPool" />
+      <virtualDirectoryDefaults allowSubDirConfig="true" />
+    </sites>
+
+    <webLimits />
+
+  </system.applicationHost>
+
+  <system.webServer>
+
+    <serverRuntime />
+
+    <asp scriptErrorSentToBrowser="true">
+      <cache diskTemplateCacheDirectory="%TEMP%\iisexpress\ASP Compiled Templates" />
+      <limits />
+    </asp>
+
+    <caching enabled="true" enableKernelCache="true">
+    </caching>
+
+    <cgi />
+
+    <defaultDocument enabled="true">
+      <files>
+        <add value="Default.htm" />
+        <add value="Default.asp" />
+        <add value="index.htm" />
+        <add value="index.html" />
+        <add value="iisstart.htm" />
+        <add value="default.aspx" />
+      </files>
+    </defaultDocument>
+
+    <directoryBrowse enabled="false" />
+
+    <fastCgi />
+
+    <!--
+
+          The <globalModules> section defines all native-code modules.
+          To enable a module, specify it in the <modules> section.
+
+        -->
+    <globalModules>
+      <add name="UriCacheModule" image="%IIS_BIN%\cachuri.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="DynamicCompressionModule" image="%IIS_BIN%\compdyn.dll" />
+      <add name="StaticCompressionModule" image="%IIS_BIN%\compstat.dll" />
+      <add name="DefaultDocumentModule" image="%IIS_BIN%\defdoc.dll" />
+      <add name="DirectoryListingModule" image="%IIS_BIN%\dirlist.dll" />
+      <add name="ProtocolSupportModule" image="%IIS_BIN%\protsup.dll" />
+      <add name="HttpRedirectionModule" image="%IIS_BIN%\redirect.dll" />
+      <add name="ServerSideIncludeModule" image="%IIS_BIN%\iis_ssi.dll" />
+      <add name="StaticFileModule" image="%IIS_BIN%\static.dll" />
+      <add name="AnonymousAuthenticationModule" image="%IIS_BIN%\authanon.dll" />
+      <add name="CertificateMappingAuthenticationModule" image="%IIS_BIN%\authcert.dll" />
+      <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="IISCertificateMappingAuthenticationModule" image="%IIS_BIN%\authmap.dll" />
+      <add name="IpRestrictionModule" image="%IIS_BIN%\iprestr.dll" />
+      <add name="DynamicIpRestrictionModule" image="%IIS_BIN%\diprestr.dll" />
+      <add name="RequestFilteringModule" image="%IIS_BIN%\modrqflt.dll" />
+      <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="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="RewriteModule" image="%IIS_BIN%\rewrite.dll" />
+      <add name="ConfigurationValidationModule" image="%IIS_BIN%\validcfg.dll" />
+      <add name="ApplicationInitializationModule" image="%IIS_BIN%\warmup.dll" />
+      <add name="WebSocketModule" image="%IIS_BIN%\iiswsock.dll" />
+      <add name="WebMatrixSupportModule" image="%IIS_BIN%\webmatrixsup.dll" />
+      <add name="ManagedEngine" image="%windir%\Microsoft.NET\Framework\v2.0.50727\webengine.dll" preCondition="integratedMode,runtimeVersionv2.0,bitness32" />
+      <add name="ManagedEngine64" image="%windir%\Microsoft.NET\Framework64\v2.0.50727\webengine.dll" preCondition="integratedMode,runtimeVersionv2.0,bitness64" />
+      <add name="ManagedEngineV4.0_32bit" image="%windir%\Microsoft.NET\Framework\v4.0.30319\webengine4.dll" preCondition="integratedMode,runtimeVersionv4.0,bitness32" />
+      <add name="ManagedEngineV4.0_64bit" image="%windir%\Microsoft.NET\Framework64\v4.0.30319\webengine4.dll" preCondition="integratedMode,runtimeVersionv4.0,bitness64" />
+      <add name="AspNetCoreModule" image="[ANCMPath]"/>
+    </globalModules>
+
+    <httpCompression directory="%TEMP%\iisexpress\IIS Temporary Compressed Files">
+      <scheme name="gzip" dll="%IIS_BIN%\gzip.dll" />
+      <dynamicTypes>
+        <add mimeType="text/*" enabled="true" />
+        <add mimeType="message/*" enabled="true" />
+        <add mimeType="application/x-javascript" enabled="true" />
+        <add mimeType="*/*" enabled="false" />
+      </dynamicTypes>
+      <staticTypes>
+        <add mimeType="text/*" enabled="true" />
+        <add mimeType="message/*" enabled="true" />
+        <add mimeType="application/x-javascript" enabled="true" />
+        <add mimeType="application/atom+xml" enabled="true" />
+        <add mimeType="application/xaml+xml" enabled="true" />
+        <add mimeType="*/*" enabled="false" />
+      </staticTypes>
+    </httpCompression>
+
+    <httpErrors lockAttributes="allowAbsolutePathsWhenDelegated,defaultPath">
+      <error statusCode="401" prefixLanguageFilePath="%IIS_BIN%\custerr" path="401.htm" />
+      <error statusCode="403" prefixLanguageFilePath="%IIS_BIN%\custerr" path="403.htm" />
+      <error statusCode="404" prefixLanguageFilePath="%IIS_BIN%\custerr" path="404.htm" />
+      <error statusCode="405" prefixLanguageFilePath="%IIS_BIN%\custerr" path="405.htm" />
+      <error statusCode="406" prefixLanguageFilePath="%IIS_BIN%\custerr" path="406.htm" />
+      <error statusCode="412" prefixLanguageFilePath="%IIS_BIN%\custerr" path="412.htm" />
+      <error statusCode="500" prefixLanguageFilePath="%IIS_BIN%\custerr" path="500.htm" />
+      <error statusCode="501" prefixLanguageFilePath="%IIS_BIN%\custerr" path="501.htm" />
+      <error statusCode="502" prefixLanguageFilePath="%IIS_BIN%\custerr" path="502.htm" />
+    </httpErrors>
+
+    <httpLogging dontLog="false" />
+
+    <httpProtocol>
+      <customHeaders>
+        <clear />
+        <add name="X-Powered-By" value="ASP.NET" />
+      </customHeaders>
+      <redirectHeaders>
+        <clear />
+      </redirectHeaders>
+    </httpProtocol>
+
+    <httpRedirect enabled="false" />
+
+    <httpTracing>
+    </httpTracing>
+
+    <isapiFilters>
+      <filter name="ASP.Net_2.0.50727-64" path="%windir%\Microsoft.NET\Framework64\v2.0.50727\aspnet_filter.dll" enableCache="true" preCondition="bitness64,runtimeVersionv2.0" />
+      <filter name="ASP.Net_2.0.50727.0" path="%windir%\Microsoft.NET\Framework\v2.0.50727\aspnet_filter.dll" enableCache="true" preCondition="bitness32,runtimeVersionv2.0" />
+      <filter name="ASP.Net_2.0_for_v1.1" path="%windir%\Microsoft.NET\Framework\v2.0.50727\aspnet_filter.dll" enableCache="true" preCondition="runtimeVersionv1.1" />
+      <filter name="ASP.Net_4.0_32bit" path="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_filter.dll" enableCache="true" preCondition="bitness32,runtimeVersionv4.0" />
+      <filter name="ASP.Net_4.0_64bit" path="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_filter.dll" enableCache="true" preCondition="bitness64,runtimeVersionv4.0" />
+    </isapiFilters>
+
+    <odbcLogging />
+
+    <security>
+
+      <access sslFlags="None" />
+
+      <applicationDependencies>
+        <application name="Active Server Pages" groupId="ASP" />
+      </applicationDependencies>
+
+      <authentication>
+
+        <anonymousAuthentication enabled="true" userName="" />
+
+        <basicAuthentication enabled="false" />
+
+        <clientCertificateMappingAuthentication enabled="false" />
+
+        <digestAuthentication enabled="false" />
+
+        <iisClientCertificateMappingAuthentication enabled="false">
+        </iisClientCertificateMappingAuthentication>
+
+        <windowsAuthentication enabled="false">
+          <providers>
+            <add value="Negotiate" />
+            <add value="NTLM" />
+          </providers>
+        </windowsAuthentication>
+
+      </authentication>
+
+      <authorization>
+        <add accessType="Allow" users="*" />
+      </authorization>
+
+      <ipSecurity allowUnlisted="true" />
+
+      <isapiCgiRestriction notListedIsapisAllowed="true" notListedCgisAllowed="true">
+        <add path="%windir%\Microsoft.NET\Framework64\v4.0.30319\webengine4.dll" allowed="true" groupId="ASP.NET_v4.0" description="ASP.NET_v4.0" />
+        <add path="%windir%\Microsoft.NET\Framework\v4.0.30319\webengine4.dll" allowed="true" groupId="ASP.NET_v4.0" description="ASP.NET_v4.0" />
+        <add path="%windir%\Microsoft.NET\Framework64\v2.0.50727\aspnet_isapi.dll" allowed="true" groupId="ASP.NET v2.0.50727" description="ASP.NET v2.0.50727" />
+        <add path="%windir%\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll" allowed="true" groupId="ASP.NET v2.0.50727" description="ASP.NET v2.0.50727" />
+      </isapiCgiRestriction>
+
+      <requestFiltering>
+        <fileExtensions allowUnlisted="true" applyToWebDAV="true">
+          <add fileExtension=".asa" allowed="false" />
+          <add fileExtension=".asax" allowed="false" />
+          <add fileExtension=".ascx" allowed="false" />
+          <add fileExtension=".master" allowed="false" />
+          <add fileExtension=".skin" allowed="false" />
+          <add fileExtension=".browser" allowed="false" />
+          <add fileExtension=".sitemap" allowed="false" />
+          <add fileExtension=".config" allowed="false" />
+          <add fileExtension=".cs" allowed="false" />
+          <add fileExtension=".csproj" allowed="false" />
+          <add fileExtension=".vb" allowed="false" />
+          <add fileExtension=".vbproj" allowed="false" />
+          <add fileExtension=".webinfo" allowed="false" />
+          <add fileExtension=".licx" allowed="false" />
+          <add fileExtension=".resx" allowed="false" />
+          <add fileExtension=".resources" allowed="false" />
+          <add fileExtension=".mdb" allowed="false" />
+          <add fileExtension=".vjsproj" allowed="false" />
+          <add fileExtension=".java" allowed="false" />
+          <add fileExtension=".jsl" allowed="false" />
+          <add fileExtension=".ldb" allowed="false" />
+          <add fileExtension=".dsdgm" allowed="false" />
+          <add fileExtension=".ssdgm" allowed="false" />
+          <add fileExtension=".lsad" allowed="false" />
+          <add fileExtension=".ssmap" allowed="false" />
+          <add fileExtension=".cd" allowed="false" />
+          <add fileExtension=".dsprototype" allowed="false" />
+          <add fileExtension=".lsaprototype" allowed="false" />
+          <add fileExtension=".sdm" allowed="false" />
+          <add fileExtension=".sdmDocument" allowed="false" />
+          <add fileExtension=".mdf" allowed="false" />
+          <add fileExtension=".ldf" allowed="false" />
+          <add fileExtension=".ad" allowed="false" />
+          <add fileExtension=".dd" allowed="false" />
+          <add fileExtension=".ldd" allowed="false" />
+          <add fileExtension=".sd" allowed="false" />
+          <add fileExtension=".adprototype" allowed="false" />
+          <add fileExtension=".lddprototype" allowed="false" />
+          <add fileExtension=".exclude" allowed="false" />
+          <add fileExtension=".refresh" allowed="false" />
+          <add fileExtension=".compiled" allowed="false" />
+          <add fileExtension=".msgx" allowed="false" />
+          <add fileExtension=".vsdisco" allowed="false" />
+          <add fileExtension=".rules" allowed="false" />
+        </fileExtensions>
+        <verbs allowUnlisted="true" applyToWebDAV="true" />
+        <hiddenSegments applyToWebDAV="true">
+          <add segment="web.config" />
+          <add segment="bin" />
+          <add segment="App_code" />
+          <add segment="App_GlobalResources" />
+          <add segment="App_LocalResources" />
+          <add segment="App_WebReferences" />
+          <add segment="App_Data" />
+          <add segment="App_Browsers" />
+        </hiddenSegments>
+      </requestFiltering>
+
+    </security>
+
+    <serverSideInclude ssiExecDisable="false" />
+
+    <staticContent lockAttributes="isDocFooterFileName">
+      <mimeMap fileExtension=".323" mimeType="text/h323" />
+      <mimeMap fileExtension=".3g2" mimeType="video/3gpp2" />
+      <mimeMap fileExtension=".3gp2" mimeType="video/3gpp2" />
+      <mimeMap fileExtension=".3gp" mimeType="video/3gpp" />
+      <mimeMap fileExtension=".3gpp" mimeType="video/3gpp" />
+      <mimeMap fileExtension=".aac" mimeType="audio/aac" />
+      <mimeMap fileExtension=".aaf" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".aca" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".accdb" mimeType="application/msaccess" />
+      <mimeMap fileExtension=".accde" mimeType="application/msaccess" />
+      <mimeMap fileExtension=".accdt" mimeType="application/msaccess" />
+      <mimeMap fileExtension=".acx" mimeType="application/internet-property-stream" />
+      <mimeMap fileExtension=".adt" mimeType="audio/vnd.dlna.adts" />
+      <mimeMap fileExtension=".adts" mimeType="audio/vnd.dlna.adts" />
+      <mimeMap fileExtension=".afm" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".ai" mimeType="application/postscript" />
+      <mimeMap fileExtension=".aif" mimeType="audio/x-aiff" />
+      <mimeMap fileExtension=".aifc" mimeType="audio/aiff" />
+      <mimeMap fileExtension=".aiff" mimeType="audio/aiff" />
+      <mimeMap fileExtension=".application" mimeType="application/x-ms-application" />
+      <mimeMap fileExtension=".art" mimeType="image/x-jg" />
+      <mimeMap fileExtension=".asd" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".asf" mimeType="video/x-ms-asf" />
+      <mimeMap fileExtension=".asi" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".asm" mimeType="text/plain" />
+      <mimeMap fileExtension=".asr" mimeType="video/x-ms-asf" />
+      <mimeMap fileExtension=".asx" mimeType="video/x-ms-asf" />
+      <mimeMap fileExtension=".atom" mimeType="application/atom+xml" />
+      <mimeMap fileExtension=".au" mimeType="audio/basic" />
+      <mimeMap fileExtension=".avi" mimeType="video/x-msvideo" />
+      <mimeMap fileExtension=".axs" mimeType="application/olescript" />
+      <mimeMap fileExtension=".bas" mimeType="text/plain" />
+      <mimeMap fileExtension=".bcpio" mimeType="application/x-bcpio" />
+      <mimeMap fileExtension=".bin" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".bmp" mimeType="image/bmp" />
+      <mimeMap fileExtension=".c" mimeType="text/plain" />
+      <mimeMap fileExtension=".cab" mimeType="application/vnd.ms-cab-compressed" />
+      <mimeMap fileExtension=".calx" mimeType="application/vnd.ms-office.calx" />
+      <mimeMap fileExtension=".cat" mimeType="application/vnd.ms-pki.seccat" />
+      <mimeMap fileExtension=".cdf" mimeType="application/x-cdf" />
+      <mimeMap fileExtension=".chm" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".class" mimeType="application/x-java-applet" />
+      <mimeMap fileExtension=".clp" mimeType="application/x-msclip" />
+      <mimeMap fileExtension=".cmx" mimeType="image/x-cmx" />
+      <mimeMap fileExtension=".cnf" mimeType="text/plain" />
+      <mimeMap fileExtension=".cod" mimeType="image/cis-cod" />
+      <mimeMap fileExtension=".cpio" mimeType="application/x-cpio" />
+      <mimeMap fileExtension=".cpp" mimeType="text/plain" />
+      <mimeMap fileExtension=".crd" mimeType="application/x-mscardfile" />
+      <mimeMap fileExtension=".crl" mimeType="application/pkix-crl" />
+      <mimeMap fileExtension=".crt" mimeType="application/x-x509-ca-cert" />
+      <mimeMap fileExtension=".csh" mimeType="application/x-csh" />
+      <mimeMap fileExtension=".css" mimeType="text/css" />
+      <mimeMap fileExtension=".csv" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".cur" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".dcr" mimeType="application/x-director" />
+      <mimeMap fileExtension=".deploy" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".der" mimeType="application/x-x509-ca-cert" />
+      <mimeMap fileExtension=".dib" mimeType="image/bmp" />
+      <mimeMap fileExtension=".dir" mimeType="application/x-director" />
+      <mimeMap fileExtension=".disco" mimeType="text/xml" />
+      <mimeMap fileExtension=".dll" mimeType="application/x-msdownload" />
+      <mimeMap fileExtension=".dll.config" mimeType="text/xml" />
+      <mimeMap fileExtension=".dlm" mimeType="text/dlm" />
+      <mimeMap fileExtension=".doc" mimeType="application/msword" />
+      <mimeMap fileExtension=".docm" mimeType="application/vnd.ms-word.document.macroEnabled.12" />
+      <mimeMap fileExtension=".docx" mimeType="application/vnd.openxmlformats-officedocument.wordprocessingml.document" />
+      <mimeMap fileExtension=".dot" mimeType="application/msword" />
+      <mimeMap fileExtension=".dotm" mimeType="application/vnd.ms-word.template.macroEnabled.12" />
+      <mimeMap fileExtension=".dotx" mimeType="application/vnd.openxmlformats-officedocument.wordprocessingml.template" />
+      <mimeMap fileExtension=".dsp" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".dtd" mimeType="text/xml" />
+      <mimeMap fileExtension=".dvi" mimeType="application/x-dvi" />
+      <mimeMap fileExtension=".dvr-ms" mimeType="video/x-ms-dvr" />
+      <mimeMap fileExtension=".dwf" mimeType="drawing/x-dwf" />
+      <mimeMap fileExtension=".dwp" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".dxr" mimeType="application/x-director" />
+      <mimeMap fileExtension=".eml" mimeType="message/rfc822" />
+      <mimeMap fileExtension=".emz" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".eot" mimeType="application/vnd.ms-fontobject" />
+      <mimeMap fileExtension=".eps" mimeType="application/postscript" />
+      <mimeMap fileExtension=".etx" mimeType="text/x-setext" />
+      <mimeMap fileExtension=".evy" mimeType="application/envoy" />
+      <mimeMap fileExtension=".exe" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".exe.config" mimeType="text/xml" />
+      <mimeMap fileExtension=".fdf" mimeType="application/vnd.fdf" />
+      <mimeMap fileExtension=".fif" mimeType="application/fractals" />
+      <mimeMap fileExtension=".fla" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".flr" mimeType="x-world/x-vrml" />
+      <mimeMap fileExtension=".flv" mimeType="video/x-flv" />
+      <mimeMap fileExtension=".gif" mimeType="image/gif" />
+      <mimeMap fileExtension=".gtar" mimeType="application/x-gtar" />
+      <mimeMap fileExtension=".gz" mimeType="application/x-gzip" />
+      <mimeMap fileExtension=".h" mimeType="text/plain" />
+      <mimeMap fileExtension=".hdf" mimeType="application/x-hdf" />
+      <mimeMap fileExtension=".hdml" mimeType="text/x-hdml" />
+      <mimeMap fileExtension=".hhc" mimeType="application/x-oleobject" />
+      <mimeMap fileExtension=".hhk" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".hhp" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".hlp" mimeType="application/winhlp" />
+      <mimeMap fileExtension=".hqx" mimeType="application/mac-binhex40" />
+      <mimeMap fileExtension=".hta" mimeType="application/hta" />
+      <mimeMap fileExtension=".htc" mimeType="text/x-component" />
+      <mimeMap fileExtension=".htm" mimeType="text/html" />
+      <mimeMap fileExtension=".html" mimeType="text/html" />
+      <mimeMap fileExtension=".htt" mimeType="text/webviewhtml" />
+      <mimeMap fileExtension=".hxt" mimeType="text/html" />
+      <mimeMap fileExtension=".ical" mimeType="text/calendar" />
+      <mimeMap fileExtension=".icalendar" mimeType="text/calendar" />
+      <mimeMap fileExtension=".ico" mimeType="image/x-icon" />
+      <mimeMap fileExtension=".ics" mimeType="text/calendar" />
+      <mimeMap fileExtension=".ief" mimeType="image/ief" />
+      <mimeMap fileExtension=".ifb" mimeType="text/calendar" />
+      <mimeMap fileExtension=".iii" mimeType="application/x-iphone" />
+      <mimeMap fileExtension=".inf" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".ins" mimeType="application/x-internet-signup" />
+      <mimeMap fileExtension=".isp" mimeType="application/x-internet-signup" />
+      <mimeMap fileExtension=".IVF" mimeType="video/x-ivf" />
+      <mimeMap fileExtension=".jar" mimeType="application/java-archive" />
+      <mimeMap fileExtension=".java" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".jck" mimeType="application/liquidmotion" />
+      <mimeMap fileExtension=".jcz" mimeType="application/liquidmotion" />
+      <mimeMap fileExtension=".jfif" mimeType="image/pjpeg" />
+      <mimeMap fileExtension=".jpb" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".jpe" mimeType="image/jpeg" />
+      <mimeMap fileExtension=".jpeg" mimeType="image/jpeg" />
+      <mimeMap fileExtension=".jpg" mimeType="image/jpeg" />
+      <mimeMap fileExtension=".js" mimeType="application/javascript" />
+      <mimeMap fileExtension=".jsx" mimeType="text/jscript" />
+      <mimeMap fileExtension=".latex" mimeType="application/x-latex" />
+      <mimeMap fileExtension=".lit" mimeType="application/x-ms-reader" />
+      <mimeMap fileExtension=".lpk" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".lsf" mimeType="video/x-la-asf" />
+      <mimeMap fileExtension=".lsx" mimeType="video/x-la-asf" />
+      <mimeMap fileExtension=".lzh" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".m13" mimeType="application/x-msmediaview" />
+      <mimeMap fileExtension=".m14" mimeType="application/x-msmediaview" />
+      <mimeMap fileExtension=".m1v" mimeType="video/mpeg" />
+      <mimeMap fileExtension=".m2ts" mimeType="video/vnd.dlna.mpeg-tts" />
+      <mimeMap fileExtension=".m3u" mimeType="audio/x-mpegurl" />
+      <mimeMap fileExtension=".m4a" mimeType="audio/mp4" />
+      <mimeMap fileExtension=".m4v" mimeType="video/mp4" />
+      <mimeMap fileExtension=".man" mimeType="application/x-troff-man" />
+      <mimeMap fileExtension=".manifest" mimeType="application/x-ms-manifest" />
+      <mimeMap fileExtension=".map" mimeType="text/plain" />
+      <mimeMap fileExtension=".mdb" mimeType="application/x-msaccess" />
+      <mimeMap fileExtension=".mdp" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".me" mimeType="application/x-troff-me" />
+      <mimeMap fileExtension=".mht" mimeType="message/rfc822" />
+      <mimeMap fileExtension=".mhtml" mimeType="message/rfc822" />
+      <mimeMap fileExtension=".mid" mimeType="audio/mid" />
+      <mimeMap fileExtension=".midi" mimeType="audio/mid" />
+      <mimeMap fileExtension=".mix" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".mmf" mimeType="application/x-smaf" />
+      <mimeMap fileExtension=".mno" mimeType="text/xml" />
+      <mimeMap fileExtension=".mny" mimeType="application/x-msmoney" />
+      <mimeMap fileExtension=".mov" mimeType="video/quicktime" />
+      <mimeMap fileExtension=".movie" mimeType="video/x-sgi-movie" />
+      <mimeMap fileExtension=".mp2" mimeType="video/mpeg" />
+      <mimeMap fileExtension=".mp3" mimeType="audio/mpeg" />
+      <mimeMap fileExtension=".mp4" mimeType="video/mp4" />
+      <mimeMap fileExtension=".mp4v" mimeType="video/mp4" />
+      <mimeMap fileExtension=".mpa" mimeType="video/mpeg" />
+      <mimeMap fileExtension=".mpe" mimeType="video/mpeg" />
+      <mimeMap fileExtension=".mpeg" mimeType="video/mpeg" />
+      <mimeMap fileExtension=".mpg" mimeType="video/mpeg" />
+      <mimeMap fileExtension=".mpp" mimeType="application/vnd.ms-project" />
+      <mimeMap fileExtension=".mpv2" mimeType="video/mpeg" />
+      <mimeMap fileExtension=".ms" mimeType="application/x-troff-ms" />
+      <mimeMap fileExtension=".msi" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".mso" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".mvb" mimeType="application/x-msmediaview" />
+      <mimeMap fileExtension=".mvc" mimeType="application/x-miva-compiled" />
+      <mimeMap fileExtension=".nc" mimeType="application/x-netcdf" />
+      <mimeMap fileExtension=".nsc" mimeType="video/x-ms-asf" />
+      <mimeMap fileExtension=".nws" mimeType="message/rfc822" />
+      <mimeMap fileExtension=".ocx" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".oda" mimeType="application/oda" />
+      <mimeMap fileExtension=".odc" mimeType="text/x-ms-odc" />
+      <mimeMap fileExtension=".ods" mimeType="application/oleobject" />
+      <mimeMap fileExtension=".oga" mimeType="audio/ogg" />
+      <mimeMap fileExtension=".ogg" mimeType="video/ogg" />
+      <mimeMap fileExtension=".ogv" mimeType="video/ogg" />
+      <mimeMap fileExtension=".ogx" mimeType="application/ogg" />
+      <mimeMap fileExtension=".one" mimeType="application/onenote" />
+      <mimeMap fileExtension=".onea" mimeType="application/onenote" />
+      <mimeMap fileExtension=".onetoc" mimeType="application/onenote" />
+      <mimeMap fileExtension=".onetoc2" mimeType="application/onenote" />
+      <mimeMap fileExtension=".onetmp" mimeType="application/onenote" />
+      <mimeMap fileExtension=".onepkg" mimeType="application/onenote" />
+      <mimeMap fileExtension=".osdx" mimeType="application/opensearchdescription+xml" />
+      <mimeMap fileExtension=".otf" mimeType="font/otf" />
+      <mimeMap fileExtension=".p10" mimeType="application/pkcs10" />
+      <mimeMap fileExtension=".p12" mimeType="application/x-pkcs12" />
+      <mimeMap fileExtension=".p7b" mimeType="application/x-pkcs7-certificates" />
+      <mimeMap fileExtension=".p7c" mimeType="application/pkcs7-mime" />
+      <mimeMap fileExtension=".p7m" mimeType="application/pkcs7-mime" />
+      <mimeMap fileExtension=".p7r" mimeType="application/x-pkcs7-certreqresp" />
+      <mimeMap fileExtension=".p7s" mimeType="application/pkcs7-signature" />
+      <mimeMap fileExtension=".pbm" mimeType="image/x-portable-bitmap" />
+      <mimeMap fileExtension=".pcx" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".pcz" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".pdf" mimeType="application/pdf" />
+      <mimeMap fileExtension=".pfb" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".pfm" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".pfx" mimeType="application/x-pkcs12" />
+      <mimeMap fileExtension=".pgm" mimeType="image/x-portable-graymap" />
+      <mimeMap fileExtension=".pko" mimeType="application/vnd.ms-pki.pko" />
+      <mimeMap fileExtension=".pma" mimeType="application/x-perfmon" />
+      <mimeMap fileExtension=".pmc" mimeType="application/x-perfmon" />
+      <mimeMap fileExtension=".pml" mimeType="application/x-perfmon" />
+      <mimeMap fileExtension=".pmr" mimeType="application/x-perfmon" />
+      <mimeMap fileExtension=".pmw" mimeType="application/x-perfmon" />
+      <mimeMap fileExtension=".png" mimeType="image/png" />
+      <mimeMap fileExtension=".pnm" mimeType="image/x-portable-anymap" />
+      <mimeMap fileExtension=".pnz" mimeType="image/png" />
+      <mimeMap fileExtension=".pot" mimeType="application/vnd.ms-powerpoint" />
+      <mimeMap fileExtension=".potm" mimeType="application/vnd.ms-powerpoint.template.macroEnabled.12" />
+      <mimeMap fileExtension=".potx" mimeType="application/vnd.openxmlformats-officedocument.presentationml.template" />
+      <mimeMap fileExtension=".ppam" mimeType="application/vnd.ms-powerpoint.addin.macroEnabled.12" />
+      <mimeMap fileExtension=".ppm" mimeType="image/x-portable-pixmap" />
+      <mimeMap fileExtension=".pps" mimeType="application/vnd.ms-powerpoint" />
+      <mimeMap fileExtension=".ppsm" mimeType="application/vnd.ms-powerpoint.slideshow.macroEnabled.12" />
+      <mimeMap fileExtension=".ppsx" mimeType="application/vnd.openxmlformats-officedocument.presentationml.slideshow" />
+      <mimeMap fileExtension=".ppt" mimeType="application/vnd.ms-powerpoint" />
+      <mimeMap fileExtension=".pptm" mimeType="application/vnd.ms-powerpoint.presentation.macroEnabled.12" />
+      <mimeMap fileExtension=".pptx" mimeType="application/vnd.openxmlformats-officedocument.presentationml.presentation" />
+      <mimeMap fileExtension=".prf" mimeType="application/pics-rules" />
+      <mimeMap fileExtension=".prm" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".prx" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".ps" mimeType="application/postscript" />
+      <mimeMap fileExtension=".psd" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".psm" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".psp" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".pub" mimeType="application/x-mspublisher" />
+      <mimeMap fileExtension=".qt" mimeType="video/quicktime" />
+      <mimeMap fileExtension=".qtl" mimeType="application/x-quicktimeplayer" />
+      <mimeMap fileExtension=".qxd" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".ra" mimeType="audio/x-pn-realaudio" />
+      <mimeMap fileExtension=".ram" mimeType="audio/x-pn-realaudio" />
+      <mimeMap fileExtension=".rar" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".ras" mimeType="image/x-cmu-raster" />
+      <mimeMap fileExtension=".rf" mimeType="image/vnd.rn-realflash" />
+      <mimeMap fileExtension=".rgb" mimeType="image/x-rgb" />
+      <mimeMap fileExtension=".rm" mimeType="application/vnd.rn-realmedia" />
+      <mimeMap fileExtension=".rmi" mimeType="audio/mid" />
+      <mimeMap fileExtension=".roff" mimeType="application/x-troff" />
+      <mimeMap fileExtension=".rpm" mimeType="audio/x-pn-realaudio-plugin" />
+      <mimeMap fileExtension=".rtf" mimeType="application/rtf" />
+      <mimeMap fileExtension=".rtx" mimeType="text/richtext" />
+      <mimeMap fileExtension=".scd" mimeType="application/x-msschedule" />
+      <mimeMap fileExtension=".sct" mimeType="text/scriptlet" />
+      <mimeMap fileExtension=".sea" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".setpay" mimeType="application/set-payment-initiation" />
+      <mimeMap fileExtension=".setreg" mimeType="application/set-registration-initiation" />
+      <mimeMap fileExtension=".sgml" mimeType="text/sgml" />
+      <mimeMap fileExtension=".sh" mimeType="application/x-sh" />
+      <mimeMap fileExtension=".shar" mimeType="application/x-shar" />
+      <mimeMap fileExtension=".sit" mimeType="application/x-stuffit" />
+      <mimeMap fileExtension=".sldm" mimeType="application/vnd.ms-powerpoint.slide.macroEnabled.12" />
+      <mimeMap fileExtension=".sldx" mimeType="application/vnd.openxmlformats-officedocument.presentationml.slide" />
+      <mimeMap fileExtension=".smd" mimeType="audio/x-smd" />
+      <mimeMap fileExtension=".smi" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".smx" mimeType="audio/x-smd" />
+      <mimeMap fileExtension=".smz" mimeType="audio/x-smd" />
+      <mimeMap fileExtension=".snd" mimeType="audio/basic" />
+      <mimeMap fileExtension=".snp" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".spc" mimeType="application/x-pkcs7-certificates" />
+      <mimeMap fileExtension=".spl" mimeType="application/futuresplash" />
+      <mimeMap fileExtension=".spx" mimeType="audio/ogg" />
+      <mimeMap fileExtension=".src" mimeType="application/x-wais-source" />
+      <mimeMap fileExtension=".ssm" mimeType="application/streamingmedia" />
+      <mimeMap fileExtension=".sst" mimeType="application/vnd.ms-pki.certstore" />
+      <mimeMap fileExtension=".stl" mimeType="application/vnd.ms-pki.stl" />
+      <mimeMap fileExtension=".sv4cpio" mimeType="application/x-sv4cpio" />
+      <mimeMap fileExtension=".sv4crc" mimeType="application/x-sv4crc" />
+      <mimeMap fileExtension=".svg" mimeType="image/svg+xml" />
+      <mimeMap fileExtension=".svgz" mimeType="image/svg+xml" />
+      <mimeMap fileExtension=".swf" mimeType="application/x-shockwave-flash" />
+      <mimeMap fileExtension=".t" mimeType="application/x-troff" />
+      <mimeMap fileExtension=".tar" mimeType="application/x-tar" />
+      <mimeMap fileExtension=".tcl" mimeType="application/x-tcl" />
+      <mimeMap fileExtension=".tex" mimeType="application/x-tex" />
+      <mimeMap fileExtension=".texi" mimeType="application/x-texinfo" />
+      <mimeMap fileExtension=".texinfo" mimeType="application/x-texinfo" />
+      <mimeMap fileExtension=".tgz" mimeType="application/x-compressed" />
+      <mimeMap fileExtension=".thmx" mimeType="application/vnd.ms-officetheme" />
+      <mimeMap fileExtension=".thn" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".tif" mimeType="image/tiff" />
+      <mimeMap fileExtension=".tiff" mimeType="image/tiff" />
+      <mimeMap fileExtension=".toc" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".tr" mimeType="application/x-troff" />
+      <mimeMap fileExtension=".trm" mimeType="application/x-msterminal" />
+      <mimeMap fileExtension=".ts" mimeType="video/vnd.dlna.mpeg-tts" />
+      <mimeMap fileExtension=".tsv" mimeType="text/tab-separated-values" />
+      <mimeMap fileExtension=".ttf" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".tts" mimeType="video/vnd.dlna.mpeg-tts" />
+      <mimeMap fileExtension=".txt" mimeType="text/plain" />
+      <mimeMap fileExtension=".u32" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".uls" mimeType="text/iuls" />
+      <mimeMap fileExtension=".ustar" mimeType="application/x-ustar" />
+      <mimeMap fileExtension=".vbs" mimeType="text/vbscript" />
+      <mimeMap fileExtension=".vcf" mimeType="text/x-vcard" />
+      <mimeMap fileExtension=".vcs" mimeType="text/plain" />
+      <mimeMap fileExtension=".vdx" mimeType="application/vnd.ms-visio.viewer" />
+      <mimeMap fileExtension=".vml" mimeType="text/xml" />
+      <mimeMap fileExtension=".vsd" mimeType="application/vnd.visio" />
+      <mimeMap fileExtension=".vss" mimeType="application/vnd.visio" />
+      <mimeMap fileExtension=".vst" mimeType="application/vnd.visio" />
+      <mimeMap fileExtension=".vsto" mimeType="application/x-ms-vsto" />
+      <mimeMap fileExtension=".vsw" mimeType="application/vnd.visio" />
+      <mimeMap fileExtension=".vsx" mimeType="application/vnd.visio" />
+      <mimeMap fileExtension=".vtx" mimeType="application/vnd.visio" />
+      <mimeMap fileExtension=".wav" mimeType="audio/wav" />
+      <mimeMap fileExtension=".wax" mimeType="audio/x-ms-wax" />
+      <mimeMap fileExtension=".wbmp" mimeType="image/vnd.wap.wbmp" />
+      <mimeMap fileExtension=".wcm" mimeType="application/vnd.ms-works" />
+      <mimeMap fileExtension=".wdb" mimeType="application/vnd.ms-works" />
+      <mimeMap fileExtension=".webm" mimeType="video/webm" />
+      <mimeMap fileExtension=".wks" mimeType="application/vnd.ms-works" />
+      <mimeMap fileExtension=".wm" mimeType="video/x-ms-wm" />
+      <mimeMap fileExtension=".wma" mimeType="audio/x-ms-wma" />
+      <mimeMap fileExtension=".wmd" mimeType="application/x-ms-wmd" />
+      <mimeMap fileExtension=".wmf" mimeType="application/x-msmetafile" />
+      <mimeMap fileExtension=".wml" mimeType="text/vnd.wap.wml" />
+      <mimeMap fileExtension=".wmlc" mimeType="application/vnd.wap.wmlc" />
+      <mimeMap fileExtension=".wmls" mimeType="text/vnd.wap.wmlscript" />
+      <mimeMap fileExtension=".wmlsc" mimeType="application/vnd.wap.wmlscriptc" />
+      <mimeMap fileExtension=".wmp" mimeType="video/x-ms-wmp" />
+      <mimeMap fileExtension=".wmv" mimeType="video/x-ms-wmv" />
+      <mimeMap fileExtension=".wmx" mimeType="video/x-ms-wmx" />
+      <mimeMap fileExtension=".wmz" mimeType="application/x-ms-wmz" />
+      <mimeMap fileExtension=".woff" mimeType="font/x-woff" />
+      <mimeMap fileExtension=".wps" mimeType="application/vnd.ms-works" />
+      <mimeMap fileExtension=".wri" mimeType="application/x-mswrite" />
+      <mimeMap fileExtension=".wrl" mimeType="x-world/x-vrml" />
+      <mimeMap fileExtension=".wrz" mimeType="x-world/x-vrml" />
+      <mimeMap fileExtension=".wsdl" mimeType="text/xml" />
+      <mimeMap fileExtension=".wtv" mimeType="video/x-ms-wtv" />
+      <mimeMap fileExtension=".wvx" mimeType="video/x-ms-wvx" />
+      <mimeMap fileExtension=".x" mimeType="application/directx" />
+      <mimeMap fileExtension=".xaf" mimeType="x-world/x-vrml" />
+      <mimeMap fileExtension=".xaml" mimeType="application/xaml+xml" />
+      <mimeMap fileExtension=".xap" mimeType="application/x-silverlight-app" />
+      <mimeMap fileExtension=".xbap" mimeType="application/x-ms-xbap" />
+      <mimeMap fileExtension=".xbm" mimeType="image/x-xbitmap" />
+      <mimeMap fileExtension=".xdr" mimeType="text/plain" />
+      <mimeMap fileExtension=".xht" mimeType="application/xhtml+xml" />
+      <mimeMap fileExtension=".xhtml" mimeType="application/xhtml+xml" />
+      <mimeMap fileExtension=".xla" mimeType="application/vnd.ms-excel" />
+      <mimeMap fileExtension=".xlam" mimeType="application/vnd.ms-excel.addin.macroEnabled.12" />
+      <mimeMap fileExtension=".xlc" mimeType="application/vnd.ms-excel" />
+      <mimeMap fileExtension=".xlm" mimeType="application/vnd.ms-excel" />
+      <mimeMap fileExtension=".xls" mimeType="application/vnd.ms-excel" />
+      <mimeMap fileExtension=".xlsb" mimeType="application/vnd.ms-excel.sheet.binary.macroEnabled.12" />
+      <mimeMap fileExtension=".xlsm" mimeType="application/vnd.ms-excel.sheet.macroEnabled.12" />
+      <mimeMap fileExtension=".xlsx" mimeType="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" />
+      <mimeMap fileExtension=".xlt" mimeType="application/vnd.ms-excel" />
+      <mimeMap fileExtension=".xltm" mimeType="application/vnd.ms-excel.template.macroEnabled.12" />
+      <mimeMap fileExtension=".xltx" mimeType="application/vnd.openxmlformats-officedocument.spreadsheetml.template" />
+      <mimeMap fileExtension=".xlw" mimeType="application/vnd.ms-excel" />
+      <mimeMap fileExtension=".xml" mimeType="text/xml" />
+      <mimeMap fileExtension=".xof" mimeType="x-world/x-vrml" />
+      <mimeMap fileExtension=".xpm" mimeType="image/x-xpixmap" />
+      <mimeMap fileExtension=".xps" mimeType="application/vnd.ms-xpsdocument" />
+      <mimeMap fileExtension=".xsd" mimeType="text/xml" />
+      <mimeMap fileExtension=".xsf" mimeType="text/xml" />
+      <mimeMap fileExtension=".xsl" mimeType="text/xml" />
+      <mimeMap fileExtension=".xslt" mimeType="text/xml" />
+      <mimeMap fileExtension=".xsn" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".xtp" mimeType="application/octet-stream" />
+      <mimeMap fileExtension=".xwd" mimeType="image/x-xwindowdump" />
+      <mimeMap fileExtension=".z" mimeType="application/x-compress" />
+      <mimeMap fileExtension=".zip" mimeType="application/x-zip-compressed" />
+    </staticContent>
+
+    <tracing>
+
+      <traceProviderDefinitions>
+        <add name="WWW Server" guid="{3a2a4e84-4c21-4981-ae10-3fda0d9b0f83}">
+          <areas>
+            <clear />
+            <add name="Authentication" value="2" />
+            <add name="Security" value="4" />
+            <add name="Filter" value="8" />
+            <add name="StaticFile" value="16" />
+            <add name="CGI" value="32" />
+            <add name="Compression" value="64" />
+            <add name="Cache" value="128" />
+            <add name="RequestNotifications" value="256" />
+            <add name="Module" value="512" />
+            <add name="Rewrite" value="1024" />
+            <add name="FastCGI" value="4096" />
+            <add name="WebSocket" value="16384" />
+          </areas>
+        </add>
+        <add name="ASP" guid="{06b94d9a-b15e-456e-a4ef-37c984a2cb4b}">
+          <areas>
+            <clear />
+          </areas>
+        </add>
+        <add name="ISAPI Extension" guid="{a1c2040e-8840-4c31-ba11-9871031a19ea}">
+          <areas>
+            <clear />
+          </areas>
+        </add>
+        <add name="ASPNET" guid="{AFF081FE-0247-4275-9C4E-021F3DC1DA35}">
+          <areas>
+            <add name="Infrastructure" value="1" />
+            <add name="Module" value="2" />
+            <add name="Page" value="4" />
+            <add name="AppServices" value="8" />
+          </areas>
+        </add>
+      </traceProviderDefinitions>
+
+      <traceFailedRequests>
+        <add path="*">
+          <traceAreas>
+            <add provider="ASP" verbosity="Verbose" />
+            <add provider="ASPNET" areas="Infrastructure,Module,Page,AppServices" verbosity="Verbose" />
+            <add provider="ISAPI Extension" verbosity="Verbose" />
+            <add provider="WWW Server" areas="Authentication,Security,Filter,StaticFile,CGI,Compression,Cache,RequestNotifications,Module,Rewrite,WebSocket" verbosity="Verbose" />
+          </traceAreas>
+          <failureDefinitions statusCodes="200-999" />
+        </add>
+      </traceFailedRequests>
+
+    </tracing>
+
+    <urlCompression />
+
+    <validation />
+    <webdav>
+      <globalSettings>
+        <propertyStores>
+          <add name="webdav_simple_prop" image="%IIS_BIN%\webdav_simple_prop.dll" image32="%IIS_BIN%\webdav_simple_prop.dll" />
+        </propertyStores>
+        <lockStores>
+          <add name="webdav_simple_lock" image="%IIS_BIN%\webdav_simple_lock.dll" image32="%IIS_BIN%\webdav_simple_lock.dll" />
+        </lockStores>
+
+      </globalSettings>
+      <authoring>
+        <locks enabled="true" lockStore="webdav_simple_lock" />
+      </authoring>
+      <authoringRules />
+    </webdav>
+    <applicationInitialization />
+    <webSocket />
+
+  </system.webServer>
+  <location path="" overrideMode="Allow">
+    <system.webServer>
+      <modules>
+
+        <add name="IsapiFilterModule" lockItem="true" />
+        <add name="BasicAuthenticationModule" lockItem="true" />
+        <add name="IsapiModule" lockItem="true" />
+        <add name="HttpLoggingModule" lockItem="true" />
+        <!--
+                <add name="HttpCacheModule" lockItem="true" />
+-->
+        <add name="DynamicCompressionModule" lockItem="true" />
+        <add name="StaticCompressionModule" lockItem="true" />
+        <add name="DefaultDocumentModule" lockItem="true" />
+        <add name="DirectoryListingModule" lockItem="true" />
+        <add name="ProtocolSupportModule" lockItem="true" />
+        <add name="HttpRedirectionModule" lockItem="true" />
+        <add name="ServerSideIncludeModule" lockItem="true" />
+        <add name="StaticFileModule" lockItem="true" />
+        <add name="AnonymousAuthenticationModule" lockItem="true" />
+        <add name="CertificateMappingAuthenticationModule" lockItem="true" />
+        <add name="UrlAuthorizationModule" lockItem="true" />
+        <add name="WindowsAuthenticationModule" lockItem="true" />
+        <!--
+                <add name="DigestAuthenticationModule" lockItem="true" />
+-->
+        <add name="IISCertificateMappingAuthenticationModule" lockItem="true" />
+        <add name="WebMatrixSupportModule" lockItem="true" />
+        <add name="IpRestrictionModule" lockItem="true" />
+        <add name="DynamicIpRestrictionModule" lockItem="true" />
+        <add name="RequestFilteringModule" lockItem="true" />
+        <add name="CustomLoggingModule" lockItem="true" />
+        <add name="CustomErrorModule" lockItem="true" />
+        <add name="FailedRequestsTracingModule" lockItem="true" />
+        <add name="CgiModule" lockItem="true" />
+        <add name="FastCgiModule" lockItem="true" />
+        <!--                <add name="WebDAVModule" /> -->
+        <add name="RewriteModule" />
+        <add name="OutputCache" type="System.Web.Caching.OutputCacheModule" preCondition="managedHandler" />
+        <add name="Session" type="System.Web.SessionState.SessionStateModule" preCondition="managedHandler" />
+        <add name="WindowsAuthentication" type="System.Web.Security.WindowsAuthenticationModule" preCondition="managedHandler" />
+        <add name="FormsAuthentication" type="System.Web.Security.FormsAuthenticationModule" preCondition="managedHandler" />
+        <add name="DefaultAuthentication" type="System.Web.Security.DefaultAuthenticationModule" preCondition="managedHandler" />
+        <add name="RoleManager" type="System.Web.Security.RoleManagerModule" preCondition="managedHandler" />
+        <add name="UrlAuthorization" type="System.Web.Security.UrlAuthorizationModule" preCondition="managedHandler" />
+        <add name="FileAuthorization" type="System.Web.Security.FileAuthorizationModule" preCondition="managedHandler" />
+        <add name="AnonymousIdentification" type="System.Web.Security.AnonymousIdentificationModule" preCondition="managedHandler" />
+        <add name="Profile" type="System.Web.Profile.ProfileModule" preCondition="managedHandler" />
+        <add name="UrlMappingsModule" type="System.Web.UrlMappingsModule" preCondition="managedHandler" />
+        <add name="ApplicationInitializationModule" lockItem="true" />
+        <add name="WebSocketModule" lockItem="true" />
+        <add name="ServiceModel-4.0" type="System.ServiceModel.Activation.ServiceHttpModule,System.ServiceModel.Activation,Version=4.0.0.0,Culture=neutral,PublicKeyToken=31bf3856ad364e35" preCondition="managedHandler,runtimeVersionv4.0" />
+        <add name="ConfigurationValidationModule" lockItem="true" />
+        <add name="UrlRoutingModule-4.0" type="System.Web.Routing.UrlRoutingModule" preCondition="managedHandler,runtimeVersionv4.0" />
+        <add name="ScriptModule-4.0" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" preCondition="managedHandler,runtimeVersionv4.0" />
+        <add name="ServiceModel" type="System.ServiceModel.Activation.HttpModule, System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" preCondition="managedHandler,runtimeVersionv2.0" />
+        <add name="AspNetCoreModule" />
+      </modules>
+      <handlers accessPolicy="Read, Script">
+        <!--                <add name="WebDAV" path="*" verb="PROPFIND,PROPPATCH,MKCOL,PUT,COPY,DELETE,MOVE,LOCK,UNLOCK" modules="WebDAVModule" resourceType="Unspecified" requireAccess="None" /> -->
+        <add name="AXD-ISAPI-4.0_64bit" path="*.axd" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
+        <add name="PageHandlerFactory-ISAPI-4.0_64bit" path="*.aspx" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
+        <add name="SimpleHandlerFactory-ISAPI-4.0_64bit" path="*.ashx" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
+        <add name="WebServiceHandlerFactory-ISAPI-4.0_64bit" path="*.asmx" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
+        <add name="HttpRemotingHandlerFactory-rem-ISAPI-4.0_64bit" path="*.rem" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
+        <add name="HttpRemotingHandlerFactory-soap-ISAPI-4.0_64bit" path="*.soap" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
+        <add name="svc-ISAPI-4.0_64bit" path="*.svc" verb="*" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" />
+        <add name="rules-ISAPI-4.0_64bit" path="*.rules" verb="*" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" />
+        <add name="xoml-ISAPI-4.0_64bit" path="*.xoml" verb="*" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" />
+        <add name="xamlx-ISAPI-4.0_64bit" path="*.xamlx" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" />
+        <add name="aspq-ISAPI-4.0_64bit" path="*.aspq" verb="*" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
+        <add name="cshtm-ISAPI-4.0_64bit" path="*.cshtm" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
+        <add name="cshtml-ISAPI-4.0_64bit" path="*.cshtml" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
+        <add name="vbhtm-ISAPI-4.0_64bit" path="*.vbhtm" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
+        <add name="vbhtml-ISAPI-4.0_64bit" path="*.vbhtml" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
+        <add name="svc-Integrated" path="*.svc" verb="*" type="System.ServiceModel.Activation.HttpHandler, System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" preCondition="integratedMode,runtimeVersionv2.0" />
+        <add name="svc-ISAPI-2.0" path="*.svc" verb="*" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness32" />
+        <add name="xoml-Integrated" path="*.xoml" verb="*" type="System.ServiceModel.Activation.HttpHandler, System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" preCondition="integratedMode,runtimeVersionv2.0" />
+        <add name="xoml-ISAPI-2.0" path="*.xoml" verb="*" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness32" />
+        <add name="rules-Integrated" path="*.rules" verb="*" type="System.ServiceModel.Activation.HttpHandler, System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" preCondition="integratedMode,runtimeVersionv2.0" />
+        <add name="rules-ISAPI-2.0" path="*.rules" verb="*" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness32" />
+        <add name="AXD-ISAPI-4.0_32bit" path="*.axd" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
+        <add name="PageHandlerFactory-ISAPI-4.0_32bit" path="*.aspx" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
+        <add name="SimpleHandlerFactory-ISAPI-4.0_32bit" path="*.ashx" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
+        <add name="WebServiceHandlerFactory-ISAPI-4.0_32bit" path="*.asmx" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
+        <add name="HttpRemotingHandlerFactory-rem-ISAPI-4.0_32bit" path="*.rem" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
+        <add name="HttpRemotingHandlerFactory-soap-ISAPI-4.0_32bit" path="*.soap" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
+        <add name="svc-ISAPI-4.0_32bit" path="*.svc" verb="*" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" />
+        <add name="rules-ISAPI-4.0_32bit" path="*.rules" verb="*" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" />
+        <add name="xoml-ISAPI-4.0_32bit" path="*.xoml" verb="*" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" />
+        <add name="xamlx-ISAPI-4.0_32bit" path="*.xamlx" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" />
+        <add name="aspq-ISAPI-4.0_32bit" path="*.aspq" verb="*" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
+        <add name="cshtm-ISAPI-4.0_32bit" path="*.cshtm" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
+        <add name="cshtml-ISAPI-4.0_32bit" path="*.cshtml" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
+        <add name="vbhtm-ISAPI-4.0_32bit" path="*.vbhtm" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
+        <add name="vbhtml-ISAPI-4.0_32bit" path="*.vbhtml" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
+        <add name="TraceHandler-Integrated-4.0" path="trace.axd" verb="GET,HEAD,POST,DEBUG" type="System.Web.Handlers.TraceHandler" preCondition="integratedMode,runtimeVersionv4.0" />
+        <add name="WebAdminHandler-Integrated-4.0" path="WebAdmin.axd" verb="GET,DEBUG" type="System.Web.Handlers.WebAdminHandler" preCondition="integratedMode,runtimeVersionv4.0" />
+        <add name="AssemblyResourceLoader-Integrated-4.0" path="WebResource.axd" verb="GET,DEBUG" type="System.Web.Handlers.AssemblyResourceLoader" preCondition="integratedMode,runtimeVersionv4.0" />
+        <add name="PageHandlerFactory-Integrated-4.0" path="*.aspx" verb="GET,HEAD,POST,DEBUG" type="System.Web.UI.PageHandlerFactory" preCondition="integratedMode,runtimeVersionv4.0" />
+        <add name="SimpleHandlerFactory-Integrated-4.0" path="*.ashx" verb="GET,HEAD,POST,DEBUG" type="System.Web.UI.SimpleHandlerFactory" preCondition="integratedMode,runtimeVersionv4.0" />
+        <add name="WebServiceHandlerFactory-Integrated-4.0" path="*.asmx" verb="GET,HEAD,POST,DEBUG" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" preCondition="integratedMode,runtimeVersionv4.0" />
+        <add name="HttpRemotingHandlerFactory-rem-Integrated-4.0" path="*.rem" verb="GET,HEAD,POST,DEBUG" type="System.Runtime.Remoting.Channels.Http.HttpRemotingHandlerFactory, System.Runtime.Remoting, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" preCondition="integratedMode,runtimeVersionv4.0" />
+        <add name="HttpRemotingHandlerFactory-soap-Integrated-4.0" path="*.soap" verb="GET,HEAD,POST,DEBUG" type="System.Runtime.Remoting.Channels.Http.HttpRemotingHandlerFactory, System.Runtime.Remoting, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" preCondition="integratedMode,runtimeVersionv4.0" />
+        <add name="svc-Integrated-4.0" path="*.svc" verb="*" type="System.ServiceModel.Activation.ServiceHttpHandlerFactory, System.ServiceModel.Activation, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" preCondition="integratedMode,runtimeVersionv4.0" />
+        <add name="rules-Integrated-4.0" path="*.rules" verb="*" type="System.ServiceModel.Activation.ServiceHttpHandlerFactory, System.ServiceModel.Activation, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" preCondition="integratedMode,runtimeVersionv4.0" />
+        <add name="xoml-Integrated-4.0" path="*.xoml" verb="*" type="System.ServiceModel.Activation.ServiceHttpHandlerFactory, System.ServiceModel.Activation, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" preCondition="integratedMode,runtimeVersionv4.0" />
+        <add name="xamlx-Integrated-4.0" path="*.xamlx" verb="GET,HEAD,POST,DEBUG" type="System.Xaml.Hosting.XamlHttpHandlerFactory, System.Xaml.Hosting, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" preCondition="integratedMode,runtimeVersionv4.0" />
+        <add name="aspq-Integrated-4.0" path="*.aspq" verb="GET,HEAD,POST,DEBUG" type="System.Web.HttpForbiddenHandler" preCondition="integratedMode,runtimeVersionv4.0" />
+        <add name="cshtm-Integrated-4.0" path="*.cshtm" verb="GET,HEAD,POST,DEBUG" type="System.Web.HttpForbiddenHandler" preCondition="integratedMode,runtimeVersionv4.0" />
+        <add name="cshtml-Integrated-4.0" path="*.cshtml" verb="GET,HEAD,POST,DEBUG" type="System.Web.HttpForbiddenHandler" preCondition="integratedMode,runtimeVersionv4.0" />
+        <add name="vbhtm-Integrated-4.0" path="*.vbhtm" verb="GET,HEAD,POST,DEBUG" type="System.Web.HttpForbiddenHandler" preCondition="integratedMode,runtimeVersionv4.0" />
+        <add name="vbhtml-Integrated-4.0" path="*.vbhtml" verb="GET,HEAD,POST,DEBUG" type="System.Web.HttpForbiddenHandler" preCondition="integratedMode,runtimeVersionv4.0" />
+        <add name="ScriptHandlerFactoryAppServices-Integrated-4.0" path="*_AppService.axd" verb="*" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" preCondition="integratedMode,runtimeVersionv4.0" />
+        <add name="ScriptResourceIntegrated-4.0" path="*ScriptResource.axd" verb="GET,HEAD" type="System.Web.Handlers.ScriptResourceHandler, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" preCondition="integratedMode,runtimeVersionv4.0" />
+        <add name="ASPClassic" path="*.asp" verb="GET,HEAD,POST" modules="IsapiModule" scriptProcessor="%IIS_BIN%\asp.dll" resourceType="File" />
+        <add name="SecurityCertificate" path="*.cer" verb="GET,HEAD,POST" modules="IsapiModule" scriptProcessor="%IIS_BIN%\asp.dll" resourceType="File" />
+        <add name="ISAPI-dll" path="*.dll" verb="*" modules="IsapiModule" resourceType="File" requireAccess="Execute" allowPathInfo="true" />
+        <add name="TraceHandler-Integrated" path="trace.axd" verb="GET,HEAD,POST,DEBUG" type="System.Web.Handlers.TraceHandler" preCondition="integratedMode,runtimeVersionv2.0" />
+        <add name="WebAdminHandler-Integrated" path="WebAdmin.axd" verb="GET,DEBUG" type="System.Web.Handlers.WebAdminHandler" preCondition="integratedMode,runtimeVersionv2.0" />
+        <add name="AssemblyResourceLoader-Integrated" path="WebResource.axd" verb="GET,DEBUG" type="System.Web.Handlers.AssemblyResourceLoader" preCondition="integratedMode,runtimeVersionv2.0" />
+        <add name="PageHandlerFactory-Integrated" path="*.aspx" verb="GET,HEAD,POST,DEBUG" type="System.Web.UI.PageHandlerFactory" preCondition="integratedMode,runtimeVersionv2.0" />
+        <add name="SimpleHandlerFactory-Integrated" path="*.ashx" verb="GET,HEAD,POST,DEBUG" type="System.Web.UI.SimpleHandlerFactory" preCondition="integratedMode,runtimeVersionv2.0" />
+        <add name="WebServiceHandlerFactory-Integrated" path="*.asmx" verb="GET,HEAD,POST,DEBUG" type="System.Web.Services.Protocols.WebServiceHandlerFactory,System.Web.Services,Version=2.0.0.0,Culture=neutral,PublicKeyToken=b03f5f7f11d50a3a" preCondition="integratedMode,runtimeVersionv2.0" />
+        <add name="HttpRemotingHandlerFactory-rem-Integrated" path="*.rem" verb="GET,HEAD,POST,DEBUG" type="System.Runtime.Remoting.Channels.Http.HttpRemotingHandlerFactory,System.Runtime.Remoting,Version=2.0.0.0,Culture=neutral,PublicKeyToken=b77a5c561934e089" preCondition="integratedMode,runtimeVersionv2.0" />
+        <add name="HttpRemotingHandlerFactory-soap-Integrated" path="*.soap" verb="GET,HEAD,POST,DEBUG" type="System.Runtime.Remoting.Channels.Http.HttpRemotingHandlerFactory,System.Runtime.Remoting,Version=2.0.0.0,Culture=neutral,PublicKeyToken=b77a5c561934e089" preCondition="integratedMode,runtimeVersionv2.0" />
+        <add name="AXD-ISAPI-2.0" path="*.axd" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness32" responseBufferLimit="0" />
+        <add name="PageHandlerFactory-ISAPI-2.0" path="*.aspx" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness32" responseBufferLimit="0" />
+        <add name="SimpleHandlerFactory-ISAPI-2.0" path="*.ashx" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness32" responseBufferLimit="0" />
+        <add name="WebServiceHandlerFactory-ISAPI-2.0" path="*.asmx" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness32" responseBufferLimit="0" />
+        <add name="HttpRemotingHandlerFactory-rem-ISAPI-2.0" path="*.rem" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness32" responseBufferLimit="0" />
+        <add name="HttpRemotingHandlerFactory-soap-ISAPI-2.0" path="*.soap" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness32" responseBufferLimit="0" />
+        <add name="svc-ISAPI-2.0-64" path="*.svc" verb="*" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness64" />
+        <add name="AXD-ISAPI-2.0-64" path="*.axd" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness64" responseBufferLimit="0" />
+        <add name="PageHandlerFactory-ISAPI-2.0-64" path="*.aspx" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness64" responseBufferLimit="0" />
+        <add name="SimpleHandlerFactory-ISAPI-2.0-64" path="*.ashx" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness64" responseBufferLimit="0" />
+        <add name="WebServiceHandlerFactory-ISAPI-2.0-64" path="*.asmx" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness64" responseBufferLimit="0" />
+        <add name="HttpRemotingHandlerFactory-rem-ISAPI-2.0-64" path="*.rem" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness64" responseBufferLimit="0" />
+        <add name="HttpRemotingHandlerFactory-soap-ISAPI-2.0-64" path="*.soap" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness64" responseBufferLimit="0" />
+        <add name="rules-64-ISAPI-2.0" path="*.rules" verb="*" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness64" />
+        <add name="xoml-64-ISAPI-2.0" path="*.xoml" verb="*" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness64" />
+        <add name="CGI-exe" path="*.exe" verb="*" modules="CgiModule" resourceType="File" requireAccess="Execute" allowPathInfo="true" />
+        <add name="SSINC-stm" path="*.stm" verb="GET,HEAD,POST" modules="ServerSideIncludeModule" resourceType="File" />
+        <add name="SSINC-shtm" path="*.shtm" verb="GET,HEAD,POST" modules="ServerSideIncludeModule" resourceType="File" />
+        <add name="SSINC-shtml" path="*.shtml" verb="GET,HEAD,POST" modules="ServerSideIncludeModule" resourceType="File" />
+        <add name="TRACEVerbHandler" path="*" verb="TRACE" modules="ProtocolSupportModule" requireAccess="None" />
+        <add name="OPTIONSVerbHandler" path="*" verb="OPTIONS" modules="ProtocolSupportModule" requireAccess="None" />
+        <add name="ExtensionlessUrl-ISAPI-4.0_32bit" path="*." verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
+        <add name="ExtensionlessUrlHandler-ISAPI-4.0_64bit" path="*." verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
+        <add name="ExtensionlessUrl-Integrated-4.0" path="*." verb="GET,HEAD,POST,DEBUG" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" responseBufferLimit="0" />
+        <add name="StaticFile" path="*" verb="*" modules="StaticFileModule,DefaultDocumentModule,DirectoryListingModule" resourceType="Either" requireAccess="Read" />
+      </handlers>
+    </system.webServer>
+  </location>
+  <location path="HttpTestSite">
+    <system.webServer>
+      <security>
+        <authentication>
+          <anonymousAuthentication enabled="true" />
+          <windowsAuthentication enabled="true" />
+        </authentication>
+      </security>
+    </system.webServer>
+  </location>
+</configuration>
diff --git a/src/IISIntegration/test/IISIntegration.FunctionalTests/AppHostConfig/Https.config b/src/IISIntegration/test/IISIntegration.FunctionalTests/AppHostConfig/Https.config
new file mode 100644
index 0000000000000000000000000000000000000000..e16fd734b76f1974b42188990fb2c05e864dd9c5
--- /dev/null
+++ b/src/IISIntegration/test/IISIntegration.FunctionalTests/AppHostConfig/Https.config
@@ -0,0 +1,1029 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    IIS configuration sections.
+
+    For schema documentation, see
+    %IIS_BIN%\config\schema\IIS_schema.xml.
+    
+    Please make a backup of this file before making any changes to it.
+
+    NOTE: The following environment variables are available to be used
+          within this file and are understood by the IIS Express.
+
+          %IIS_USER_HOME% - The IIS Express home directory for the user
+          %IIS_SITES_HOME% - The default home directory for sites
+          %IIS_BIN% - The location of the IIS Express binaries
+          %SYSTEMDRIVE% - The drive letter of %IIS_BIN%
+
+-->
+
+<configuration>
+
+    <!--
+
+        The <configSections> section controls the registration of sections.
+        Section is the basic unit of deployment, locking, searching and
+        containment for configuration settings.
+        
+        Every section belongs to one section group.
+        A section group is a container of logically-related sections.
+        
+        Sections cannot be nested.
+        Section groups may be nested.
+        
+        <section
+            name=""  [Required, Collection Key] [XML name of the section]
+            allowDefinition="Everywhere" [MachineOnly|MachineToApplication|AppHostOnly|Everywhere] [Level where it can be set]
+            overrideModeDefault="Allow"  [Allow|Deny] [Default delegation mode]
+            allowLocation="true"  [true|false] [Allowed in location tags]
+        />
+        
+        The recommended way to unlock sections is by using a location tag:
+        <location path="Default Web Site" overrideMode="Allow">
+            <system.webServer>
+                <asp />
+            </system.webServer>
+        </location>
+
+    -->
+    <configSections>
+        <sectionGroup name="system.applicationHost">
+            <section name="applicationPools" allowDefinition="AppHostOnly" overrideModeDefault="Deny" />
+            <section name="configHistory" allowDefinition="AppHostOnly" overrideModeDefault="Deny" />
+            <section name="customMetadata" allowDefinition="AppHostOnly" overrideModeDefault="Deny" />
+            <section name="listenerAdapters" allowDefinition="AppHostOnly" overrideModeDefault="Deny" />
+            <section name="log" allowDefinition="AppHostOnly" overrideModeDefault="Deny" />
+            <section name="preloadProviders" allowDefinition="AppHostOnly" overrideModeDefault="Deny" />
+            <section name="sites" allowDefinition="AppHostOnly" overrideModeDefault="Deny" />
+            <section name="webLimits" allowDefinition="AppHostOnly" overrideModeDefault="Deny" />
+        </sectionGroup>
+
+        <sectionGroup name="system.webServer">
+            <section name="asp" overrideModeDefault="Deny" />
+            <section name="caching" overrideModeDefault="Allow" />
+            <section name="cgi" overrideModeDefault="Deny" />
+            <section name="defaultDocument" overrideModeDefault="Allow" />
+            <section name="directoryBrowse" overrideModeDefault="Allow" />
+            <section name="fastCgi" allowDefinition="AppHostOnly" overrideModeDefault="Deny" />
+            <section name="globalModules" allowDefinition="AppHostOnly" overrideModeDefault="Deny" />
+            <section name="handlers" overrideModeDefault="Deny" />
+            <section name="httpCompression" allowDefinition="AppHostOnly" overrideModeDefault="Deny" />
+            <section name="httpErrors" overrideModeDefault="Allow" />
+            <section name="httpLogging" overrideModeDefault="Deny" />
+            <section name="httpProtocol" overrideModeDefault="Allow" />
+            <section name="httpRedirect" overrideModeDefault="Allow" />
+            <section name="httpTracing" overrideModeDefault="Deny" />
+            <section name="isapiFilters" allowDefinition="MachineToApplication" overrideModeDefault="Deny" />
+            <section name="modules" allowDefinition="MachineToApplication" overrideModeDefault="Deny" />
+            <section name="odbcLogging" overrideModeDefault="Deny" />
+            <sectionGroup name="security">
+                <section name="access" overrideModeDefault="Deny" />
+                <section name="applicationDependencies" overrideModeDefault="Deny" />
+                <sectionGroup name="authentication">
+                    <section name="anonymousAuthentication" overrideModeDefault="Deny" />
+                    <section name="basicAuthentication" overrideModeDefault="Deny" />
+                    <section name="clientCertificateMappingAuthentication" overrideModeDefault="Deny" />
+                    <section name="digestAuthentication" overrideModeDefault="Deny" />
+                    <section name="iisClientCertificateMappingAuthentication" overrideModeDefault="Deny" />
+                    <section name="windowsAuthentication" overrideModeDefault="Deny" />
+                </sectionGroup>
+                <section name="authorization" overrideModeDefault="Allow" />
+                <section name="ipSecurity" overrideModeDefault="Deny" />
+                <section name="dynamicIpSecurity" overrideModeDefault="Deny" />
+                <section name="isapiCgiRestriction" allowDefinition="AppHostOnly" overrideModeDefault="Deny" />
+                <section name="requestFiltering" overrideModeDefault="Allow" />
+            </sectionGroup>
+            <section name="serverRuntime" overrideModeDefault="Deny" />
+            <section name="serverSideInclude" overrideModeDefault="Deny" />
+            <section name="staticContent" overrideModeDefault="Allow" />
+            <sectionGroup name="tracing">
+                <section name="traceFailedRequests" overrideModeDefault="Allow" />
+                <section name="traceProviderDefinitions" overrideModeDefault="Deny" />
+            </sectionGroup>
+            <section name="urlCompression" overrideModeDefault="Allow" />
+            <section name="validation" overrideModeDefault="Allow" />
+            <sectionGroup name="webdav">
+                <section name="globalSettings" overrideModeDefault="Deny" />
+                <section name="authoring" overrideModeDefault="Deny" />
+                <section name="authoringRules" overrideModeDefault="Deny" />
+            </sectionGroup>
+            <sectionGroup name="rewrite">
+                <section name="allowedServerVariables" overrideModeDefault="Deny" />
+                <section name="rules" overrideModeDefault="Allow" />
+                <section name="outboundRules" overrideModeDefault="Allow" />
+                <section name="globalRules" overrideModeDefault="Deny" allowDefinition="AppHostOnly" />
+                <section name="providers" overrideModeDefault="Allow" />
+                <section name="rewriteMaps" overrideModeDefault="Allow" />
+            </sectionGroup>
+            <section name="applicationInitialization" allowDefinition="MachineToApplication" overrideModeDefault="Allow" />
+            <section name="webSocket" overrideModeDefault="Deny" />
+            <section name="aspNetCore" overrideModeDefault="Allow" />
+        </sectionGroup>
+    </configSections>
+
+    <configProtectedData>
+        <providers>
+            <add name="IISWASOnlyRsaProvider" type="" description="Uses RsaCryptoServiceProvider to encrypt and decrypt" keyContainerName="iisWasKey" cspProviderName="" useMachineContainer="true" useOAEP="false" />
+            <add name="AesProvider" type="Microsoft.ApplicationHost.AesProtectedConfigurationProvider" description="Uses an AES session key to encrypt and decrypt" keyContainerName="iisConfigurationKey" cspProviderName="" useOAEP="false" useMachineContainer="true" sessionKey="AQIAAA5mAAAApAAAKmFQvWHDEETRz8l2bjZlRxIkwcqTFaCUnCLljn3Q1OkesrhEO9YyLyx4bUhsj1/DyShAv7OAFFhXlrlomaornnk5PLeyO4lIXxaiT33yOFUUgxDx4GSaygkqghVV0tO5yQ/XguUBp2juMfZyztnsNa4pLcz7ZNZQ6p4yn9hxwNs=" />
+            <add name="IISWASOnlyAesProvider" type="Microsoft.ApplicationHost.AesProtectedConfigurationProvider" description="Uses an AES session key to encrypt and decrypt" keyContainerName="iisWasKey" cspProviderName="" useOAEP="false" useMachineContainer="true" sessionKey="AQIAAA5mAAAApAAA4WoiRJ8KHwzAG8AgejPxEOO4/2Vhkolbwo/8gZeNdUDSD36m55hWv4uC9tr/MlKdnwRLL0NhT50Gccyftqz5xTZ0dg5FtvQhTw/he1NwexTKbV+I4Zrd+sZUqHZTsr7JiEr6OHGXL70qoISW5G2m9U8wKT3caPiDPNj2aAaYPLo=" />
+        </providers>
+    </configProtectedData>
+
+    <system.applicationHost>
+
+        <applicationPools>
+            <add name="Clr4IntegratedAppPool" managedRuntimeVersion="v4.0" managedPipelineMode="Integrated" CLRConfigFile="%IIS_BIN%\config\templates\PersonalWebServer\aspnet.config" autoStart="true" />
+            <add name="Clr4ClassicAppPool" managedRuntimeVersion="v4.0" managedPipelineMode="Classic" CLRConfigFile="%IIS_BIN%\config\templates\PersonalWebServer\aspnet.config" autoStart="true" />
+            <add name="Clr2IntegratedAppPool" managedRuntimeVersion="v2.0" managedPipelineMode="Integrated" CLRConfigFile="%IIS_BIN%\config\templates\PersonalWebServer\aspnet.config" autoStart="true" />
+            <add name="Clr2ClassicAppPool" managedRuntimeVersion="v2.0" managedPipelineMode="Classic" CLRConfigFile="%IIS_BIN%\config\templates\PersonalWebServer\aspnet.config" autoStart="true" />
+            <add name="UnmanagedClassicAppPool" managedRuntimeVersion="" managedPipelineMode="Classic" autoStart="true" />
+            <add name="IISExpressAppPool" managedRuntimeVersion="v4.0" managedPipelineMode="Integrated" CLRConfigFile="%IIS_BIN%\config\templates\PersonalWebServer\aspnet.config" autoStart="true" />
+            <applicationPoolDefaults managedRuntimeLoader="v4.0">
+                <processModel />
+            </applicationPoolDefaults>
+        </applicationPools>
+
+        <!--
+
+          The <listenerAdapters> section defines the protocols with which the
+          Windows Process Activation Service (WAS) binds.
+
+        -->
+        <listenerAdapters>
+            <add name="http" />
+        </listenerAdapters>
+
+        <sites>
+            <site name="HttpsTestSite" id="1" serverAutoStart="true">
+                <application path="/">
+                    <virtualDirectory path="/" physicalPath="[ApplicationPhysicalPath]" />
+                </application>
+                <bindings>
+                    <binding protocol="https" bindingInformation=":[PORT]:localhost" />
+                </bindings>
+            </site>
+            <siteDefaults>
+                <logFile logFormat="W3C" directory="%IIS_USER_HOME%\Logs" />
+                <traceFailedRequestsLogging directory="%IIS_USER_HOME%\TraceLogFiles" enabled="true" maxLogFileSizeKB="1024" />
+            </siteDefaults>
+            <applicationDefaults applicationPool="IISExpressAppPool" />
+            <virtualDirectoryDefaults allowSubDirConfig="true" />
+        </sites>
+
+        <webLimits />
+
+    </system.applicationHost>
+
+    <system.webServer>
+
+        <serverRuntime />
+
+        <asp scriptErrorSentToBrowser="true">
+            <cache diskTemplateCacheDirectory="%TEMP%\iisexpress\ASP Compiled Templates" />
+            <limits />
+        </asp>
+
+        <caching enabled="true" enableKernelCache="true">
+        </caching>
+
+        <cgi />
+
+        <defaultDocument enabled="true">
+            <files>
+                <add value="Default.htm" />
+                <add value="Default.asp" />
+                <add value="index.htm" />
+                <add value="index.html" />
+                <add value="iisstart.htm" />
+                <add value="default.aspx" />
+            </files>
+        </defaultDocument>
+
+        <directoryBrowse enabled="false" />
+
+        <fastCgi />
+
+        <!--
+
+          The <globalModules> section defines all native-code modules.
+          To enable a module, specify it in the <modules> section.
+
+        -->
+        <globalModules>
+            <add name="UriCacheModule" image="%IIS_BIN%\cachuri.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="DynamicCompressionModule" image="%IIS_BIN%\compdyn.dll" />
+            <add name="StaticCompressionModule" image="%IIS_BIN%\compstat.dll" />
+            <add name="DefaultDocumentModule" image="%IIS_BIN%\defdoc.dll" />
+            <add name="DirectoryListingModule" image="%IIS_BIN%\dirlist.dll" />
+            <add name="ProtocolSupportModule" image="%IIS_BIN%\protsup.dll" />
+            <add name="HttpRedirectionModule" image="%IIS_BIN%\redirect.dll" />
+            <add name="ServerSideIncludeModule" image="%IIS_BIN%\iis_ssi.dll" />
+            <add name="StaticFileModule" image="%IIS_BIN%\static.dll" />
+            <add name="AnonymousAuthenticationModule" image="%IIS_BIN%\authanon.dll" />
+            <add name="CertificateMappingAuthenticationModule" image="%IIS_BIN%\authcert.dll" />
+            <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="IISCertificateMappingAuthenticationModule" image="%IIS_BIN%\authmap.dll" />
+            <add name="IpRestrictionModule" image="%IIS_BIN%\iprestr.dll" />
+            <add name="DynamicIpRestrictionModule" image="%IIS_BIN%\diprestr.dll" />
+            <add name="RequestFilteringModule" image="%IIS_BIN%\modrqflt.dll" />
+            <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="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="RewriteModule" image="%IIS_BIN%\rewrite.dll" />
+            <add name="ConfigurationValidationModule" image="%IIS_BIN%\validcfg.dll" />
+            <add name="ApplicationInitializationModule" image="%IIS_BIN%\warmup.dll" />
+            <add name="WebSocketModule" image="%IIS_BIN%\iiswsock.dll" />
+            <add name="WebMatrixSupportModule" image="%IIS_BIN%\webmatrixsup.dll" />
+            <add name="ManagedEngine" image="%windir%\Microsoft.NET\Framework\v2.0.50727\webengine.dll" preCondition="integratedMode,runtimeVersionv2.0,bitness32" />
+            <add name="ManagedEngine64" image="%windir%\Microsoft.NET\Framework64\v2.0.50727\webengine.dll" preCondition="integratedMode,runtimeVersionv2.0,bitness64" />
+            <add name="ManagedEngineV4.0_32bit" image="%windir%\Microsoft.NET\Framework\v4.0.30319\webengine4.dll" preCondition="integratedMode,runtimeVersionv4.0,bitness32" />
+            <add name="ManagedEngineV4.0_64bit" image="%windir%\Microsoft.NET\Framework64\v4.0.30319\webengine4.dll" preCondition="integratedMode,runtimeVersionv4.0,bitness64" />
+            <add name="AspNetCoreModule" image="[ANCMPath]" />
+        </globalModules>
+
+        <httpCompression directory="%TEMP%\iisexpress\IIS Temporary Compressed Files">
+            <scheme name="gzip" dll="%IIS_BIN%\gzip.dll" />
+            <dynamicTypes>
+                <add mimeType="text/*" enabled="true" />
+                <add mimeType="message/*" enabled="true" />
+                <add mimeType="application/x-javascript" enabled="true" />
+                <add mimeType="*/*" enabled="false" />
+            </dynamicTypes>
+            <staticTypes>
+                <add mimeType="text/*" enabled="true" />
+                <add mimeType="message/*" enabled="true" />
+                <add mimeType="application/x-javascript" enabled="true" />
+                <add mimeType="application/atom+xml" enabled="true" />
+                <add mimeType="application/xaml+xml" enabled="true" />
+                <add mimeType="*/*" enabled="false" />
+            </staticTypes>
+        </httpCompression>
+
+        <httpErrors lockAttributes="allowAbsolutePathsWhenDelegated,defaultPath">
+            <error statusCode="401" prefixLanguageFilePath="%IIS_BIN%\custerr" path="401.htm" />
+            <error statusCode="403" prefixLanguageFilePath="%IIS_BIN%\custerr" path="403.htm" />
+            <error statusCode="404" prefixLanguageFilePath="%IIS_BIN%\custerr" path="404.htm" />
+            <error statusCode="405" prefixLanguageFilePath="%IIS_BIN%\custerr" path="405.htm" />
+            <error statusCode="406" prefixLanguageFilePath="%IIS_BIN%\custerr" path="406.htm" />
+            <error statusCode="412" prefixLanguageFilePath="%IIS_BIN%\custerr" path="412.htm" />
+            <error statusCode="500" prefixLanguageFilePath="%IIS_BIN%\custerr" path="500.htm" />
+            <error statusCode="501" prefixLanguageFilePath="%IIS_BIN%\custerr" path="501.htm" />
+            <error statusCode="502" prefixLanguageFilePath="%IIS_BIN%\custerr" path="502.htm" />
+        </httpErrors>
+
+        <httpLogging dontLog="false" />
+
+        <httpProtocol>
+            <customHeaders>
+                <clear />
+                <add name="X-Powered-By" value="ASP.NET" />
+            </customHeaders>
+            <redirectHeaders>
+                <clear />
+            </redirectHeaders>
+        </httpProtocol>
+
+        <httpRedirect enabled="false" />
+
+        <httpTracing>
+        </httpTracing>
+
+        <isapiFilters>
+            <filter name="ASP.Net_2.0.50727-64" path="%windir%\Microsoft.NET\Framework64\v2.0.50727\aspnet_filter.dll" enableCache="true" preCondition="bitness64,runtimeVersionv2.0" />
+            <filter name="ASP.Net_2.0.50727.0" path="%windir%\Microsoft.NET\Framework\v2.0.50727\aspnet_filter.dll" enableCache="true" preCondition="bitness32,runtimeVersionv2.0" />
+            <filter name="ASP.Net_2.0_for_v1.1" path="%windir%\Microsoft.NET\Framework\v2.0.50727\aspnet_filter.dll" enableCache="true" preCondition="runtimeVersionv1.1" />
+            <filter name="ASP.Net_4.0_32bit" path="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_filter.dll" enableCache="true" preCondition="bitness32,runtimeVersionv4.0" />
+            <filter name="ASP.Net_4.0_64bit" path="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_filter.dll" enableCache="true" preCondition="bitness64,runtimeVersionv4.0" />
+        </isapiFilters>
+
+        <odbcLogging />
+
+        <security>
+
+            <access sslFlags="Ssl, SslNegotiateCert" />
+
+            <applicationDependencies>
+                <application name="Active Server Pages" groupId="ASP" />
+            </applicationDependencies>
+
+            <authentication>
+
+                <anonymousAuthentication enabled="true" userName="" />
+
+                <basicAuthentication enabled="false" />
+
+                <clientCertificateMappingAuthentication enabled="false" />
+
+                <digestAuthentication enabled="false" />
+
+                <iisClientCertificateMappingAuthentication enabled="false">
+                </iisClientCertificateMappingAuthentication>
+
+                <windowsAuthentication enabled="false">
+                    <providers>
+                        <add value="Negotiate" />
+                        <add value="NTLM" />
+                    </providers>
+                </windowsAuthentication>
+
+            </authentication>
+
+            <authorization>
+                <add accessType="Allow" users="*" />
+            </authorization>
+
+            <ipSecurity allowUnlisted="true" />
+
+            <isapiCgiRestriction notListedIsapisAllowed="true" notListedCgisAllowed="true">
+                <add path="%windir%\Microsoft.NET\Framework64\v4.0.30319\webengine4.dll" allowed="true" groupId="ASP.NET_v4.0" description="ASP.NET_v4.0" />
+                <add path="%windir%\Microsoft.NET\Framework\v4.0.30319\webengine4.dll" allowed="true" groupId="ASP.NET_v4.0" description="ASP.NET_v4.0" />
+                <add path="%windir%\Microsoft.NET\Framework64\v2.0.50727\aspnet_isapi.dll" allowed="true" groupId="ASP.NET v2.0.50727" description="ASP.NET v2.0.50727" />
+                <add path="%windir%\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll" allowed="true" groupId="ASP.NET v2.0.50727" description="ASP.NET v2.0.50727" />
+            </isapiCgiRestriction>
+
+            <requestFiltering>
+                <fileExtensions allowUnlisted="true" applyToWebDAV="true">
+                    <add fileExtension=".asa" allowed="false" />
+                    <add fileExtension=".asax" allowed="false" />
+                    <add fileExtension=".ascx" allowed="false" />
+                    <add fileExtension=".master" allowed="false" />
+                    <add fileExtension=".skin" allowed="false" />
+                    <add fileExtension=".browser" allowed="false" />
+                    <add fileExtension=".sitemap" allowed="false" />
+                    <add fileExtension=".config" allowed="false" />
+                    <add fileExtension=".cs" allowed="false" />
+                    <add fileExtension=".csproj" allowed="false" />
+                    <add fileExtension=".vb" allowed="false" />
+                    <add fileExtension=".vbproj" allowed="false" />
+                    <add fileExtension=".webinfo" allowed="false" />
+                    <add fileExtension=".licx" allowed="false" />
+                    <add fileExtension=".resx" allowed="false" />
+                    <add fileExtension=".resources" allowed="false" />
+                    <add fileExtension=".mdb" allowed="false" />
+                    <add fileExtension=".vjsproj" allowed="false" />
+                    <add fileExtension=".java" allowed="false" />
+                    <add fileExtension=".jsl" allowed="false" />
+                    <add fileExtension=".ldb" allowed="false" />
+                    <add fileExtension=".dsdgm" allowed="false" />
+                    <add fileExtension=".ssdgm" allowed="false" />
+                    <add fileExtension=".lsad" allowed="false" />
+                    <add fileExtension=".ssmap" allowed="false" />
+                    <add fileExtension=".cd" allowed="false" />
+                    <add fileExtension=".dsprototype" allowed="false" />
+                    <add fileExtension=".lsaprototype" allowed="false" />
+                    <add fileExtension=".sdm" allowed="false" />
+                    <add fileExtension=".sdmDocument" allowed="false" />
+                    <add fileExtension=".mdf" allowed="false" />
+                    <add fileExtension=".ldf" allowed="false" />
+                    <add fileExtension=".ad" allowed="false" />
+                    <add fileExtension=".dd" allowed="false" />
+                    <add fileExtension=".ldd" allowed="false" />
+                    <add fileExtension=".sd" allowed="false" />
+                    <add fileExtension=".adprototype" allowed="false" />
+                    <add fileExtension=".lddprototype" allowed="false" />
+                    <add fileExtension=".exclude" allowed="false" />
+                    <add fileExtension=".refresh" allowed="false" />
+                    <add fileExtension=".compiled" allowed="false" />
+                    <add fileExtension=".msgx" allowed="false" />
+                    <add fileExtension=".vsdisco" allowed="false" />
+                    <add fileExtension=".rules" allowed="false" />
+                </fileExtensions>
+                <verbs allowUnlisted="true" applyToWebDAV="true" />
+                <hiddenSegments applyToWebDAV="true">
+                    <add segment="web.config" />
+                    <add segment="bin" />
+                    <add segment="App_code" />
+                    <add segment="App_GlobalResources" />
+                    <add segment="App_LocalResources" />
+                    <add segment="App_WebReferences" />
+                    <add segment="App_Data" />
+                    <add segment="App_Browsers" />
+                </hiddenSegments>
+            </requestFiltering>
+
+        </security>
+
+        <serverSideInclude ssiExecDisable="false" />
+
+        <staticContent lockAttributes="isDocFooterFileName">
+            <mimeMap fileExtension=".323" mimeType="text/h323" />
+            <mimeMap fileExtension=".3g2" mimeType="video/3gpp2" />
+            <mimeMap fileExtension=".3gp2" mimeType="video/3gpp2" />
+            <mimeMap fileExtension=".3gp" mimeType="video/3gpp" />
+            <mimeMap fileExtension=".3gpp" mimeType="video/3gpp" />
+            <mimeMap fileExtension=".aac" mimeType="audio/aac" />
+            <mimeMap fileExtension=".aaf" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".aca" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".accdb" mimeType="application/msaccess" />
+            <mimeMap fileExtension=".accde" mimeType="application/msaccess" />
+            <mimeMap fileExtension=".accdt" mimeType="application/msaccess" />
+            <mimeMap fileExtension=".acx" mimeType="application/internet-property-stream" />
+            <mimeMap fileExtension=".adt" mimeType="audio/vnd.dlna.adts" />
+            <mimeMap fileExtension=".adts" mimeType="audio/vnd.dlna.adts" />
+            <mimeMap fileExtension=".afm" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".ai" mimeType="application/postscript" />
+            <mimeMap fileExtension=".aif" mimeType="audio/x-aiff" />
+            <mimeMap fileExtension=".aifc" mimeType="audio/aiff" />
+            <mimeMap fileExtension=".aiff" mimeType="audio/aiff" />
+            <mimeMap fileExtension=".application" mimeType="application/x-ms-application" />
+            <mimeMap fileExtension=".art" mimeType="image/x-jg" />
+            <mimeMap fileExtension=".asd" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".asf" mimeType="video/x-ms-asf" />
+            <mimeMap fileExtension=".asi" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".asm" mimeType="text/plain" />
+            <mimeMap fileExtension=".asr" mimeType="video/x-ms-asf" />
+            <mimeMap fileExtension=".asx" mimeType="video/x-ms-asf" />
+            <mimeMap fileExtension=".atom" mimeType="application/atom+xml" />
+            <mimeMap fileExtension=".au" mimeType="audio/basic" />
+            <mimeMap fileExtension=".avi" mimeType="video/x-msvideo" />
+            <mimeMap fileExtension=".axs" mimeType="application/olescript" />
+            <mimeMap fileExtension=".bas" mimeType="text/plain" />
+            <mimeMap fileExtension=".bcpio" mimeType="application/x-bcpio" />
+            <mimeMap fileExtension=".bin" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".bmp" mimeType="image/bmp" />
+            <mimeMap fileExtension=".c" mimeType="text/plain" />
+            <mimeMap fileExtension=".cab" mimeType="application/vnd.ms-cab-compressed" />
+            <mimeMap fileExtension=".calx" mimeType="application/vnd.ms-office.calx" />
+            <mimeMap fileExtension=".cat" mimeType="application/vnd.ms-pki.seccat" />
+            <mimeMap fileExtension=".cdf" mimeType="application/x-cdf" />
+            <mimeMap fileExtension=".chm" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".class" mimeType="application/x-java-applet" />
+            <mimeMap fileExtension=".clp" mimeType="application/x-msclip" />
+            <mimeMap fileExtension=".cmx" mimeType="image/x-cmx" />
+            <mimeMap fileExtension=".cnf" mimeType="text/plain" />
+            <mimeMap fileExtension=".cod" mimeType="image/cis-cod" />
+            <mimeMap fileExtension=".cpio" mimeType="application/x-cpio" />
+            <mimeMap fileExtension=".cpp" mimeType="text/plain" />
+            <mimeMap fileExtension=".crd" mimeType="application/x-mscardfile" />
+            <mimeMap fileExtension=".crl" mimeType="application/pkix-crl" />
+            <mimeMap fileExtension=".crt" mimeType="application/x-x509-ca-cert" />
+            <mimeMap fileExtension=".csh" mimeType="application/x-csh" />
+            <mimeMap fileExtension=".css" mimeType="text/css" />
+            <mimeMap fileExtension=".csv" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".cur" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".dcr" mimeType="application/x-director" />
+            <mimeMap fileExtension=".deploy" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".der" mimeType="application/x-x509-ca-cert" />
+            <mimeMap fileExtension=".dib" mimeType="image/bmp" />
+            <mimeMap fileExtension=".dir" mimeType="application/x-director" />
+            <mimeMap fileExtension=".disco" mimeType="text/xml" />
+            <mimeMap fileExtension=".dll" mimeType="application/x-msdownload" />
+            <mimeMap fileExtension=".dll.config" mimeType="text/xml" />
+            <mimeMap fileExtension=".dlm" mimeType="text/dlm" />
+            <mimeMap fileExtension=".doc" mimeType="application/msword" />
+            <mimeMap fileExtension=".docm" mimeType="application/vnd.ms-word.document.macroEnabled.12" />
+            <mimeMap fileExtension=".docx" mimeType="application/vnd.openxmlformats-officedocument.wordprocessingml.document" />
+            <mimeMap fileExtension=".dot" mimeType="application/msword" />
+            <mimeMap fileExtension=".dotm" mimeType="application/vnd.ms-word.template.macroEnabled.12" />
+            <mimeMap fileExtension=".dotx" mimeType="application/vnd.openxmlformats-officedocument.wordprocessingml.template" />
+            <mimeMap fileExtension=".dsp" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".dtd" mimeType="text/xml" />
+            <mimeMap fileExtension=".dvi" mimeType="application/x-dvi" />
+            <mimeMap fileExtension=".dvr-ms" mimeType="video/x-ms-dvr" />
+            <mimeMap fileExtension=".dwf" mimeType="drawing/x-dwf" />
+            <mimeMap fileExtension=".dwp" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".dxr" mimeType="application/x-director" />
+            <mimeMap fileExtension=".eml" mimeType="message/rfc822" />
+            <mimeMap fileExtension=".emz" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".eot" mimeType="application/vnd.ms-fontobject" />
+            <mimeMap fileExtension=".eps" mimeType="application/postscript" />
+            <mimeMap fileExtension=".etx" mimeType="text/x-setext" />
+            <mimeMap fileExtension=".evy" mimeType="application/envoy" />
+            <mimeMap fileExtension=".exe" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".exe.config" mimeType="text/xml" />
+            <mimeMap fileExtension=".fdf" mimeType="application/vnd.fdf" />
+            <mimeMap fileExtension=".fif" mimeType="application/fractals" />
+            <mimeMap fileExtension=".fla" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".flr" mimeType="x-world/x-vrml" />
+            <mimeMap fileExtension=".flv" mimeType="video/x-flv" />
+            <mimeMap fileExtension=".gif" mimeType="image/gif" />
+            <mimeMap fileExtension=".gtar" mimeType="application/x-gtar" />
+            <mimeMap fileExtension=".gz" mimeType="application/x-gzip" />
+            <mimeMap fileExtension=".h" mimeType="text/plain" />
+            <mimeMap fileExtension=".hdf" mimeType="application/x-hdf" />
+            <mimeMap fileExtension=".hdml" mimeType="text/x-hdml" />
+            <mimeMap fileExtension=".hhc" mimeType="application/x-oleobject" />
+            <mimeMap fileExtension=".hhk" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".hhp" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".hlp" mimeType="application/winhlp" />
+            <mimeMap fileExtension=".hqx" mimeType="application/mac-binhex40" />
+            <mimeMap fileExtension=".hta" mimeType="application/hta" />
+            <mimeMap fileExtension=".htc" mimeType="text/x-component" />
+            <mimeMap fileExtension=".htm" mimeType="text/html" />
+            <mimeMap fileExtension=".html" mimeType="text/html" />
+            <mimeMap fileExtension=".htt" mimeType="text/webviewhtml" />
+            <mimeMap fileExtension=".hxt" mimeType="text/html" />
+            <mimeMap fileExtension=".ical" mimeType="text/calendar" />
+            <mimeMap fileExtension=".icalendar" mimeType="text/calendar" />
+            <mimeMap fileExtension=".ico" mimeType="image/x-icon" />
+            <mimeMap fileExtension=".ics" mimeType="text/calendar" />
+            <mimeMap fileExtension=".ief" mimeType="image/ief" />
+            <mimeMap fileExtension=".ifb" mimeType="text/calendar" />
+            <mimeMap fileExtension=".iii" mimeType="application/x-iphone" />
+            <mimeMap fileExtension=".inf" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".ins" mimeType="application/x-internet-signup" />
+            <mimeMap fileExtension=".isp" mimeType="application/x-internet-signup" />
+            <mimeMap fileExtension=".IVF" mimeType="video/x-ivf" />
+            <mimeMap fileExtension=".jar" mimeType="application/java-archive" />
+            <mimeMap fileExtension=".java" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".jck" mimeType="application/liquidmotion" />
+            <mimeMap fileExtension=".jcz" mimeType="application/liquidmotion" />
+            <mimeMap fileExtension=".jfif" mimeType="image/pjpeg" />
+            <mimeMap fileExtension=".jpb" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".jpe" mimeType="image/jpeg" />
+            <mimeMap fileExtension=".jpeg" mimeType="image/jpeg" />
+            <mimeMap fileExtension=".jpg" mimeType="image/jpeg" />
+            <mimeMap fileExtension=".js" mimeType="application/javascript" />
+            <mimeMap fileExtension=".jsx" mimeType="text/jscript" />
+            <mimeMap fileExtension=".latex" mimeType="application/x-latex" />
+            <mimeMap fileExtension=".lit" mimeType="application/x-ms-reader" />
+            <mimeMap fileExtension=".lpk" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".lsf" mimeType="video/x-la-asf" />
+            <mimeMap fileExtension=".lsx" mimeType="video/x-la-asf" />
+            <mimeMap fileExtension=".lzh" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".m13" mimeType="application/x-msmediaview" />
+            <mimeMap fileExtension=".m14" mimeType="application/x-msmediaview" />
+            <mimeMap fileExtension=".m1v" mimeType="video/mpeg" />
+            <mimeMap fileExtension=".m2ts" mimeType="video/vnd.dlna.mpeg-tts" />
+            <mimeMap fileExtension=".m3u" mimeType="audio/x-mpegurl" />
+            <mimeMap fileExtension=".m4a" mimeType="audio/mp4" />
+            <mimeMap fileExtension=".m4v" mimeType="video/mp4" />
+            <mimeMap fileExtension=".man" mimeType="application/x-troff-man" />
+            <mimeMap fileExtension=".manifest" mimeType="application/x-ms-manifest" />
+            <mimeMap fileExtension=".map" mimeType="text/plain" />
+            <mimeMap fileExtension=".mdb" mimeType="application/x-msaccess" />
+            <mimeMap fileExtension=".mdp" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".me" mimeType="application/x-troff-me" />
+            <mimeMap fileExtension=".mht" mimeType="message/rfc822" />
+            <mimeMap fileExtension=".mhtml" mimeType="message/rfc822" />
+            <mimeMap fileExtension=".mid" mimeType="audio/mid" />
+            <mimeMap fileExtension=".midi" mimeType="audio/mid" />
+            <mimeMap fileExtension=".mix" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".mmf" mimeType="application/x-smaf" />
+            <mimeMap fileExtension=".mno" mimeType="text/xml" />
+            <mimeMap fileExtension=".mny" mimeType="application/x-msmoney" />
+            <mimeMap fileExtension=".mov" mimeType="video/quicktime" />
+            <mimeMap fileExtension=".movie" mimeType="video/x-sgi-movie" />
+            <mimeMap fileExtension=".mp2" mimeType="video/mpeg" />
+            <mimeMap fileExtension=".mp3" mimeType="audio/mpeg" />
+            <mimeMap fileExtension=".mp4" mimeType="video/mp4" />
+            <mimeMap fileExtension=".mp4v" mimeType="video/mp4" />
+            <mimeMap fileExtension=".mpa" mimeType="video/mpeg" />
+            <mimeMap fileExtension=".mpe" mimeType="video/mpeg" />
+            <mimeMap fileExtension=".mpeg" mimeType="video/mpeg" />
+            <mimeMap fileExtension=".mpg" mimeType="video/mpeg" />
+            <mimeMap fileExtension=".mpp" mimeType="application/vnd.ms-project" />
+            <mimeMap fileExtension=".mpv2" mimeType="video/mpeg" />
+            <mimeMap fileExtension=".ms" mimeType="application/x-troff-ms" />
+            <mimeMap fileExtension=".msi" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".mso" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".mvb" mimeType="application/x-msmediaview" />
+            <mimeMap fileExtension=".mvc" mimeType="application/x-miva-compiled" />
+            <mimeMap fileExtension=".nc" mimeType="application/x-netcdf" />
+            <mimeMap fileExtension=".nsc" mimeType="video/x-ms-asf" />
+            <mimeMap fileExtension=".nws" mimeType="message/rfc822" />
+            <mimeMap fileExtension=".ocx" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".oda" mimeType="application/oda" />
+            <mimeMap fileExtension=".odc" mimeType="text/x-ms-odc" />
+            <mimeMap fileExtension=".ods" mimeType="application/oleobject" />
+            <mimeMap fileExtension=".oga" mimeType="audio/ogg" />
+            <mimeMap fileExtension=".ogg" mimeType="video/ogg" />
+            <mimeMap fileExtension=".ogv" mimeType="video/ogg" />
+            <mimeMap fileExtension=".ogx" mimeType="application/ogg" />
+            <mimeMap fileExtension=".one" mimeType="application/onenote" />
+            <mimeMap fileExtension=".onea" mimeType="application/onenote" />
+            <mimeMap fileExtension=".onetoc" mimeType="application/onenote" />
+            <mimeMap fileExtension=".onetoc2" mimeType="application/onenote" />
+            <mimeMap fileExtension=".onetmp" mimeType="application/onenote" />
+            <mimeMap fileExtension=".onepkg" mimeType="application/onenote" />
+            <mimeMap fileExtension=".osdx" mimeType="application/opensearchdescription+xml" />
+            <mimeMap fileExtension=".otf" mimeType="font/otf" />
+            <mimeMap fileExtension=".p10" mimeType="application/pkcs10" />
+            <mimeMap fileExtension=".p12" mimeType="application/x-pkcs12" />
+            <mimeMap fileExtension=".p7b" mimeType="application/x-pkcs7-certificates" />
+            <mimeMap fileExtension=".p7c" mimeType="application/pkcs7-mime" />
+            <mimeMap fileExtension=".p7m" mimeType="application/pkcs7-mime" />
+            <mimeMap fileExtension=".p7r" mimeType="application/x-pkcs7-certreqresp" />
+            <mimeMap fileExtension=".p7s" mimeType="application/pkcs7-signature" />
+            <mimeMap fileExtension=".pbm" mimeType="image/x-portable-bitmap" />
+            <mimeMap fileExtension=".pcx" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".pcz" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".pdf" mimeType="application/pdf" />
+            <mimeMap fileExtension=".pfb" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".pfm" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".pfx" mimeType="application/x-pkcs12" />
+            <mimeMap fileExtension=".pgm" mimeType="image/x-portable-graymap" />
+            <mimeMap fileExtension=".pko" mimeType="application/vnd.ms-pki.pko" />
+            <mimeMap fileExtension=".pma" mimeType="application/x-perfmon" />
+            <mimeMap fileExtension=".pmc" mimeType="application/x-perfmon" />
+            <mimeMap fileExtension=".pml" mimeType="application/x-perfmon" />
+            <mimeMap fileExtension=".pmr" mimeType="application/x-perfmon" />
+            <mimeMap fileExtension=".pmw" mimeType="application/x-perfmon" />
+            <mimeMap fileExtension=".png" mimeType="image/png" />
+            <mimeMap fileExtension=".pnm" mimeType="image/x-portable-anymap" />
+            <mimeMap fileExtension=".pnz" mimeType="image/png" />
+            <mimeMap fileExtension=".pot" mimeType="application/vnd.ms-powerpoint" />
+            <mimeMap fileExtension=".potm" mimeType="application/vnd.ms-powerpoint.template.macroEnabled.12" />
+            <mimeMap fileExtension=".potx" mimeType="application/vnd.openxmlformats-officedocument.presentationml.template" />
+            <mimeMap fileExtension=".ppam" mimeType="application/vnd.ms-powerpoint.addin.macroEnabled.12" />
+            <mimeMap fileExtension=".ppm" mimeType="image/x-portable-pixmap" />
+            <mimeMap fileExtension=".pps" mimeType="application/vnd.ms-powerpoint" />
+            <mimeMap fileExtension=".ppsm" mimeType="application/vnd.ms-powerpoint.slideshow.macroEnabled.12" />
+            <mimeMap fileExtension=".ppsx" mimeType="application/vnd.openxmlformats-officedocument.presentationml.slideshow" />
+            <mimeMap fileExtension=".ppt" mimeType="application/vnd.ms-powerpoint" />
+            <mimeMap fileExtension=".pptm" mimeType="application/vnd.ms-powerpoint.presentation.macroEnabled.12" />
+            <mimeMap fileExtension=".pptx" mimeType="application/vnd.openxmlformats-officedocument.presentationml.presentation" />
+            <mimeMap fileExtension=".prf" mimeType="application/pics-rules" />
+            <mimeMap fileExtension=".prm" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".prx" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".ps" mimeType="application/postscript" />
+            <mimeMap fileExtension=".psd" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".psm" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".psp" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".pub" mimeType="application/x-mspublisher" />
+            <mimeMap fileExtension=".qt" mimeType="video/quicktime" />
+            <mimeMap fileExtension=".qtl" mimeType="application/x-quicktimeplayer" />
+            <mimeMap fileExtension=".qxd" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".ra" mimeType="audio/x-pn-realaudio" />
+            <mimeMap fileExtension=".ram" mimeType="audio/x-pn-realaudio" />
+            <mimeMap fileExtension=".rar" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".ras" mimeType="image/x-cmu-raster" />
+            <mimeMap fileExtension=".rf" mimeType="image/vnd.rn-realflash" />
+            <mimeMap fileExtension=".rgb" mimeType="image/x-rgb" />
+            <mimeMap fileExtension=".rm" mimeType="application/vnd.rn-realmedia" />
+            <mimeMap fileExtension=".rmi" mimeType="audio/mid" />
+            <mimeMap fileExtension=".roff" mimeType="application/x-troff" />
+            <mimeMap fileExtension=".rpm" mimeType="audio/x-pn-realaudio-plugin" />
+            <mimeMap fileExtension=".rtf" mimeType="application/rtf" />
+            <mimeMap fileExtension=".rtx" mimeType="text/richtext" />
+            <mimeMap fileExtension=".scd" mimeType="application/x-msschedule" />
+            <mimeMap fileExtension=".sct" mimeType="text/scriptlet" />
+            <mimeMap fileExtension=".sea" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".setpay" mimeType="application/set-payment-initiation" />
+            <mimeMap fileExtension=".setreg" mimeType="application/set-registration-initiation" />
+            <mimeMap fileExtension=".sgml" mimeType="text/sgml" />
+            <mimeMap fileExtension=".sh" mimeType="application/x-sh" />
+            <mimeMap fileExtension=".shar" mimeType="application/x-shar" />
+            <mimeMap fileExtension=".sit" mimeType="application/x-stuffit" />
+            <mimeMap fileExtension=".sldm" mimeType="application/vnd.ms-powerpoint.slide.macroEnabled.12" />
+            <mimeMap fileExtension=".sldx" mimeType="application/vnd.openxmlformats-officedocument.presentationml.slide" />
+            <mimeMap fileExtension=".smd" mimeType="audio/x-smd" />
+            <mimeMap fileExtension=".smi" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".smx" mimeType="audio/x-smd" />
+            <mimeMap fileExtension=".smz" mimeType="audio/x-smd" />
+            <mimeMap fileExtension=".snd" mimeType="audio/basic" />
+            <mimeMap fileExtension=".snp" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".spc" mimeType="application/x-pkcs7-certificates" />
+            <mimeMap fileExtension=".spl" mimeType="application/futuresplash" />
+            <mimeMap fileExtension=".spx" mimeType="audio/ogg" />
+            <mimeMap fileExtension=".src" mimeType="application/x-wais-source" />
+            <mimeMap fileExtension=".ssm" mimeType="application/streamingmedia" />
+            <mimeMap fileExtension=".sst" mimeType="application/vnd.ms-pki.certstore" />
+            <mimeMap fileExtension=".stl" mimeType="application/vnd.ms-pki.stl" />
+            <mimeMap fileExtension=".sv4cpio" mimeType="application/x-sv4cpio" />
+            <mimeMap fileExtension=".sv4crc" mimeType="application/x-sv4crc" />
+            <mimeMap fileExtension=".svg" mimeType="image/svg+xml" />
+            <mimeMap fileExtension=".svgz" mimeType="image/svg+xml" />
+            <mimeMap fileExtension=".swf" mimeType="application/x-shockwave-flash" />
+            <mimeMap fileExtension=".t" mimeType="application/x-troff" />
+            <mimeMap fileExtension=".tar" mimeType="application/x-tar" />
+            <mimeMap fileExtension=".tcl" mimeType="application/x-tcl" />
+            <mimeMap fileExtension=".tex" mimeType="application/x-tex" />
+            <mimeMap fileExtension=".texi" mimeType="application/x-texinfo" />
+            <mimeMap fileExtension=".texinfo" mimeType="application/x-texinfo" />
+            <mimeMap fileExtension=".tgz" mimeType="application/x-compressed" />
+            <mimeMap fileExtension=".thmx" mimeType="application/vnd.ms-officetheme" />
+            <mimeMap fileExtension=".thn" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".tif" mimeType="image/tiff" />
+            <mimeMap fileExtension=".tiff" mimeType="image/tiff" />
+            <mimeMap fileExtension=".toc" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".tr" mimeType="application/x-troff" />
+            <mimeMap fileExtension=".trm" mimeType="application/x-msterminal" />
+            <mimeMap fileExtension=".ts" mimeType="video/vnd.dlna.mpeg-tts" />
+            <mimeMap fileExtension=".tsv" mimeType="text/tab-separated-values" />
+            <mimeMap fileExtension=".ttf" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".tts" mimeType="video/vnd.dlna.mpeg-tts" />
+            <mimeMap fileExtension=".txt" mimeType="text/plain" />
+            <mimeMap fileExtension=".u32" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".uls" mimeType="text/iuls" />
+            <mimeMap fileExtension=".ustar" mimeType="application/x-ustar" />
+            <mimeMap fileExtension=".vbs" mimeType="text/vbscript" />
+            <mimeMap fileExtension=".vcf" mimeType="text/x-vcard" />
+            <mimeMap fileExtension=".vcs" mimeType="text/plain" />
+            <mimeMap fileExtension=".vdx" mimeType="application/vnd.ms-visio.viewer" />
+            <mimeMap fileExtension=".vml" mimeType="text/xml" />
+            <mimeMap fileExtension=".vsd" mimeType="application/vnd.visio" />
+            <mimeMap fileExtension=".vss" mimeType="application/vnd.visio" />
+            <mimeMap fileExtension=".vst" mimeType="application/vnd.visio" />
+            <mimeMap fileExtension=".vsto" mimeType="application/x-ms-vsto" />
+            <mimeMap fileExtension=".vsw" mimeType="application/vnd.visio" />
+            <mimeMap fileExtension=".vsx" mimeType="application/vnd.visio" />
+            <mimeMap fileExtension=".vtx" mimeType="application/vnd.visio" />
+            <mimeMap fileExtension=".wav" mimeType="audio/wav" />
+            <mimeMap fileExtension=".wax" mimeType="audio/x-ms-wax" />
+            <mimeMap fileExtension=".wbmp" mimeType="image/vnd.wap.wbmp" />
+            <mimeMap fileExtension=".wcm" mimeType="application/vnd.ms-works" />
+            <mimeMap fileExtension=".wdb" mimeType="application/vnd.ms-works" />
+            <mimeMap fileExtension=".webm" mimeType="video/webm" />
+            <mimeMap fileExtension=".wks" mimeType="application/vnd.ms-works" />
+            <mimeMap fileExtension=".wm" mimeType="video/x-ms-wm" />
+            <mimeMap fileExtension=".wma" mimeType="audio/x-ms-wma" />
+            <mimeMap fileExtension=".wmd" mimeType="application/x-ms-wmd" />
+            <mimeMap fileExtension=".wmf" mimeType="application/x-msmetafile" />
+            <mimeMap fileExtension=".wml" mimeType="text/vnd.wap.wml" />
+            <mimeMap fileExtension=".wmlc" mimeType="application/vnd.wap.wmlc" />
+            <mimeMap fileExtension=".wmls" mimeType="text/vnd.wap.wmlscript" />
+            <mimeMap fileExtension=".wmlsc" mimeType="application/vnd.wap.wmlscriptc" />
+            <mimeMap fileExtension=".wmp" mimeType="video/x-ms-wmp" />
+            <mimeMap fileExtension=".wmv" mimeType="video/x-ms-wmv" />
+            <mimeMap fileExtension=".wmx" mimeType="video/x-ms-wmx" />
+            <mimeMap fileExtension=".wmz" mimeType="application/x-ms-wmz" />
+            <mimeMap fileExtension=".woff" mimeType="font/x-woff" />
+            <mimeMap fileExtension=".wps" mimeType="application/vnd.ms-works" />
+            <mimeMap fileExtension=".wri" mimeType="application/x-mswrite" />
+            <mimeMap fileExtension=".wrl" mimeType="x-world/x-vrml" />
+            <mimeMap fileExtension=".wrz" mimeType="x-world/x-vrml" />
+            <mimeMap fileExtension=".wsdl" mimeType="text/xml" />
+            <mimeMap fileExtension=".wtv" mimeType="video/x-ms-wtv" />
+            <mimeMap fileExtension=".wvx" mimeType="video/x-ms-wvx" />
+            <mimeMap fileExtension=".x" mimeType="application/directx" />
+            <mimeMap fileExtension=".xaf" mimeType="x-world/x-vrml" />
+            <mimeMap fileExtension=".xaml" mimeType="application/xaml+xml" />
+            <mimeMap fileExtension=".xap" mimeType="application/x-silverlight-app" />
+            <mimeMap fileExtension=".xbap" mimeType="application/x-ms-xbap" />
+            <mimeMap fileExtension=".xbm" mimeType="image/x-xbitmap" />
+            <mimeMap fileExtension=".xdr" mimeType="text/plain" />
+            <mimeMap fileExtension=".xht" mimeType="application/xhtml+xml" />
+            <mimeMap fileExtension=".xhtml" mimeType="application/xhtml+xml" />
+            <mimeMap fileExtension=".xla" mimeType="application/vnd.ms-excel" />
+            <mimeMap fileExtension=".xlam" mimeType="application/vnd.ms-excel.addin.macroEnabled.12" />
+            <mimeMap fileExtension=".xlc" mimeType="application/vnd.ms-excel" />
+            <mimeMap fileExtension=".xlm" mimeType="application/vnd.ms-excel" />
+            <mimeMap fileExtension=".xls" mimeType="application/vnd.ms-excel" />
+            <mimeMap fileExtension=".xlsb" mimeType="application/vnd.ms-excel.sheet.binary.macroEnabled.12" />
+            <mimeMap fileExtension=".xlsm" mimeType="application/vnd.ms-excel.sheet.macroEnabled.12" />
+            <mimeMap fileExtension=".xlsx" mimeType="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" />
+            <mimeMap fileExtension=".xlt" mimeType="application/vnd.ms-excel" />
+            <mimeMap fileExtension=".xltm" mimeType="application/vnd.ms-excel.template.macroEnabled.12" />
+            <mimeMap fileExtension=".xltx" mimeType="application/vnd.openxmlformats-officedocument.spreadsheetml.template" />
+            <mimeMap fileExtension=".xlw" mimeType="application/vnd.ms-excel" />
+            <mimeMap fileExtension=".xml" mimeType="text/xml" />
+            <mimeMap fileExtension=".xof" mimeType="x-world/x-vrml" />
+            <mimeMap fileExtension=".xpm" mimeType="image/x-xpixmap" />
+            <mimeMap fileExtension=".xps" mimeType="application/vnd.ms-xpsdocument" />
+            <mimeMap fileExtension=".xsd" mimeType="text/xml" />
+            <mimeMap fileExtension=".xsf" mimeType="text/xml" />
+            <mimeMap fileExtension=".xsl" mimeType="text/xml" />
+            <mimeMap fileExtension=".xslt" mimeType="text/xml" />
+            <mimeMap fileExtension=".xsn" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".xtp" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".xwd" mimeType="image/x-xwindowdump" />
+            <mimeMap fileExtension=".z" mimeType="application/x-compress" />
+            <mimeMap fileExtension=".zip" mimeType="application/x-zip-compressed" />
+        </staticContent>
+
+        <tracing>
+
+             <traceProviderDefinitions>
+                <add name="WWW Server" guid="{3a2a4e84-4c21-4981-ae10-3fda0d9b0f83}">
+                    <areas>
+                        <clear />
+                        <add name="Authentication" value="2" />
+                        <add name="Security" value="4" />
+                        <add name="Filter" value="8" />
+                        <add name="StaticFile" value="16" />
+                        <add name="CGI" value="32" />
+                        <add name="Compression" value="64" />
+                        <add name="Cache" value="128" />
+                        <add name="RequestNotifications" value="256" />
+                        <add name="Module" value="512" />
+                        <add name="Rewrite" value="1024" />
+                        <add name="FastCGI" value="4096" />
+                        <add name="WebSocket" value="16384" />
+                    </areas>
+                </add>
+                <add name="ASP" guid="{06b94d9a-b15e-456e-a4ef-37c984a2cb4b}">
+                    <areas>
+                        <clear />
+                    </areas>
+                </add>
+                <add name="ISAPI Extension" guid="{a1c2040e-8840-4c31-ba11-9871031a19ea}">
+                    <areas>
+                        <clear />
+                    </areas>
+                </add>
+                <add name="ASPNET" guid="{AFF081FE-0247-4275-9C4E-021F3DC1DA35}">
+                    <areas>
+                        <add name="Infrastructure" value="1" />
+                        <add name="Module" value="2" />
+                        <add name="Page" value="4" />
+                        <add name="AppServices" value="8" />
+                    </areas>
+                </add>
+            </traceProviderDefinitions>
+
+            <traceFailedRequests>
+                <add path="*">
+                    <traceAreas>
+                        <add provider="ASP" verbosity="Verbose" />
+                        <add provider="ASPNET" areas="Infrastructure,Module,Page,AppServices" verbosity="Verbose" />
+                        <add provider="ISAPI Extension" verbosity="Verbose" />
+                        <add provider="WWW Server" areas="Authentication,Security,Filter,StaticFile,CGI,Compression,Cache,RequestNotifications,Module,Rewrite,WebSocket" verbosity="Verbose" />
+                    </traceAreas>
+                    <failureDefinitions statusCodes="200-999" />
+                </add>
+            </traceFailedRequests>
+
+        </tracing>
+
+        <urlCompression />
+
+        <validation />
+        <webdav>
+            <globalSettings>
+                <propertyStores>
+                    <add name="webdav_simple_prop" image="%IIS_BIN%\webdav_simple_prop.dll" image32="%IIS_BIN%\webdav_simple_prop.dll" />
+                </propertyStores>
+                <lockStores>
+                    <add name="webdav_simple_lock" image="%IIS_BIN%\webdav_simple_lock.dll" image32="%IIS_BIN%\webdav_simple_lock.dll" />
+                </lockStores>
+
+            </globalSettings>
+            <authoring>
+                <locks enabled="true" lockStore="webdav_simple_lock" />
+            </authoring>
+            <authoringRules />
+        </webdav>
+        <applicationInitialization />
+        <webSocket />
+
+    </system.webServer>
+    <location path="" overrideMode="Allow">
+        <system.webServer>
+            <modules>
+              <add name="IsapiFilterModule" lockItem="true" />
+              <add name="BasicAuthenticationModule" lockItem="true" />
+              <add name="IsapiModule" lockItem="true" />
+              <add name="HttpLoggingModule" lockItem="true" />
+                <!--
+                <add name="HttpCacheModule" lockItem="true" />
+-->
+                <add name="DynamicCompressionModule" lockItem="true" />
+                <add name="StaticCompressionModule" lockItem="true" />
+                <add name="DefaultDocumentModule" lockItem="true" />
+                <add name="DirectoryListingModule" lockItem="true" />
+                <add name="ProtocolSupportModule" lockItem="true" />
+                <add name="HttpRedirectionModule" lockItem="true" />
+                <add name="ServerSideIncludeModule" lockItem="true" />
+                <add name="StaticFileModule" lockItem="true" />
+                <add name="AnonymousAuthenticationModule" lockItem="true" />
+                <add name="CertificateMappingAuthenticationModule" lockItem="true" />
+                <add name="UrlAuthorizationModule" lockItem="true" />
+                <add name="WindowsAuthenticationModule" lockItem="true" />
+                <!--
+                <add name="DigestAuthenticationModule" lockItem="true" />
+-->
+                <add name="IISCertificateMappingAuthenticationModule" lockItem="true" />
+                <add name="WebMatrixSupportModule" lockItem="true" />
+                <add name="IpRestrictionModule" lockItem="true" />
+                <add name="DynamicIpRestrictionModule" lockItem="true" />
+                <add name="RequestFilteringModule" lockItem="true" />
+                <add name="CustomLoggingModule" lockItem="true" />
+                <add name="CustomErrorModule" lockItem="true" />
+                <add name="FailedRequestsTracingModule" lockItem="true" />
+                <add name="CgiModule" lockItem="true" />
+                <add name="FastCgiModule" lockItem="true" />
+                <!--                <add name="WebDAVModule" /> -->
+                <add name="RewriteModule" />
+                <add name="OutputCache" type="System.Web.Caching.OutputCacheModule" preCondition="managedHandler" />
+                <add name="Session" type="System.Web.SessionState.SessionStateModule" preCondition="managedHandler" />
+                <add name="WindowsAuthentication" type="System.Web.Security.WindowsAuthenticationModule" preCondition="managedHandler" />
+                <add name="FormsAuthentication" type="System.Web.Security.FormsAuthenticationModule" preCondition="managedHandler" />
+                <add name="DefaultAuthentication" type="System.Web.Security.DefaultAuthenticationModule" preCondition="managedHandler" />
+                <add name="RoleManager" type="System.Web.Security.RoleManagerModule" preCondition="managedHandler" />
+                <add name="UrlAuthorization" type="System.Web.Security.UrlAuthorizationModule" preCondition="managedHandler" />
+                <add name="FileAuthorization" type="System.Web.Security.FileAuthorizationModule" preCondition="managedHandler" />
+                <add name="AnonymousIdentification" type="System.Web.Security.AnonymousIdentificationModule" preCondition="managedHandler" />
+                <add name="Profile" type="System.Web.Profile.ProfileModule" preCondition="managedHandler" />
+                <add name="UrlMappingsModule" type="System.Web.UrlMappingsModule" preCondition="managedHandler" />
+                <add name="ApplicationInitializationModule" lockItem="true" />
+                <add name="WebSocketModule" lockItem="true" />
+                <add name="ServiceModel-4.0" type="System.ServiceModel.Activation.ServiceHttpModule,System.ServiceModel.Activation,Version=4.0.0.0,Culture=neutral,PublicKeyToken=31bf3856ad364e35" preCondition="managedHandler,runtimeVersionv4.0" />
+                <add name="ConfigurationValidationModule" lockItem="true" />
+                <add name="UrlRoutingModule-4.0" type="System.Web.Routing.UrlRoutingModule" preCondition="managedHandler,runtimeVersionv4.0" />
+                <add name="ScriptModule-4.0" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" preCondition="managedHandler,runtimeVersionv4.0" />
+                <add name="ServiceModel" type="System.ServiceModel.Activation.HttpModule, System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" preCondition="managedHandler,runtimeVersionv2.0" />
+                <add name="AspNetCoreModule" />
+            </modules>
+            <handlers accessPolicy="Read, Script">
+                <!--                <add name="WebDAV" path="*" verb="PROPFIND,PROPPATCH,MKCOL,PUT,COPY,DELETE,MOVE,LOCK,UNLOCK" modules="WebDAVModule" resourceType="Unspecified" requireAccess="None" /> -->
+                <add name="AXD-ISAPI-4.0_64bit" path="*.axd" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
+                <add name="PageHandlerFactory-ISAPI-4.0_64bit" path="*.aspx" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
+                <add name="SimpleHandlerFactory-ISAPI-4.0_64bit" path="*.ashx" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
+                <add name="WebServiceHandlerFactory-ISAPI-4.0_64bit" path="*.asmx" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
+                <add name="HttpRemotingHandlerFactory-rem-ISAPI-4.0_64bit" path="*.rem" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
+                <add name="HttpRemotingHandlerFactory-soap-ISAPI-4.0_64bit" path="*.soap" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
+                <add name="svc-ISAPI-4.0_64bit" path="*.svc" verb="*" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" />
+                <add name="rules-ISAPI-4.0_64bit" path="*.rules" verb="*" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" />
+                <add name="xoml-ISAPI-4.0_64bit" path="*.xoml" verb="*" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" />
+                <add name="xamlx-ISAPI-4.0_64bit" path="*.xamlx" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" />
+                <add name="aspq-ISAPI-4.0_64bit" path="*.aspq" verb="*" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
+                <add name="cshtm-ISAPI-4.0_64bit" path="*.cshtm" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
+                <add name="cshtml-ISAPI-4.0_64bit" path="*.cshtml" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
+                <add name="vbhtm-ISAPI-4.0_64bit" path="*.vbhtm" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
+                <add name="vbhtml-ISAPI-4.0_64bit" path="*.vbhtml" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
+                <add name="svc-Integrated" path="*.svc" verb="*" type="System.ServiceModel.Activation.HttpHandler, System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" preCondition="integratedMode,runtimeVersionv2.0" />
+                <add name="svc-ISAPI-2.0" path="*.svc" verb="*" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness32" />
+                <add name="xoml-Integrated" path="*.xoml" verb="*" type="System.ServiceModel.Activation.HttpHandler, System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" preCondition="integratedMode,runtimeVersionv2.0" />
+                <add name="xoml-ISAPI-2.0" path="*.xoml" verb="*" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness32" />
+                <add name="rules-Integrated" path="*.rules" verb="*" type="System.ServiceModel.Activation.HttpHandler, System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" preCondition="integratedMode,runtimeVersionv2.0" />
+                <add name="rules-ISAPI-2.0" path="*.rules" verb="*" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness32" />
+                <add name="AXD-ISAPI-4.0_32bit" path="*.axd" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
+                <add name="PageHandlerFactory-ISAPI-4.0_32bit" path="*.aspx" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
+                <add name="SimpleHandlerFactory-ISAPI-4.0_32bit" path="*.ashx" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
+                <add name="WebServiceHandlerFactory-ISAPI-4.0_32bit" path="*.asmx" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
+                <add name="HttpRemotingHandlerFactory-rem-ISAPI-4.0_32bit" path="*.rem" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
+                <add name="HttpRemotingHandlerFactory-soap-ISAPI-4.0_32bit" path="*.soap" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
+                <add name="svc-ISAPI-4.0_32bit" path="*.svc" verb="*" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" />
+                <add name="rules-ISAPI-4.0_32bit" path="*.rules" verb="*" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" />
+                <add name="xoml-ISAPI-4.0_32bit" path="*.xoml" verb="*" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" />
+                <add name="xamlx-ISAPI-4.0_32bit" path="*.xamlx" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" />
+                <add name="aspq-ISAPI-4.0_32bit" path="*.aspq" verb="*" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
+                <add name="cshtm-ISAPI-4.0_32bit" path="*.cshtm" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
+                <add name="cshtml-ISAPI-4.0_32bit" path="*.cshtml" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
+                <add name="vbhtm-ISAPI-4.0_32bit" path="*.vbhtm" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
+                <add name="vbhtml-ISAPI-4.0_32bit" path="*.vbhtml" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
+                <add name="TraceHandler-Integrated-4.0" path="trace.axd" verb="GET,HEAD,POST,DEBUG" type="System.Web.Handlers.TraceHandler" preCondition="integratedMode,runtimeVersionv4.0" />
+                <add name="WebAdminHandler-Integrated-4.0" path="WebAdmin.axd" verb="GET,DEBUG" type="System.Web.Handlers.WebAdminHandler" preCondition="integratedMode,runtimeVersionv4.0" />
+                <add name="AssemblyResourceLoader-Integrated-4.0" path="WebResource.axd" verb="GET,DEBUG" type="System.Web.Handlers.AssemblyResourceLoader" preCondition="integratedMode,runtimeVersionv4.0" />
+                <add name="PageHandlerFactory-Integrated-4.0" path="*.aspx" verb="GET,HEAD,POST,DEBUG" type="System.Web.UI.PageHandlerFactory" preCondition="integratedMode,runtimeVersionv4.0" />
+                <add name="SimpleHandlerFactory-Integrated-4.0" path="*.ashx" verb="GET,HEAD,POST,DEBUG" type="System.Web.UI.SimpleHandlerFactory" preCondition="integratedMode,runtimeVersionv4.0" />
+                <add name="WebServiceHandlerFactory-Integrated-4.0" path="*.asmx" verb="GET,HEAD,POST,DEBUG" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" preCondition="integratedMode,runtimeVersionv4.0" />
+                <add name="HttpRemotingHandlerFactory-rem-Integrated-4.0" path="*.rem" verb="GET,HEAD,POST,DEBUG" type="System.Runtime.Remoting.Channels.Http.HttpRemotingHandlerFactory, System.Runtime.Remoting, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" preCondition="integratedMode,runtimeVersionv4.0" />
+                <add name="HttpRemotingHandlerFactory-soap-Integrated-4.0" path="*.soap" verb="GET,HEAD,POST,DEBUG" type="System.Runtime.Remoting.Channels.Http.HttpRemotingHandlerFactory, System.Runtime.Remoting, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" preCondition="integratedMode,runtimeVersionv4.0" />
+                <add name="svc-Integrated-4.0" path="*.svc" verb="*" type="System.ServiceModel.Activation.ServiceHttpHandlerFactory, System.ServiceModel.Activation, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" preCondition="integratedMode,runtimeVersionv4.0" />
+                <add name="rules-Integrated-4.0" path="*.rules" verb="*" type="System.ServiceModel.Activation.ServiceHttpHandlerFactory, System.ServiceModel.Activation, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" preCondition="integratedMode,runtimeVersionv4.0" />
+                <add name="xoml-Integrated-4.0" path="*.xoml" verb="*" type="System.ServiceModel.Activation.ServiceHttpHandlerFactory, System.ServiceModel.Activation, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" preCondition="integratedMode,runtimeVersionv4.0" />
+                <add name="xamlx-Integrated-4.0" path="*.xamlx" verb="GET,HEAD,POST,DEBUG" type="System.Xaml.Hosting.XamlHttpHandlerFactory, System.Xaml.Hosting, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" preCondition="integratedMode,runtimeVersionv4.0" />
+                <add name="aspq-Integrated-4.0" path="*.aspq" verb="GET,HEAD,POST,DEBUG" type="System.Web.HttpForbiddenHandler" preCondition="integratedMode,runtimeVersionv4.0" />
+                <add name="cshtm-Integrated-4.0" path="*.cshtm" verb="GET,HEAD,POST,DEBUG" type="System.Web.HttpForbiddenHandler" preCondition="integratedMode,runtimeVersionv4.0" />
+                <add name="cshtml-Integrated-4.0" path="*.cshtml" verb="GET,HEAD,POST,DEBUG" type="System.Web.HttpForbiddenHandler" preCondition="integratedMode,runtimeVersionv4.0" />
+                <add name="vbhtm-Integrated-4.0" path="*.vbhtm" verb="GET,HEAD,POST,DEBUG" type="System.Web.HttpForbiddenHandler" preCondition="integratedMode,runtimeVersionv4.0" />
+                <add name="vbhtml-Integrated-4.0" path="*.vbhtml" verb="GET,HEAD,POST,DEBUG" type="System.Web.HttpForbiddenHandler" preCondition="integratedMode,runtimeVersionv4.0" />
+                <add name="ScriptHandlerFactoryAppServices-Integrated-4.0" path="*_AppService.axd" verb="*" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" preCondition="integratedMode,runtimeVersionv4.0" />
+                <add name="ScriptResourceIntegrated-4.0" path="*ScriptResource.axd" verb="GET,HEAD" type="System.Web.Handlers.ScriptResourceHandler, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" preCondition="integratedMode,runtimeVersionv4.0" />
+                <add name="ASPClassic" path="*.asp" verb="GET,HEAD,POST" modules="IsapiModule" scriptProcessor="%IIS_BIN%\asp.dll" resourceType="File" />
+                <add name="SecurityCertificate" path="*.cer" verb="GET,HEAD,POST" modules="IsapiModule" scriptProcessor="%IIS_BIN%\asp.dll" resourceType="File" />
+                <add name="ISAPI-dll" path="*.dll" verb="*" modules="IsapiModule" resourceType="File" requireAccess="Execute" allowPathInfo="true" />
+                <add name="TraceHandler-Integrated" path="trace.axd" verb="GET,HEAD,POST,DEBUG" type="System.Web.Handlers.TraceHandler" preCondition="integratedMode,runtimeVersionv2.0" />
+                <add name="WebAdminHandler-Integrated" path="WebAdmin.axd" verb="GET,DEBUG" type="System.Web.Handlers.WebAdminHandler" preCondition="integratedMode,runtimeVersionv2.0" />
+                <add name="AssemblyResourceLoader-Integrated" path="WebResource.axd" verb="GET,DEBUG" type="System.Web.Handlers.AssemblyResourceLoader" preCondition="integratedMode,runtimeVersionv2.0" />
+                <add name="PageHandlerFactory-Integrated" path="*.aspx" verb="GET,HEAD,POST,DEBUG" type="System.Web.UI.PageHandlerFactory" preCondition="integratedMode,runtimeVersionv2.0" />
+                <add name="SimpleHandlerFactory-Integrated" path="*.ashx" verb="GET,HEAD,POST,DEBUG" type="System.Web.UI.SimpleHandlerFactory" preCondition="integratedMode,runtimeVersionv2.0" />
+                <add name="WebServiceHandlerFactory-Integrated" path="*.asmx" verb="GET,HEAD,POST,DEBUG" type="System.Web.Services.Protocols.WebServiceHandlerFactory,System.Web.Services,Version=2.0.0.0,Culture=neutral,PublicKeyToken=b03f5f7f11d50a3a" preCondition="integratedMode,runtimeVersionv2.0" />
+                <add name="HttpRemotingHandlerFactory-rem-Integrated" path="*.rem" verb="GET,HEAD,POST,DEBUG" type="System.Runtime.Remoting.Channels.Http.HttpRemotingHandlerFactory,System.Runtime.Remoting,Version=2.0.0.0,Culture=neutral,PublicKeyToken=b77a5c561934e089" preCondition="integratedMode,runtimeVersionv2.0" />
+                <add name="HttpRemotingHandlerFactory-soap-Integrated" path="*.soap" verb="GET,HEAD,POST,DEBUG" type="System.Runtime.Remoting.Channels.Http.HttpRemotingHandlerFactory,System.Runtime.Remoting,Version=2.0.0.0,Culture=neutral,PublicKeyToken=b77a5c561934e089" preCondition="integratedMode,runtimeVersionv2.0" />
+                <add name="AXD-ISAPI-2.0" path="*.axd" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness32" responseBufferLimit="0" />
+                <add name="PageHandlerFactory-ISAPI-2.0" path="*.aspx" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness32" responseBufferLimit="0" />
+                <add name="SimpleHandlerFactory-ISAPI-2.0" path="*.ashx" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness32" responseBufferLimit="0" />
+                <add name="WebServiceHandlerFactory-ISAPI-2.0" path="*.asmx" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness32" responseBufferLimit="0" />
+                <add name="HttpRemotingHandlerFactory-rem-ISAPI-2.0" path="*.rem" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness32" responseBufferLimit="0" />
+                <add name="HttpRemotingHandlerFactory-soap-ISAPI-2.0" path="*.soap" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness32" responseBufferLimit="0" />
+                <add name="svc-ISAPI-2.0-64" path="*.svc" verb="*" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness64" />
+                <add name="AXD-ISAPI-2.0-64" path="*.axd" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness64" responseBufferLimit="0" />
+                <add name="PageHandlerFactory-ISAPI-2.0-64" path="*.aspx" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness64" responseBufferLimit="0" />
+                <add name="SimpleHandlerFactory-ISAPI-2.0-64" path="*.ashx" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness64" responseBufferLimit="0" />
+                <add name="WebServiceHandlerFactory-ISAPI-2.0-64" path="*.asmx" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness64" responseBufferLimit="0" />
+                <add name="HttpRemotingHandlerFactory-rem-ISAPI-2.0-64" path="*.rem" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness64" responseBufferLimit="0" />
+                <add name="HttpRemotingHandlerFactory-soap-ISAPI-2.0-64" path="*.soap" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness64" responseBufferLimit="0" />
+                <add name="rules-64-ISAPI-2.0" path="*.rules" verb="*" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness64" />
+                <add name="xoml-64-ISAPI-2.0" path="*.xoml" verb="*" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness64" />
+                <add name="CGI-exe" path="*.exe" verb="*" modules="CgiModule" resourceType="File" requireAccess="Execute" allowPathInfo="true" />
+                <add name="SSINC-stm" path="*.stm" verb="GET,HEAD,POST" modules="ServerSideIncludeModule" resourceType="File" />
+                <add name="SSINC-shtm" path="*.shtm" verb="GET,HEAD,POST" modules="ServerSideIncludeModule" resourceType="File" />
+                <add name="SSINC-shtml" path="*.shtml" verb="GET,HEAD,POST" modules="ServerSideIncludeModule" resourceType="File" />
+                <add name="TRACEVerbHandler" path="*" verb="TRACE" modules="ProtocolSupportModule" requireAccess="None" />
+                <add name="OPTIONSVerbHandler" path="*" verb="OPTIONS" modules="ProtocolSupportModule" requireAccess="None" />
+                <add name="ExtensionlessUrl-ISAPI-4.0_32bit" path="*." verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
+                <add name="ExtensionlessUrlHandler-ISAPI-4.0_64bit" path="*." verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
+                <add name="ExtensionlessUrl-Integrated-4.0" path="*." verb="GET,HEAD,POST,DEBUG" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" responseBufferLimit="0" />
+                <add name="StaticFile" path="*" verb="*" modules="StaticFileModule,DefaultDocumentModule,DirectoryListingModule" resourceType="Either" requireAccess="Read" />
+            </handlers>
+        </system.webServer>
+    </location>
+</configuration>
diff --git a/src/IISIntegration/test/IISIntegration.FunctionalTests/AppHostConfig/NtlmAuthentation.config b/src/IISIntegration/test/IISIntegration.FunctionalTests/AppHostConfig/NtlmAuthentation.config
new file mode 100644
index 0000000000000000000000000000000000000000..d74f6b2e4fa595822ba93c734b47fd16fa0ccc53
--- /dev/null
+++ b/src/IISIntegration/test/IISIntegration.FunctionalTests/AppHostConfig/NtlmAuthentation.config
@@ -0,0 +1,1040 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    IIS configuration sections.
+
+    For schema documentation, see
+    %IIS_BIN%\config\schema\IIS_schema.xml.
+    
+    Please make a backup of this file before making any changes to it.
+
+    NOTE: The following environment variables are available to be used
+          within this file and are understood by the IIS Express.
+
+          %IIS_USER_HOME% - The IIS Express home directory for the user
+          %IIS_SITES_HOME% - The default home directory for sites
+          %IIS_BIN% - The location of the IIS Express binaries
+          %SYSTEMDRIVE% - The drive letter of %IIS_BIN%
+
+-->
+
+<configuration>
+
+    <!--
+
+        The <configSections> section controls the registration of sections.
+        Section is the basic unit of deployment, locking, searching and
+        containment for configuration settings.
+        
+        Every section belongs to one section group.
+        A section group is a container of logically-related sections.
+        
+        Sections cannot be nested.
+        Section groups may be nested.
+        
+        <section
+            name=""  [Required, Collection Key] [XML name of the section]
+            allowDefinition="Everywhere" [MachineOnly|MachineToApplication|AppHostOnly|Everywhere] [Level where it can be set]
+            overrideModeDefault="Allow"  [Allow|Deny] [Default delegation mode]
+            allowLocation="true"  [true|false] [Allowed in location tags]
+        />
+        
+        The recommended way to unlock sections is by using a location tag:
+        <location path="Default Web Site" overrideMode="Allow">
+            <system.webServer>
+                <asp />
+            </system.webServer>
+        </location>
+
+    -->
+    <configSections>
+        <sectionGroup name="system.applicationHost">
+            <section name="applicationPools" allowDefinition="AppHostOnly" overrideModeDefault="Deny" />
+            <section name="configHistory" allowDefinition="AppHostOnly" overrideModeDefault="Deny" />
+            <section name="customMetadata" allowDefinition="AppHostOnly" overrideModeDefault="Deny" />
+            <section name="listenerAdapters" allowDefinition="AppHostOnly" overrideModeDefault="Deny" />
+            <section name="log" allowDefinition="AppHostOnly" overrideModeDefault="Deny" />
+            <section name="preloadProviders" allowDefinition="AppHostOnly" overrideModeDefault="Deny" />
+            <section name="sites" allowDefinition="AppHostOnly" overrideModeDefault="Deny" />
+            <section name="webLimits" allowDefinition="AppHostOnly" overrideModeDefault="Deny" />
+        </sectionGroup>
+
+        <sectionGroup name="system.webServer">
+            <section name="asp" overrideModeDefault="Deny" />
+            <section name="caching" overrideModeDefault="Allow" />
+            <section name="cgi" overrideModeDefault="Deny" />
+            <section name="defaultDocument" overrideModeDefault="Allow" />
+            <section name="directoryBrowse" overrideModeDefault="Allow" />
+            <section name="fastCgi" allowDefinition="AppHostOnly" overrideModeDefault="Deny" />
+            <section name="globalModules" allowDefinition="AppHostOnly" overrideModeDefault="Deny" />
+            <section name="handlers" overrideModeDefault="Deny" />
+            <section name="httpCompression" allowDefinition="AppHostOnly" overrideModeDefault="Deny" />
+            <section name="httpErrors" overrideModeDefault="Allow" />
+            <section name="httpLogging" overrideModeDefault="Deny" />
+            <section name="httpProtocol" overrideModeDefault="Allow" />
+            <section name="httpRedirect" overrideModeDefault="Allow" />
+            <section name="httpTracing" overrideModeDefault="Deny" />
+            <section name="isapiFilters" allowDefinition="MachineToApplication" overrideModeDefault="Deny" />
+            <section name="modules" allowDefinition="MachineToApplication" overrideModeDefault="Deny" />
+            <section name="odbcLogging" overrideModeDefault="Deny" />
+            <sectionGroup name="security">
+                <section name="access" overrideModeDefault="Deny" />
+                <section name="applicationDependencies" overrideModeDefault="Deny" />
+                <sectionGroup name="authentication">
+                    <section name="anonymousAuthentication" overrideModeDefault="Deny" />
+                    <section name="basicAuthentication" overrideModeDefault="Deny" />
+                    <section name="clientCertificateMappingAuthentication" overrideModeDefault="Deny" />
+                    <section name="digestAuthentication" overrideModeDefault="Deny" />
+                    <section name="iisClientCertificateMappingAuthentication" overrideModeDefault="Deny" />
+                    <section name="windowsAuthentication" overrideModeDefault="Deny" />
+                </sectionGroup>
+                <section name="authorization" overrideModeDefault="Allow" />
+                <section name="ipSecurity" overrideModeDefault="Deny" />
+                <section name="dynamicIpSecurity" overrideModeDefault="Deny" />
+                <section name="isapiCgiRestriction" allowDefinition="AppHostOnly" overrideModeDefault="Deny" />
+                <section name="requestFiltering" overrideModeDefault="Allow" />
+            </sectionGroup>
+            <section name="serverRuntime" overrideModeDefault="Deny" />
+            <section name="serverSideInclude" overrideModeDefault="Deny" />
+            <section name="staticContent" overrideModeDefault="Allow" />
+            <sectionGroup name="tracing">
+                <section name="traceFailedRequests" overrideModeDefault="Allow" />
+                <section name="traceProviderDefinitions" overrideModeDefault="Deny" />
+            </sectionGroup>
+            <section name="urlCompression" overrideModeDefault="Allow" />
+            <section name="validation" overrideModeDefault="Allow" />
+            <sectionGroup name="webdav">
+                <section name="globalSettings" overrideModeDefault="Deny" />
+                <section name="authoring" overrideModeDefault="Deny" />
+                <section name="authoringRules" overrideModeDefault="Deny" />
+            </sectionGroup>
+            <sectionGroup name="rewrite">
+                <section name="allowedServerVariables" overrideModeDefault="Deny" />
+                <section name="rules" overrideModeDefault="Allow" />
+                <section name="outboundRules" overrideModeDefault="Allow" />
+                <section name="globalRules" overrideModeDefault="Deny" allowDefinition="AppHostOnly" />
+                <section name="providers" overrideModeDefault="Allow" />
+                <section name="rewriteMaps" overrideModeDefault="Allow" />
+            </sectionGroup>
+            <section name="applicationInitialization" allowDefinition="MachineToApplication" overrideModeDefault="Allow" />
+            <section name="webSocket" overrideModeDefault="Deny" />
+            <section name="aspNetCore" overrideModeDefault="Allow" />
+        </sectionGroup>
+    </configSections>
+
+    <configProtectedData>
+        <providers>
+            <add name="IISWASOnlyRsaProvider" type="" description="Uses RsaCryptoServiceProvider to encrypt and decrypt" keyContainerName="iisWasKey" cspProviderName="" useMachineContainer="true" useOAEP="false" />
+            <add name="AesProvider" type="Microsoft.ApplicationHost.AesProtectedConfigurationProvider" description="Uses an AES session key to encrypt and decrypt" keyContainerName="iisConfigurationKey" cspProviderName="" useOAEP="false" useMachineContainer="true" sessionKey="AQIAAA5mAAAApAAAKmFQvWHDEETRz8l2bjZlRxIkwcqTFaCUnCLljn3Q1OkesrhEO9YyLyx4bUhsj1/DyShAv7OAFFhXlrlomaornnk5PLeyO4lIXxaiT33yOFUUgxDx4GSaygkqghVV0tO5yQ/XguUBp2juMfZyztnsNa4pLcz7ZNZQ6p4yn9hxwNs=" />
+            <add name="IISWASOnlyAesProvider" type="Microsoft.ApplicationHost.AesProtectedConfigurationProvider" description="Uses an AES session key to encrypt and decrypt" keyContainerName="iisWasKey" cspProviderName="" useOAEP="false" useMachineContainer="true" sessionKey="AQIAAA5mAAAApAAA4WoiRJ8KHwzAG8AgejPxEOO4/2Vhkolbwo/8gZeNdUDSD36m55hWv4uC9tr/MlKdnwRLL0NhT50Gccyftqz5xTZ0dg5FtvQhTw/he1NwexTKbV+I4Zrd+sZUqHZTsr7JiEr6OHGXL70qoISW5G2m9U8wKT3caPiDPNj2aAaYPLo=" />
+        </providers>
+    </configProtectedData>
+
+    <system.applicationHost>
+
+        <applicationPools>
+            <add name="Clr4IntegratedAppPool" managedRuntimeVersion="v4.0" managedPipelineMode="Integrated" CLRConfigFile="%IIS_BIN%\config\templates\PersonalWebServer\aspnet.config" autoStart="true" />
+            <add name="Clr4ClassicAppPool" managedRuntimeVersion="v4.0" managedPipelineMode="Classic" CLRConfigFile="%IIS_BIN%\config\templates\PersonalWebServer\aspnet.config" autoStart="true" />
+            <add name="Clr2IntegratedAppPool" managedRuntimeVersion="v2.0" managedPipelineMode="Integrated" CLRConfigFile="%IIS_BIN%\config\templates\PersonalWebServer\aspnet.config" autoStart="true" />
+            <add name="Clr2ClassicAppPool" managedRuntimeVersion="v2.0" managedPipelineMode="Classic" CLRConfigFile="%IIS_BIN%\config\templates\PersonalWebServer\aspnet.config" autoStart="true" />
+            <add name="UnmanagedClassicAppPool" managedRuntimeVersion="" managedPipelineMode="Classic" autoStart="true" />
+            <add name="IISExpressAppPool" managedRuntimeVersion="v4.0" managedPipelineMode="Integrated" CLRConfigFile="%IIS_BIN%\config\templates\PersonalWebServer\aspnet.config" autoStart="true" />
+            <applicationPoolDefaults managedRuntimeLoader="v4.0">
+                <processModel />
+            </applicationPoolDefaults>
+        </applicationPools>
+
+        <!--
+
+          The <listenerAdapters> section defines the protocols with which the
+          Windows Process Activation Service (WAS) binds.
+
+        -->
+        <listenerAdapters>
+            <add name="http" />
+        </listenerAdapters>
+
+        <sites>
+            <site name="NtlmAuthenticationTestSite" id="1" serverAutoStart="true">
+                <application path="/">
+                    <virtualDirectory path="/" physicalPath="[ApplicationPhysicalPath]" />
+                </application>
+                <bindings>
+                    <binding protocol="http" bindingInformation=":[PORT]:localhost" />
+                </bindings>
+            </site>
+            <siteDefaults>
+                <logFile logFormat="W3C" directory="%IIS_USER_HOME%\Logs" />
+                <traceFailedRequestsLogging directory="%IIS_USER_HOME%\TraceLogFiles" enabled="true" maxLogFileSizeKB="1024" />
+            </siteDefaults>
+            <applicationDefaults applicationPool="IISExpressAppPool" />
+            <virtualDirectoryDefaults allowSubDirConfig="true" />
+        </sites>
+
+        <webLimits />
+
+    </system.applicationHost>
+
+    <system.webServer>
+
+        <serverRuntime />
+
+        <asp scriptErrorSentToBrowser="true">
+            <cache diskTemplateCacheDirectory="%TEMP%\iisexpress\ASP Compiled Templates" />
+            <limits />
+        </asp>
+
+        <caching enabled="true" enableKernelCache="true">
+        </caching>
+
+        <cgi />
+
+        <defaultDocument enabled="true">
+            <files>
+                <add value="Default.htm" />
+                <add value="Default.asp" />
+                <add value="index.htm" />
+                <add value="index.html" />
+                <add value="iisstart.htm" />
+                <add value="default.aspx" />
+            </files>
+        </defaultDocument>
+
+        <directoryBrowse enabled="false" />
+
+        <fastCgi />
+
+        <!--
+
+          The <globalModules> section defines all native-code modules.
+          To enable a module, specify it in the <modules> section.
+
+        -->
+        <globalModules>
+            <add name="UriCacheModule" image="%IIS_BIN%\cachuri.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="DynamicCompressionModule" image="%IIS_BIN%\compdyn.dll" />
+            <add name="StaticCompressionModule" image="%IIS_BIN%\compstat.dll" />
+            <add name="DefaultDocumentModule" image="%IIS_BIN%\defdoc.dll" />
+            <add name="DirectoryListingModule" image="%IIS_BIN%\dirlist.dll" />
+            <add name="ProtocolSupportModule" image="%IIS_BIN%\protsup.dll" />
+            <add name="HttpRedirectionModule" image="%IIS_BIN%\redirect.dll" />
+            <add name="ServerSideIncludeModule" image="%IIS_BIN%\iis_ssi.dll" />
+            <add name="StaticFileModule" image="%IIS_BIN%\static.dll" />
+            <add name="AnonymousAuthenticationModule" image="%IIS_BIN%\authanon.dll" />
+            <add name="CertificateMappingAuthenticationModule" image="%IIS_BIN%\authcert.dll" />
+            <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="IISCertificateMappingAuthenticationModule" image="%IIS_BIN%\authmap.dll" />
+            <add name="IpRestrictionModule" image="%IIS_BIN%\iprestr.dll" />
+            <add name="DynamicIpRestrictionModule" image="%IIS_BIN%\diprestr.dll" />
+            <add name="RequestFilteringModule" image="%IIS_BIN%\modrqflt.dll" />
+            <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="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="RewriteModule" image="%IIS_BIN%\rewrite.dll" />
+            <add name="ConfigurationValidationModule" image="%IIS_BIN%\validcfg.dll" />
+            <add name="ApplicationInitializationModule" image="%IIS_BIN%\warmup.dll" />
+            <add name="WebSocketModule" image="%IIS_BIN%\iiswsock.dll" />
+            <add name="WebMatrixSupportModule" image="%IIS_BIN%\webmatrixsup.dll" />
+            <add name="ManagedEngine" image="%windir%\Microsoft.NET\Framework\v2.0.50727\webengine.dll" preCondition="integratedMode,runtimeVersionv2.0,bitness32" />
+            <add name="ManagedEngine64" image="%windir%\Microsoft.NET\Framework64\v2.0.50727\webengine.dll" preCondition="integratedMode,runtimeVersionv2.0,bitness64" />
+            <add name="ManagedEngineV4.0_32bit" image="%windir%\Microsoft.NET\Framework\v4.0.30319\webengine4.dll" preCondition="integratedMode,runtimeVersionv4.0,bitness32" />
+            <add name="ManagedEngineV4.0_64bit" image="%windir%\Microsoft.NET\Framework64\v4.0.30319\webengine4.dll" preCondition="integratedMode,runtimeVersionv4.0,bitness64" />
+            <add name="AspNetCoreModule" image="[ANCMPath]" />
+        </globalModules>
+
+        <httpCompression directory="%TEMP%\iisexpress\IIS Temporary Compressed Files">
+            <scheme name="gzip" dll="%IIS_BIN%\gzip.dll" />
+            <dynamicTypes>
+                <add mimeType="text/*" enabled="true" />
+                <add mimeType="message/*" enabled="true" />
+                <add mimeType="application/x-javascript" enabled="true" />
+                <add mimeType="*/*" enabled="false" />
+            </dynamicTypes>
+            <staticTypes>
+                <add mimeType="text/*" enabled="true" />
+                <add mimeType="message/*" enabled="true" />
+                <add mimeType="application/x-javascript" enabled="true" />
+                <add mimeType="application/atom+xml" enabled="true" />
+                <add mimeType="application/xaml+xml" enabled="true" />
+                <add mimeType="*/*" enabled="false" />
+            </staticTypes>
+        </httpCompression>
+
+        <httpErrors lockAttributes="allowAbsolutePathsWhenDelegated,defaultPath">
+            <error statusCode="401" prefixLanguageFilePath="%IIS_BIN%\custerr" path="401.htm" />
+            <error statusCode="403" prefixLanguageFilePath="%IIS_BIN%\custerr" path="403.htm" />
+            <error statusCode="404" prefixLanguageFilePath="%IIS_BIN%\custerr" path="404.htm" />
+            <error statusCode="405" prefixLanguageFilePath="%IIS_BIN%\custerr" path="405.htm" />
+            <error statusCode="406" prefixLanguageFilePath="%IIS_BIN%\custerr" path="406.htm" />
+            <error statusCode="412" prefixLanguageFilePath="%IIS_BIN%\custerr" path="412.htm" />
+            <error statusCode="500" prefixLanguageFilePath="%IIS_BIN%\custerr" path="500.htm" />
+            <error statusCode="501" prefixLanguageFilePath="%IIS_BIN%\custerr" path="501.htm" />
+            <error statusCode="502" prefixLanguageFilePath="%IIS_BIN%\custerr" path="502.htm" />
+        </httpErrors>
+
+        <httpLogging dontLog="false" />
+
+        <httpProtocol>
+            <customHeaders>
+                <clear />
+                <add name="X-Powered-By" value="ASP.NET" />
+            </customHeaders>
+            <redirectHeaders>
+                <clear />
+            </redirectHeaders>
+        </httpProtocol>
+
+        <httpRedirect enabled="false" />
+
+        <httpTracing>
+        </httpTracing>
+
+        <isapiFilters>
+            <filter name="ASP.Net_2.0.50727-64" path="%windir%\Microsoft.NET\Framework64\v2.0.50727\aspnet_filter.dll" enableCache="true" preCondition="bitness64,runtimeVersionv2.0" />
+            <filter name="ASP.Net_2.0.50727.0" path="%windir%\Microsoft.NET\Framework\v2.0.50727\aspnet_filter.dll" enableCache="true" preCondition="bitness32,runtimeVersionv2.0" />
+            <filter name="ASP.Net_2.0_for_v1.1" path="%windir%\Microsoft.NET\Framework\v2.0.50727\aspnet_filter.dll" enableCache="true" preCondition="runtimeVersionv1.1" />
+            <filter name="ASP.Net_4.0_32bit" path="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_filter.dll" enableCache="true" preCondition="bitness32,runtimeVersionv4.0" />
+            <filter name="ASP.Net_4.0_64bit" path="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_filter.dll" enableCache="true" preCondition="bitness64,runtimeVersionv4.0" />
+        </isapiFilters>
+
+        <odbcLogging />
+
+        <security>
+
+            <access sslFlags="None" />
+
+            <applicationDependencies>
+                <application name="Active Server Pages" groupId="ASP" />
+            </applicationDependencies>
+
+            <authentication>
+
+                <anonymousAuthentication enabled="true" userName="" />
+
+                <basicAuthentication enabled="false" />
+
+                <clientCertificateMappingAuthentication enabled="false" />
+
+                <digestAuthentication enabled="false" />
+
+                <iisClientCertificateMappingAuthentication enabled="false">
+                </iisClientCertificateMappingAuthentication>
+
+                <windowsAuthentication enabled="false">
+                    <providers>
+                        <add value="Negotiate" />
+                        <add value="NTLM" />
+                    </providers>
+                </windowsAuthentication>
+
+            </authentication>
+
+            <authorization>
+                <add accessType="Allow" users="*" />
+            </authorization>
+
+            <ipSecurity allowUnlisted="true" />
+
+            <isapiCgiRestriction notListedIsapisAllowed="true" notListedCgisAllowed="true">
+                <add path="%windir%\Microsoft.NET\Framework64\v4.0.30319\webengine4.dll" allowed="true" groupId="ASP.NET_v4.0" description="ASP.NET_v4.0" />
+                <add path="%windir%\Microsoft.NET\Framework\v4.0.30319\webengine4.dll" allowed="true" groupId="ASP.NET_v4.0" description="ASP.NET_v4.0" />
+                <add path="%windir%\Microsoft.NET\Framework64\v2.0.50727\aspnet_isapi.dll" allowed="true" groupId="ASP.NET v2.0.50727" description="ASP.NET v2.0.50727" />
+                <add path="%windir%\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll" allowed="true" groupId="ASP.NET v2.0.50727" description="ASP.NET v2.0.50727" />
+            </isapiCgiRestriction>
+
+            <requestFiltering>
+                <fileExtensions allowUnlisted="true" applyToWebDAV="true">
+                    <add fileExtension=".asa" allowed="false" />
+                    <add fileExtension=".asax" allowed="false" />
+                    <add fileExtension=".ascx" allowed="false" />
+                    <add fileExtension=".master" allowed="false" />
+                    <add fileExtension=".skin" allowed="false" />
+                    <add fileExtension=".browser" allowed="false" />
+                    <add fileExtension=".sitemap" allowed="false" />
+                    <add fileExtension=".config" allowed="false" />
+                    <add fileExtension=".cs" allowed="false" />
+                    <add fileExtension=".csproj" allowed="false" />
+                    <add fileExtension=".vb" allowed="false" />
+                    <add fileExtension=".vbproj" allowed="false" />
+                    <add fileExtension=".webinfo" allowed="false" />
+                    <add fileExtension=".licx" allowed="false" />
+                    <add fileExtension=".resx" allowed="false" />
+                    <add fileExtension=".resources" allowed="false" />
+                    <add fileExtension=".mdb" allowed="false" />
+                    <add fileExtension=".vjsproj" allowed="false" />
+                    <add fileExtension=".java" allowed="false" />
+                    <add fileExtension=".jsl" allowed="false" />
+                    <add fileExtension=".ldb" allowed="false" />
+                    <add fileExtension=".dsdgm" allowed="false" />
+                    <add fileExtension=".ssdgm" allowed="false" />
+                    <add fileExtension=".lsad" allowed="false" />
+                    <add fileExtension=".ssmap" allowed="false" />
+                    <add fileExtension=".cd" allowed="false" />
+                    <add fileExtension=".dsprototype" allowed="false" />
+                    <add fileExtension=".lsaprototype" allowed="false" />
+                    <add fileExtension=".sdm" allowed="false" />
+                    <add fileExtension=".sdmDocument" allowed="false" />
+                    <add fileExtension=".mdf" allowed="false" />
+                    <add fileExtension=".ldf" allowed="false" />
+                    <add fileExtension=".ad" allowed="false" />
+                    <add fileExtension=".dd" allowed="false" />
+                    <add fileExtension=".ldd" allowed="false" />
+                    <add fileExtension=".sd" allowed="false" />
+                    <add fileExtension=".adprototype" allowed="false" />
+                    <add fileExtension=".lddprototype" allowed="false" />
+                    <add fileExtension=".exclude" allowed="false" />
+                    <add fileExtension=".refresh" allowed="false" />
+                    <add fileExtension=".compiled" allowed="false" />
+                    <add fileExtension=".msgx" allowed="false" />
+                    <add fileExtension=".vsdisco" allowed="false" />
+                    <add fileExtension=".rules" allowed="false" />
+                </fileExtensions>
+                <verbs allowUnlisted="true" applyToWebDAV="true" />
+                <hiddenSegments applyToWebDAV="true">
+                    <add segment="web.config" />
+                    <add segment="bin" />
+                    <add segment="App_code" />
+                    <add segment="App_GlobalResources" />
+                    <add segment="App_LocalResources" />
+                    <add segment="App_WebReferences" />
+                    <add segment="App_Data" />
+                    <add segment="App_Browsers" />
+                </hiddenSegments>
+            </requestFiltering>
+
+        </security>
+
+        <serverSideInclude ssiExecDisable="false" />
+
+        <staticContent lockAttributes="isDocFooterFileName">
+            <mimeMap fileExtension=".323" mimeType="text/h323" />
+            <mimeMap fileExtension=".3g2" mimeType="video/3gpp2" />
+            <mimeMap fileExtension=".3gp2" mimeType="video/3gpp2" />
+            <mimeMap fileExtension=".3gp" mimeType="video/3gpp" />
+            <mimeMap fileExtension=".3gpp" mimeType="video/3gpp" />
+            <mimeMap fileExtension=".aac" mimeType="audio/aac" />
+            <mimeMap fileExtension=".aaf" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".aca" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".accdb" mimeType="application/msaccess" />
+            <mimeMap fileExtension=".accde" mimeType="application/msaccess" />
+            <mimeMap fileExtension=".accdt" mimeType="application/msaccess" />
+            <mimeMap fileExtension=".acx" mimeType="application/internet-property-stream" />
+            <mimeMap fileExtension=".adt" mimeType="audio/vnd.dlna.adts" />
+            <mimeMap fileExtension=".adts" mimeType="audio/vnd.dlna.adts" />
+            <mimeMap fileExtension=".afm" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".ai" mimeType="application/postscript" />
+            <mimeMap fileExtension=".aif" mimeType="audio/x-aiff" />
+            <mimeMap fileExtension=".aifc" mimeType="audio/aiff" />
+            <mimeMap fileExtension=".aiff" mimeType="audio/aiff" />
+            <mimeMap fileExtension=".application" mimeType="application/x-ms-application" />
+            <mimeMap fileExtension=".art" mimeType="image/x-jg" />
+            <mimeMap fileExtension=".asd" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".asf" mimeType="video/x-ms-asf" />
+            <mimeMap fileExtension=".asi" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".asm" mimeType="text/plain" />
+            <mimeMap fileExtension=".asr" mimeType="video/x-ms-asf" />
+            <mimeMap fileExtension=".asx" mimeType="video/x-ms-asf" />
+            <mimeMap fileExtension=".atom" mimeType="application/atom+xml" />
+            <mimeMap fileExtension=".au" mimeType="audio/basic" />
+            <mimeMap fileExtension=".avi" mimeType="video/x-msvideo" />
+            <mimeMap fileExtension=".axs" mimeType="application/olescript" />
+            <mimeMap fileExtension=".bas" mimeType="text/plain" />
+            <mimeMap fileExtension=".bcpio" mimeType="application/x-bcpio" />
+            <mimeMap fileExtension=".bin" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".bmp" mimeType="image/bmp" />
+            <mimeMap fileExtension=".c" mimeType="text/plain" />
+            <mimeMap fileExtension=".cab" mimeType="application/vnd.ms-cab-compressed" />
+            <mimeMap fileExtension=".calx" mimeType="application/vnd.ms-office.calx" />
+            <mimeMap fileExtension=".cat" mimeType="application/vnd.ms-pki.seccat" />
+            <mimeMap fileExtension=".cdf" mimeType="application/x-cdf" />
+            <mimeMap fileExtension=".chm" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".class" mimeType="application/x-java-applet" />
+            <mimeMap fileExtension=".clp" mimeType="application/x-msclip" />
+            <mimeMap fileExtension=".cmx" mimeType="image/x-cmx" />
+            <mimeMap fileExtension=".cnf" mimeType="text/plain" />
+            <mimeMap fileExtension=".cod" mimeType="image/cis-cod" />
+            <mimeMap fileExtension=".cpio" mimeType="application/x-cpio" />
+            <mimeMap fileExtension=".cpp" mimeType="text/plain" />
+            <mimeMap fileExtension=".crd" mimeType="application/x-mscardfile" />
+            <mimeMap fileExtension=".crl" mimeType="application/pkix-crl" />
+            <mimeMap fileExtension=".crt" mimeType="application/x-x509-ca-cert" />
+            <mimeMap fileExtension=".csh" mimeType="application/x-csh" />
+            <mimeMap fileExtension=".css" mimeType="text/css" />
+            <mimeMap fileExtension=".csv" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".cur" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".dcr" mimeType="application/x-director" />
+            <mimeMap fileExtension=".deploy" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".der" mimeType="application/x-x509-ca-cert" />
+            <mimeMap fileExtension=".dib" mimeType="image/bmp" />
+            <mimeMap fileExtension=".dir" mimeType="application/x-director" />
+            <mimeMap fileExtension=".disco" mimeType="text/xml" />
+            <mimeMap fileExtension=".dll" mimeType="application/x-msdownload" />
+            <mimeMap fileExtension=".dll.config" mimeType="text/xml" />
+            <mimeMap fileExtension=".dlm" mimeType="text/dlm" />
+            <mimeMap fileExtension=".doc" mimeType="application/msword" />
+            <mimeMap fileExtension=".docm" mimeType="application/vnd.ms-word.document.macroEnabled.12" />
+            <mimeMap fileExtension=".docx" mimeType="application/vnd.openxmlformats-officedocument.wordprocessingml.document" />
+            <mimeMap fileExtension=".dot" mimeType="application/msword" />
+            <mimeMap fileExtension=".dotm" mimeType="application/vnd.ms-word.template.macroEnabled.12" />
+            <mimeMap fileExtension=".dotx" mimeType="application/vnd.openxmlformats-officedocument.wordprocessingml.template" />
+            <mimeMap fileExtension=".dsp" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".dtd" mimeType="text/xml" />
+            <mimeMap fileExtension=".dvi" mimeType="application/x-dvi" />
+            <mimeMap fileExtension=".dvr-ms" mimeType="video/x-ms-dvr" />
+            <mimeMap fileExtension=".dwf" mimeType="drawing/x-dwf" />
+            <mimeMap fileExtension=".dwp" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".dxr" mimeType="application/x-director" />
+            <mimeMap fileExtension=".eml" mimeType="message/rfc822" />
+            <mimeMap fileExtension=".emz" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".eot" mimeType="application/vnd.ms-fontobject" />
+            <mimeMap fileExtension=".eps" mimeType="application/postscript" />
+            <mimeMap fileExtension=".etx" mimeType="text/x-setext" />
+            <mimeMap fileExtension=".evy" mimeType="application/envoy" />
+            <mimeMap fileExtension=".exe" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".exe.config" mimeType="text/xml" />
+            <mimeMap fileExtension=".fdf" mimeType="application/vnd.fdf" />
+            <mimeMap fileExtension=".fif" mimeType="application/fractals" />
+            <mimeMap fileExtension=".fla" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".flr" mimeType="x-world/x-vrml" />
+            <mimeMap fileExtension=".flv" mimeType="video/x-flv" />
+            <mimeMap fileExtension=".gif" mimeType="image/gif" />
+            <mimeMap fileExtension=".gtar" mimeType="application/x-gtar" />
+            <mimeMap fileExtension=".gz" mimeType="application/x-gzip" />
+            <mimeMap fileExtension=".h" mimeType="text/plain" />
+            <mimeMap fileExtension=".hdf" mimeType="application/x-hdf" />
+            <mimeMap fileExtension=".hdml" mimeType="text/x-hdml" />
+            <mimeMap fileExtension=".hhc" mimeType="application/x-oleobject" />
+            <mimeMap fileExtension=".hhk" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".hhp" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".hlp" mimeType="application/winhlp" />
+            <mimeMap fileExtension=".hqx" mimeType="application/mac-binhex40" />
+            <mimeMap fileExtension=".hta" mimeType="application/hta" />
+            <mimeMap fileExtension=".htc" mimeType="text/x-component" />
+            <mimeMap fileExtension=".htm" mimeType="text/html" />
+            <mimeMap fileExtension=".html" mimeType="text/html" />
+            <mimeMap fileExtension=".htt" mimeType="text/webviewhtml" />
+            <mimeMap fileExtension=".hxt" mimeType="text/html" />
+            <mimeMap fileExtension=".ical" mimeType="text/calendar" />
+            <mimeMap fileExtension=".icalendar" mimeType="text/calendar" />
+            <mimeMap fileExtension=".ico" mimeType="image/x-icon" />
+            <mimeMap fileExtension=".ics" mimeType="text/calendar" />
+            <mimeMap fileExtension=".ief" mimeType="image/ief" />
+            <mimeMap fileExtension=".ifb" mimeType="text/calendar" />
+            <mimeMap fileExtension=".iii" mimeType="application/x-iphone" />
+            <mimeMap fileExtension=".inf" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".ins" mimeType="application/x-internet-signup" />
+            <mimeMap fileExtension=".isp" mimeType="application/x-internet-signup" />
+            <mimeMap fileExtension=".IVF" mimeType="video/x-ivf" />
+            <mimeMap fileExtension=".jar" mimeType="application/java-archive" />
+            <mimeMap fileExtension=".java" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".jck" mimeType="application/liquidmotion" />
+            <mimeMap fileExtension=".jcz" mimeType="application/liquidmotion" />
+            <mimeMap fileExtension=".jfif" mimeType="image/pjpeg" />
+            <mimeMap fileExtension=".jpb" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".jpe" mimeType="image/jpeg" />
+            <mimeMap fileExtension=".jpeg" mimeType="image/jpeg" />
+            <mimeMap fileExtension=".jpg" mimeType="image/jpeg" />
+            <mimeMap fileExtension=".js" mimeType="application/javascript" />
+            <mimeMap fileExtension=".jsx" mimeType="text/jscript" />
+            <mimeMap fileExtension=".latex" mimeType="application/x-latex" />
+            <mimeMap fileExtension=".lit" mimeType="application/x-ms-reader" />
+            <mimeMap fileExtension=".lpk" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".lsf" mimeType="video/x-la-asf" />
+            <mimeMap fileExtension=".lsx" mimeType="video/x-la-asf" />
+            <mimeMap fileExtension=".lzh" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".m13" mimeType="application/x-msmediaview" />
+            <mimeMap fileExtension=".m14" mimeType="application/x-msmediaview" />
+            <mimeMap fileExtension=".m1v" mimeType="video/mpeg" />
+            <mimeMap fileExtension=".m2ts" mimeType="video/vnd.dlna.mpeg-tts" />
+            <mimeMap fileExtension=".m3u" mimeType="audio/x-mpegurl" />
+            <mimeMap fileExtension=".m4a" mimeType="audio/mp4" />
+            <mimeMap fileExtension=".m4v" mimeType="video/mp4" />
+            <mimeMap fileExtension=".man" mimeType="application/x-troff-man" />
+            <mimeMap fileExtension=".manifest" mimeType="application/x-ms-manifest" />
+            <mimeMap fileExtension=".map" mimeType="text/plain" />
+            <mimeMap fileExtension=".mdb" mimeType="application/x-msaccess" />
+            <mimeMap fileExtension=".mdp" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".me" mimeType="application/x-troff-me" />
+            <mimeMap fileExtension=".mht" mimeType="message/rfc822" />
+            <mimeMap fileExtension=".mhtml" mimeType="message/rfc822" />
+            <mimeMap fileExtension=".mid" mimeType="audio/mid" />
+            <mimeMap fileExtension=".midi" mimeType="audio/mid" />
+            <mimeMap fileExtension=".mix" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".mmf" mimeType="application/x-smaf" />
+            <mimeMap fileExtension=".mno" mimeType="text/xml" />
+            <mimeMap fileExtension=".mny" mimeType="application/x-msmoney" />
+            <mimeMap fileExtension=".mov" mimeType="video/quicktime" />
+            <mimeMap fileExtension=".movie" mimeType="video/x-sgi-movie" />
+            <mimeMap fileExtension=".mp2" mimeType="video/mpeg" />
+            <mimeMap fileExtension=".mp3" mimeType="audio/mpeg" />
+            <mimeMap fileExtension=".mp4" mimeType="video/mp4" />
+            <mimeMap fileExtension=".mp4v" mimeType="video/mp4" />
+            <mimeMap fileExtension=".mpa" mimeType="video/mpeg" />
+            <mimeMap fileExtension=".mpe" mimeType="video/mpeg" />
+            <mimeMap fileExtension=".mpeg" mimeType="video/mpeg" />
+            <mimeMap fileExtension=".mpg" mimeType="video/mpeg" />
+            <mimeMap fileExtension=".mpp" mimeType="application/vnd.ms-project" />
+            <mimeMap fileExtension=".mpv2" mimeType="video/mpeg" />
+            <mimeMap fileExtension=".ms" mimeType="application/x-troff-ms" />
+            <mimeMap fileExtension=".msi" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".mso" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".mvb" mimeType="application/x-msmediaview" />
+            <mimeMap fileExtension=".mvc" mimeType="application/x-miva-compiled" />
+            <mimeMap fileExtension=".nc" mimeType="application/x-netcdf" />
+            <mimeMap fileExtension=".nsc" mimeType="video/x-ms-asf" />
+            <mimeMap fileExtension=".nws" mimeType="message/rfc822" />
+            <mimeMap fileExtension=".ocx" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".oda" mimeType="application/oda" />
+            <mimeMap fileExtension=".odc" mimeType="text/x-ms-odc" />
+            <mimeMap fileExtension=".ods" mimeType="application/oleobject" />
+            <mimeMap fileExtension=".oga" mimeType="audio/ogg" />
+            <mimeMap fileExtension=".ogg" mimeType="video/ogg" />
+            <mimeMap fileExtension=".ogv" mimeType="video/ogg" />
+            <mimeMap fileExtension=".ogx" mimeType="application/ogg" />
+            <mimeMap fileExtension=".one" mimeType="application/onenote" />
+            <mimeMap fileExtension=".onea" mimeType="application/onenote" />
+            <mimeMap fileExtension=".onetoc" mimeType="application/onenote" />
+            <mimeMap fileExtension=".onetoc2" mimeType="application/onenote" />
+            <mimeMap fileExtension=".onetmp" mimeType="application/onenote" />
+            <mimeMap fileExtension=".onepkg" mimeType="application/onenote" />
+            <mimeMap fileExtension=".osdx" mimeType="application/opensearchdescription+xml" />
+            <mimeMap fileExtension=".otf" mimeType="font/otf" />
+            <mimeMap fileExtension=".p10" mimeType="application/pkcs10" />
+            <mimeMap fileExtension=".p12" mimeType="application/x-pkcs12" />
+            <mimeMap fileExtension=".p7b" mimeType="application/x-pkcs7-certificates" />
+            <mimeMap fileExtension=".p7c" mimeType="application/pkcs7-mime" />
+            <mimeMap fileExtension=".p7m" mimeType="application/pkcs7-mime" />
+            <mimeMap fileExtension=".p7r" mimeType="application/x-pkcs7-certreqresp" />
+            <mimeMap fileExtension=".p7s" mimeType="application/pkcs7-signature" />
+            <mimeMap fileExtension=".pbm" mimeType="image/x-portable-bitmap" />
+            <mimeMap fileExtension=".pcx" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".pcz" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".pdf" mimeType="application/pdf" />
+            <mimeMap fileExtension=".pfb" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".pfm" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".pfx" mimeType="application/x-pkcs12" />
+            <mimeMap fileExtension=".pgm" mimeType="image/x-portable-graymap" />
+            <mimeMap fileExtension=".pko" mimeType="application/vnd.ms-pki.pko" />
+            <mimeMap fileExtension=".pma" mimeType="application/x-perfmon" />
+            <mimeMap fileExtension=".pmc" mimeType="application/x-perfmon" />
+            <mimeMap fileExtension=".pml" mimeType="application/x-perfmon" />
+            <mimeMap fileExtension=".pmr" mimeType="application/x-perfmon" />
+            <mimeMap fileExtension=".pmw" mimeType="application/x-perfmon" />
+            <mimeMap fileExtension=".png" mimeType="image/png" />
+            <mimeMap fileExtension=".pnm" mimeType="image/x-portable-anymap" />
+            <mimeMap fileExtension=".pnz" mimeType="image/png" />
+            <mimeMap fileExtension=".pot" mimeType="application/vnd.ms-powerpoint" />
+            <mimeMap fileExtension=".potm" mimeType="application/vnd.ms-powerpoint.template.macroEnabled.12" />
+            <mimeMap fileExtension=".potx" mimeType="application/vnd.openxmlformats-officedocument.presentationml.template" />
+            <mimeMap fileExtension=".ppam" mimeType="application/vnd.ms-powerpoint.addin.macroEnabled.12" />
+            <mimeMap fileExtension=".ppm" mimeType="image/x-portable-pixmap" />
+            <mimeMap fileExtension=".pps" mimeType="application/vnd.ms-powerpoint" />
+            <mimeMap fileExtension=".ppsm" mimeType="application/vnd.ms-powerpoint.slideshow.macroEnabled.12" />
+            <mimeMap fileExtension=".ppsx" mimeType="application/vnd.openxmlformats-officedocument.presentationml.slideshow" />
+            <mimeMap fileExtension=".ppt" mimeType="application/vnd.ms-powerpoint" />
+            <mimeMap fileExtension=".pptm" mimeType="application/vnd.ms-powerpoint.presentation.macroEnabled.12" />
+            <mimeMap fileExtension=".pptx" mimeType="application/vnd.openxmlformats-officedocument.presentationml.presentation" />
+            <mimeMap fileExtension=".prf" mimeType="application/pics-rules" />
+            <mimeMap fileExtension=".prm" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".prx" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".ps" mimeType="application/postscript" />
+            <mimeMap fileExtension=".psd" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".psm" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".psp" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".pub" mimeType="application/x-mspublisher" />
+            <mimeMap fileExtension=".qt" mimeType="video/quicktime" />
+            <mimeMap fileExtension=".qtl" mimeType="application/x-quicktimeplayer" />
+            <mimeMap fileExtension=".qxd" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".ra" mimeType="audio/x-pn-realaudio" />
+            <mimeMap fileExtension=".ram" mimeType="audio/x-pn-realaudio" />
+            <mimeMap fileExtension=".rar" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".ras" mimeType="image/x-cmu-raster" />
+            <mimeMap fileExtension=".rf" mimeType="image/vnd.rn-realflash" />
+            <mimeMap fileExtension=".rgb" mimeType="image/x-rgb" />
+            <mimeMap fileExtension=".rm" mimeType="application/vnd.rn-realmedia" />
+            <mimeMap fileExtension=".rmi" mimeType="audio/mid" />
+            <mimeMap fileExtension=".roff" mimeType="application/x-troff" />
+            <mimeMap fileExtension=".rpm" mimeType="audio/x-pn-realaudio-plugin" />
+            <mimeMap fileExtension=".rtf" mimeType="application/rtf" />
+            <mimeMap fileExtension=".rtx" mimeType="text/richtext" />
+            <mimeMap fileExtension=".scd" mimeType="application/x-msschedule" />
+            <mimeMap fileExtension=".sct" mimeType="text/scriptlet" />
+            <mimeMap fileExtension=".sea" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".setpay" mimeType="application/set-payment-initiation" />
+            <mimeMap fileExtension=".setreg" mimeType="application/set-registration-initiation" />
+            <mimeMap fileExtension=".sgml" mimeType="text/sgml" />
+            <mimeMap fileExtension=".sh" mimeType="application/x-sh" />
+            <mimeMap fileExtension=".shar" mimeType="application/x-shar" />
+            <mimeMap fileExtension=".sit" mimeType="application/x-stuffit" />
+            <mimeMap fileExtension=".sldm" mimeType="application/vnd.ms-powerpoint.slide.macroEnabled.12" />
+            <mimeMap fileExtension=".sldx" mimeType="application/vnd.openxmlformats-officedocument.presentationml.slide" />
+            <mimeMap fileExtension=".smd" mimeType="audio/x-smd" />
+            <mimeMap fileExtension=".smi" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".smx" mimeType="audio/x-smd" />
+            <mimeMap fileExtension=".smz" mimeType="audio/x-smd" />
+            <mimeMap fileExtension=".snd" mimeType="audio/basic" />
+            <mimeMap fileExtension=".snp" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".spc" mimeType="application/x-pkcs7-certificates" />
+            <mimeMap fileExtension=".spl" mimeType="application/futuresplash" />
+            <mimeMap fileExtension=".spx" mimeType="audio/ogg" />
+            <mimeMap fileExtension=".src" mimeType="application/x-wais-source" />
+            <mimeMap fileExtension=".ssm" mimeType="application/streamingmedia" />
+            <mimeMap fileExtension=".sst" mimeType="application/vnd.ms-pki.certstore" />
+            <mimeMap fileExtension=".stl" mimeType="application/vnd.ms-pki.stl" />
+            <mimeMap fileExtension=".sv4cpio" mimeType="application/x-sv4cpio" />
+            <mimeMap fileExtension=".sv4crc" mimeType="application/x-sv4crc" />
+            <mimeMap fileExtension=".svg" mimeType="image/svg+xml" />
+            <mimeMap fileExtension=".svgz" mimeType="image/svg+xml" />
+            <mimeMap fileExtension=".swf" mimeType="application/x-shockwave-flash" />
+            <mimeMap fileExtension=".t" mimeType="application/x-troff" />
+            <mimeMap fileExtension=".tar" mimeType="application/x-tar" />
+            <mimeMap fileExtension=".tcl" mimeType="application/x-tcl" />
+            <mimeMap fileExtension=".tex" mimeType="application/x-tex" />
+            <mimeMap fileExtension=".texi" mimeType="application/x-texinfo" />
+            <mimeMap fileExtension=".texinfo" mimeType="application/x-texinfo" />
+            <mimeMap fileExtension=".tgz" mimeType="application/x-compressed" />
+            <mimeMap fileExtension=".thmx" mimeType="application/vnd.ms-officetheme" />
+            <mimeMap fileExtension=".thn" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".tif" mimeType="image/tiff" />
+            <mimeMap fileExtension=".tiff" mimeType="image/tiff" />
+            <mimeMap fileExtension=".toc" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".tr" mimeType="application/x-troff" />
+            <mimeMap fileExtension=".trm" mimeType="application/x-msterminal" />
+            <mimeMap fileExtension=".ts" mimeType="video/vnd.dlna.mpeg-tts" />
+            <mimeMap fileExtension=".tsv" mimeType="text/tab-separated-values" />
+            <mimeMap fileExtension=".ttf" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".tts" mimeType="video/vnd.dlna.mpeg-tts" />
+            <mimeMap fileExtension=".txt" mimeType="text/plain" />
+            <mimeMap fileExtension=".u32" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".uls" mimeType="text/iuls" />
+            <mimeMap fileExtension=".ustar" mimeType="application/x-ustar" />
+            <mimeMap fileExtension=".vbs" mimeType="text/vbscript" />
+            <mimeMap fileExtension=".vcf" mimeType="text/x-vcard" />
+            <mimeMap fileExtension=".vcs" mimeType="text/plain" />
+            <mimeMap fileExtension=".vdx" mimeType="application/vnd.ms-visio.viewer" />
+            <mimeMap fileExtension=".vml" mimeType="text/xml" />
+            <mimeMap fileExtension=".vsd" mimeType="application/vnd.visio" />
+            <mimeMap fileExtension=".vss" mimeType="application/vnd.visio" />
+            <mimeMap fileExtension=".vst" mimeType="application/vnd.visio" />
+            <mimeMap fileExtension=".vsto" mimeType="application/x-ms-vsto" />
+            <mimeMap fileExtension=".vsw" mimeType="application/vnd.visio" />
+            <mimeMap fileExtension=".vsx" mimeType="application/vnd.visio" />
+            <mimeMap fileExtension=".vtx" mimeType="application/vnd.visio" />
+            <mimeMap fileExtension=".wav" mimeType="audio/wav" />
+            <mimeMap fileExtension=".wax" mimeType="audio/x-ms-wax" />
+            <mimeMap fileExtension=".wbmp" mimeType="image/vnd.wap.wbmp" />
+            <mimeMap fileExtension=".wcm" mimeType="application/vnd.ms-works" />
+            <mimeMap fileExtension=".wdb" mimeType="application/vnd.ms-works" />
+            <mimeMap fileExtension=".webm" mimeType="video/webm" />
+            <mimeMap fileExtension=".wks" mimeType="application/vnd.ms-works" />
+            <mimeMap fileExtension=".wm" mimeType="video/x-ms-wm" />
+            <mimeMap fileExtension=".wma" mimeType="audio/x-ms-wma" />
+            <mimeMap fileExtension=".wmd" mimeType="application/x-ms-wmd" />
+            <mimeMap fileExtension=".wmf" mimeType="application/x-msmetafile" />
+            <mimeMap fileExtension=".wml" mimeType="text/vnd.wap.wml" />
+            <mimeMap fileExtension=".wmlc" mimeType="application/vnd.wap.wmlc" />
+            <mimeMap fileExtension=".wmls" mimeType="text/vnd.wap.wmlscript" />
+            <mimeMap fileExtension=".wmlsc" mimeType="application/vnd.wap.wmlscriptc" />
+            <mimeMap fileExtension=".wmp" mimeType="video/x-ms-wmp" />
+            <mimeMap fileExtension=".wmv" mimeType="video/x-ms-wmv" />
+            <mimeMap fileExtension=".wmx" mimeType="video/x-ms-wmx" />
+            <mimeMap fileExtension=".wmz" mimeType="application/x-ms-wmz" />
+            <mimeMap fileExtension=".woff" mimeType="font/x-woff" />
+            <mimeMap fileExtension=".wps" mimeType="application/vnd.ms-works" />
+            <mimeMap fileExtension=".wri" mimeType="application/x-mswrite" />
+            <mimeMap fileExtension=".wrl" mimeType="x-world/x-vrml" />
+            <mimeMap fileExtension=".wrz" mimeType="x-world/x-vrml" />
+            <mimeMap fileExtension=".wsdl" mimeType="text/xml" />
+            <mimeMap fileExtension=".wtv" mimeType="video/x-ms-wtv" />
+            <mimeMap fileExtension=".wvx" mimeType="video/x-ms-wvx" />
+            <mimeMap fileExtension=".x" mimeType="application/directx" />
+            <mimeMap fileExtension=".xaf" mimeType="x-world/x-vrml" />
+            <mimeMap fileExtension=".xaml" mimeType="application/xaml+xml" />
+            <mimeMap fileExtension=".xap" mimeType="application/x-silverlight-app" />
+            <mimeMap fileExtension=".xbap" mimeType="application/x-ms-xbap" />
+            <mimeMap fileExtension=".xbm" mimeType="image/x-xbitmap" />
+            <mimeMap fileExtension=".xdr" mimeType="text/plain" />
+            <mimeMap fileExtension=".xht" mimeType="application/xhtml+xml" />
+            <mimeMap fileExtension=".xhtml" mimeType="application/xhtml+xml" />
+            <mimeMap fileExtension=".xla" mimeType="application/vnd.ms-excel" />
+            <mimeMap fileExtension=".xlam" mimeType="application/vnd.ms-excel.addin.macroEnabled.12" />
+            <mimeMap fileExtension=".xlc" mimeType="application/vnd.ms-excel" />
+            <mimeMap fileExtension=".xlm" mimeType="application/vnd.ms-excel" />
+            <mimeMap fileExtension=".xls" mimeType="application/vnd.ms-excel" />
+            <mimeMap fileExtension=".xlsb" mimeType="application/vnd.ms-excel.sheet.binary.macroEnabled.12" />
+            <mimeMap fileExtension=".xlsm" mimeType="application/vnd.ms-excel.sheet.macroEnabled.12" />
+            <mimeMap fileExtension=".xlsx" mimeType="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" />
+            <mimeMap fileExtension=".xlt" mimeType="application/vnd.ms-excel" />
+            <mimeMap fileExtension=".xltm" mimeType="application/vnd.ms-excel.template.macroEnabled.12" />
+            <mimeMap fileExtension=".xltx" mimeType="application/vnd.openxmlformats-officedocument.spreadsheetml.template" />
+            <mimeMap fileExtension=".xlw" mimeType="application/vnd.ms-excel" />
+            <mimeMap fileExtension=".xml" mimeType="text/xml" />
+            <mimeMap fileExtension=".xof" mimeType="x-world/x-vrml" />
+            <mimeMap fileExtension=".xpm" mimeType="image/x-xpixmap" />
+            <mimeMap fileExtension=".xps" mimeType="application/vnd.ms-xpsdocument" />
+            <mimeMap fileExtension=".xsd" mimeType="text/xml" />
+            <mimeMap fileExtension=".xsf" mimeType="text/xml" />
+            <mimeMap fileExtension=".xsl" mimeType="text/xml" />
+            <mimeMap fileExtension=".xslt" mimeType="text/xml" />
+            <mimeMap fileExtension=".xsn" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".xtp" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".xwd" mimeType="image/x-xwindowdump" />
+            <mimeMap fileExtension=".z" mimeType="application/x-compress" />
+            <mimeMap fileExtension=".zip" mimeType="application/x-zip-compressed" />
+        </staticContent>
+
+        <tracing>
+
+             <traceProviderDefinitions>
+                <add name="WWW Server" guid="{3a2a4e84-4c21-4981-ae10-3fda0d9b0f83}">
+                    <areas>
+                        <clear />
+                        <add name="Authentication" value="2" />
+                        <add name="Security" value="4" />
+                        <add name="Filter" value="8" />
+                        <add name="StaticFile" value="16" />
+                        <add name="CGI" value="32" />
+                        <add name="Compression" value="64" />
+                        <add name="Cache" value="128" />
+                        <add name="RequestNotifications" value="256" />
+                        <add name="Module" value="512" />
+                        <add name="Rewrite" value="1024" />
+                        <add name="FastCGI" value="4096" />
+                        <add name="WebSocket" value="16384" />
+                    </areas>
+                </add>
+                <add name="ASP" guid="{06b94d9a-b15e-456e-a4ef-37c984a2cb4b}">
+                    <areas>
+                        <clear />
+                    </areas>
+                </add>
+                <add name="ISAPI Extension" guid="{a1c2040e-8840-4c31-ba11-9871031a19ea}">
+                    <areas>
+                        <clear />
+                    </areas>
+                </add>
+                <add name="ASPNET" guid="{AFF081FE-0247-4275-9C4E-021F3DC1DA35}">
+                    <areas>
+                        <add name="Infrastructure" value="1" />
+                        <add name="Module" value="2" />
+                        <add name="Page" value="4" />
+                        <add name="AppServices" value="8" />
+                    </areas>
+                </add>
+            </traceProviderDefinitions>
+
+            <traceFailedRequests>
+                <add path="*">
+                    <traceAreas>
+                        <add provider="ASP" verbosity="Verbose" />
+                        <add provider="ASPNET" areas="Infrastructure,Module,Page,AppServices" verbosity="Verbose" />
+                        <add provider="ISAPI Extension" verbosity="Verbose" />
+                        <add provider="WWW Server" areas="Authentication,Security,Filter,StaticFile,CGI,Compression,Cache,RequestNotifications,Module,Rewrite,WebSocket" verbosity="Verbose" />
+                    </traceAreas>
+                    <failureDefinitions statusCodes="200-999" />
+                </add>
+            </traceFailedRequests>
+
+        </tracing>
+
+        <urlCompression />
+
+        <validation />
+        <webdav>
+            <globalSettings>
+                <propertyStores>
+                    <add name="webdav_simple_prop" image="%IIS_BIN%\webdav_simple_prop.dll" image32="%IIS_BIN%\webdav_simple_prop.dll" />
+                </propertyStores>
+                <lockStores>
+                    <add name="webdav_simple_lock" image="%IIS_BIN%\webdav_simple_lock.dll" image32="%IIS_BIN%\webdav_simple_lock.dll" />
+                </lockStores>
+
+            </globalSettings>
+            <authoring>
+                <locks enabled="true" lockStore="webdav_simple_lock" />
+            </authoring>
+            <authoringRules />
+        </webdav>
+        <applicationInitialization />
+        <webSocket />
+
+    </system.webServer>
+    <location path="" overrideMode="Allow">
+        <system.webServer>
+            <modules>
+              <add name="IsapiFilterModule" lockItem="true" />
+              <add name="BasicAuthenticationModule" lockItem="true" />
+              <add name="IsapiModule" lockItem="true" />
+              <add name="HttpLoggingModule" lockItem="true" />
+                <!--
+                <add name="HttpCacheModule" lockItem="true" />
+-->
+                <add name="DynamicCompressionModule" lockItem="true" />
+                <add name="StaticCompressionModule" lockItem="true" />
+                <add name="DefaultDocumentModule" lockItem="true" />
+                <add name="DirectoryListingModule" lockItem="true" />
+                <add name="ProtocolSupportModule" lockItem="true" />
+                <add name="HttpRedirectionModule" lockItem="true" />
+                <add name="ServerSideIncludeModule" lockItem="true" />
+                <add name="StaticFileModule" lockItem="true" />
+                <add name="AnonymousAuthenticationModule" lockItem="true" />
+                <add name="CertificateMappingAuthenticationModule" lockItem="true" />
+                <add name="UrlAuthorizationModule" lockItem="true" />
+                <add name="WindowsAuthenticationModule" lockItem="true" />
+                <!--
+                <add name="DigestAuthenticationModule" lockItem="true" />
+-->
+                <add name="IISCertificateMappingAuthenticationModule" lockItem="true" />
+                <add name="WebMatrixSupportModule" lockItem="true" />
+                <add name="IpRestrictionModule" lockItem="true" />
+                <add name="DynamicIpRestrictionModule" lockItem="true" />
+                <add name="RequestFilteringModule" lockItem="true" />
+                <add name="CustomLoggingModule" lockItem="true" />
+                <add name="CustomErrorModule" lockItem="true" />
+                <add name="FailedRequestsTracingModule" lockItem="true" />
+                <add name="CgiModule" lockItem="true" />
+                <add name="FastCgiModule" lockItem="true" />
+                <!--                <add name="WebDAVModule" /> -->
+                <add name="RewriteModule" />
+                <add name="OutputCache" type="System.Web.Caching.OutputCacheModule" preCondition="managedHandler" />
+                <add name="Session" type="System.Web.SessionState.SessionStateModule" preCondition="managedHandler" />
+                <add name="WindowsAuthentication" type="System.Web.Security.WindowsAuthenticationModule" preCondition="managedHandler" />
+                <add name="FormsAuthentication" type="System.Web.Security.FormsAuthenticationModule" preCondition="managedHandler" />
+                <add name="DefaultAuthentication" type="System.Web.Security.DefaultAuthenticationModule" preCondition="managedHandler" />
+                <add name="RoleManager" type="System.Web.Security.RoleManagerModule" preCondition="managedHandler" />
+                <add name="UrlAuthorization" type="System.Web.Security.UrlAuthorizationModule" preCondition="managedHandler" />
+                <add name="FileAuthorization" type="System.Web.Security.FileAuthorizationModule" preCondition="managedHandler" />
+                <add name="AnonymousIdentification" type="System.Web.Security.AnonymousIdentificationModule" preCondition="managedHandler" />
+                <add name="Profile" type="System.Web.Profile.ProfileModule" preCondition="managedHandler" />
+                <add name="UrlMappingsModule" type="System.Web.UrlMappingsModule" preCondition="managedHandler" />
+                <add name="ApplicationInitializationModule" lockItem="true" />
+                <add name="WebSocketModule" lockItem="true" />
+                <add name="ServiceModel-4.0" type="System.ServiceModel.Activation.ServiceHttpModule,System.ServiceModel.Activation,Version=4.0.0.0,Culture=neutral,PublicKeyToken=31bf3856ad364e35" preCondition="managedHandler,runtimeVersionv4.0" />
+                <add name="ConfigurationValidationModule" lockItem="true" />
+                <add name="UrlRoutingModule-4.0" type="System.Web.Routing.UrlRoutingModule" preCondition="managedHandler,runtimeVersionv4.0" />
+                <add name="ScriptModule-4.0" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" preCondition="managedHandler,runtimeVersionv4.0" />
+                <add name="ServiceModel" type="System.ServiceModel.Activation.HttpModule, System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" preCondition="managedHandler,runtimeVersionv2.0" />
+                <add name="AspNetCoreModule" />
+            </modules>
+            <handlers accessPolicy="Read, Script">
+                <!--                <add name="WebDAV" path="*" verb="PROPFIND,PROPPATCH,MKCOL,PUT,COPY,DELETE,MOVE,LOCK,UNLOCK" modules="WebDAVModule" resourceType="Unspecified" requireAccess="None" /> -->
+                <add name="AXD-ISAPI-4.0_64bit" path="*.axd" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
+                <add name="PageHandlerFactory-ISAPI-4.0_64bit" path="*.aspx" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
+                <add name="SimpleHandlerFactory-ISAPI-4.0_64bit" path="*.ashx" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
+                <add name="WebServiceHandlerFactory-ISAPI-4.0_64bit" path="*.asmx" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
+                <add name="HttpRemotingHandlerFactory-rem-ISAPI-4.0_64bit" path="*.rem" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
+                <add name="HttpRemotingHandlerFactory-soap-ISAPI-4.0_64bit" path="*.soap" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
+                <add name="svc-ISAPI-4.0_64bit" path="*.svc" verb="*" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" />
+                <add name="rules-ISAPI-4.0_64bit" path="*.rules" verb="*" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" />
+                <add name="xoml-ISAPI-4.0_64bit" path="*.xoml" verb="*" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" />
+                <add name="xamlx-ISAPI-4.0_64bit" path="*.xamlx" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" />
+                <add name="aspq-ISAPI-4.0_64bit" path="*.aspq" verb="*" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
+                <add name="cshtm-ISAPI-4.0_64bit" path="*.cshtm" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
+                <add name="cshtml-ISAPI-4.0_64bit" path="*.cshtml" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
+                <add name="vbhtm-ISAPI-4.0_64bit" path="*.vbhtm" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
+                <add name="vbhtml-ISAPI-4.0_64bit" path="*.vbhtml" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
+                <add name="svc-Integrated" path="*.svc" verb="*" type="System.ServiceModel.Activation.HttpHandler, System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" preCondition="integratedMode,runtimeVersionv2.0" />
+                <add name="svc-ISAPI-2.0" path="*.svc" verb="*" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness32" />
+                <add name="xoml-Integrated" path="*.xoml" verb="*" type="System.ServiceModel.Activation.HttpHandler, System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" preCondition="integratedMode,runtimeVersionv2.0" />
+                <add name="xoml-ISAPI-2.0" path="*.xoml" verb="*" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness32" />
+                <add name="rules-Integrated" path="*.rules" verb="*" type="System.ServiceModel.Activation.HttpHandler, System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" preCondition="integratedMode,runtimeVersionv2.0" />
+                <add name="rules-ISAPI-2.0" path="*.rules" verb="*" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness32" />
+                <add name="AXD-ISAPI-4.0_32bit" path="*.axd" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
+                <add name="PageHandlerFactory-ISAPI-4.0_32bit" path="*.aspx" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
+                <add name="SimpleHandlerFactory-ISAPI-4.0_32bit" path="*.ashx" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
+                <add name="WebServiceHandlerFactory-ISAPI-4.0_32bit" path="*.asmx" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
+                <add name="HttpRemotingHandlerFactory-rem-ISAPI-4.0_32bit" path="*.rem" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
+                <add name="HttpRemotingHandlerFactory-soap-ISAPI-4.0_32bit" path="*.soap" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
+                <add name="svc-ISAPI-4.0_32bit" path="*.svc" verb="*" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" />
+                <add name="rules-ISAPI-4.0_32bit" path="*.rules" verb="*" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" />
+                <add name="xoml-ISAPI-4.0_32bit" path="*.xoml" verb="*" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" />
+                <add name="xamlx-ISAPI-4.0_32bit" path="*.xamlx" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" />
+                <add name="aspq-ISAPI-4.0_32bit" path="*.aspq" verb="*" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
+                <add name="cshtm-ISAPI-4.0_32bit" path="*.cshtm" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
+                <add name="cshtml-ISAPI-4.0_32bit" path="*.cshtml" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
+                <add name="vbhtm-ISAPI-4.0_32bit" path="*.vbhtm" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
+                <add name="vbhtml-ISAPI-4.0_32bit" path="*.vbhtml" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
+                <add name="TraceHandler-Integrated-4.0" path="trace.axd" verb="GET,HEAD,POST,DEBUG" type="System.Web.Handlers.TraceHandler" preCondition="integratedMode,runtimeVersionv4.0" />
+                <add name="WebAdminHandler-Integrated-4.0" path="WebAdmin.axd" verb="GET,DEBUG" type="System.Web.Handlers.WebAdminHandler" preCondition="integratedMode,runtimeVersionv4.0" />
+                <add name="AssemblyResourceLoader-Integrated-4.0" path="WebResource.axd" verb="GET,DEBUG" type="System.Web.Handlers.AssemblyResourceLoader" preCondition="integratedMode,runtimeVersionv4.0" />
+                <add name="PageHandlerFactory-Integrated-4.0" path="*.aspx" verb="GET,HEAD,POST,DEBUG" type="System.Web.UI.PageHandlerFactory" preCondition="integratedMode,runtimeVersionv4.0" />
+                <add name="SimpleHandlerFactory-Integrated-4.0" path="*.ashx" verb="GET,HEAD,POST,DEBUG" type="System.Web.UI.SimpleHandlerFactory" preCondition="integratedMode,runtimeVersionv4.0" />
+                <add name="WebServiceHandlerFactory-Integrated-4.0" path="*.asmx" verb="GET,HEAD,POST,DEBUG" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" preCondition="integratedMode,runtimeVersionv4.0" />
+                <add name="HttpRemotingHandlerFactory-rem-Integrated-4.0" path="*.rem" verb="GET,HEAD,POST,DEBUG" type="System.Runtime.Remoting.Channels.Http.HttpRemotingHandlerFactory, System.Runtime.Remoting, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" preCondition="integratedMode,runtimeVersionv4.0" />
+                <add name="HttpRemotingHandlerFactory-soap-Integrated-4.0" path="*.soap" verb="GET,HEAD,POST,DEBUG" type="System.Runtime.Remoting.Channels.Http.HttpRemotingHandlerFactory, System.Runtime.Remoting, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" preCondition="integratedMode,runtimeVersionv4.0" />
+                <add name="svc-Integrated-4.0" path="*.svc" verb="*" type="System.ServiceModel.Activation.ServiceHttpHandlerFactory, System.ServiceModel.Activation, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" preCondition="integratedMode,runtimeVersionv4.0" />
+                <add name="rules-Integrated-4.0" path="*.rules" verb="*" type="System.ServiceModel.Activation.ServiceHttpHandlerFactory, System.ServiceModel.Activation, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" preCondition="integratedMode,runtimeVersionv4.0" />
+                <add name="xoml-Integrated-4.0" path="*.xoml" verb="*" type="System.ServiceModel.Activation.ServiceHttpHandlerFactory, System.ServiceModel.Activation, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" preCondition="integratedMode,runtimeVersionv4.0" />
+                <add name="xamlx-Integrated-4.0" path="*.xamlx" verb="GET,HEAD,POST,DEBUG" type="System.Xaml.Hosting.XamlHttpHandlerFactory, System.Xaml.Hosting, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" preCondition="integratedMode,runtimeVersionv4.0" />
+                <add name="aspq-Integrated-4.0" path="*.aspq" verb="GET,HEAD,POST,DEBUG" type="System.Web.HttpForbiddenHandler" preCondition="integratedMode,runtimeVersionv4.0" />
+                <add name="cshtm-Integrated-4.0" path="*.cshtm" verb="GET,HEAD,POST,DEBUG" type="System.Web.HttpForbiddenHandler" preCondition="integratedMode,runtimeVersionv4.0" />
+                <add name="cshtml-Integrated-4.0" path="*.cshtml" verb="GET,HEAD,POST,DEBUG" type="System.Web.HttpForbiddenHandler" preCondition="integratedMode,runtimeVersionv4.0" />
+                <add name="vbhtm-Integrated-4.0" path="*.vbhtm" verb="GET,HEAD,POST,DEBUG" type="System.Web.HttpForbiddenHandler" preCondition="integratedMode,runtimeVersionv4.0" />
+                <add name="vbhtml-Integrated-4.0" path="*.vbhtml" verb="GET,HEAD,POST,DEBUG" type="System.Web.HttpForbiddenHandler" preCondition="integratedMode,runtimeVersionv4.0" />
+                <add name="ScriptHandlerFactoryAppServices-Integrated-4.0" path="*_AppService.axd" verb="*" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" preCondition="integratedMode,runtimeVersionv4.0" />
+                <add name="ScriptResourceIntegrated-4.0" path="*ScriptResource.axd" verb="GET,HEAD" type="System.Web.Handlers.ScriptResourceHandler, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" preCondition="integratedMode,runtimeVersionv4.0" />
+                <add name="ASPClassic" path="*.asp" verb="GET,HEAD,POST" modules="IsapiModule" scriptProcessor="%IIS_BIN%\asp.dll" resourceType="File" />
+                <add name="SecurityCertificate" path="*.cer" verb="GET,HEAD,POST" modules="IsapiModule" scriptProcessor="%IIS_BIN%\asp.dll" resourceType="File" />
+                <add name="ISAPI-dll" path="*.dll" verb="*" modules="IsapiModule" resourceType="File" requireAccess="Execute" allowPathInfo="true" />
+                <add name="TraceHandler-Integrated" path="trace.axd" verb="GET,HEAD,POST,DEBUG" type="System.Web.Handlers.TraceHandler" preCondition="integratedMode,runtimeVersionv2.0" />
+                <add name="WebAdminHandler-Integrated" path="WebAdmin.axd" verb="GET,DEBUG" type="System.Web.Handlers.WebAdminHandler" preCondition="integratedMode,runtimeVersionv2.0" />
+                <add name="AssemblyResourceLoader-Integrated" path="WebResource.axd" verb="GET,DEBUG" type="System.Web.Handlers.AssemblyResourceLoader" preCondition="integratedMode,runtimeVersionv2.0" />
+                <add name="PageHandlerFactory-Integrated" path="*.aspx" verb="GET,HEAD,POST,DEBUG" type="System.Web.UI.PageHandlerFactory" preCondition="integratedMode,runtimeVersionv2.0" />
+                <add name="SimpleHandlerFactory-Integrated" path="*.ashx" verb="GET,HEAD,POST,DEBUG" type="System.Web.UI.SimpleHandlerFactory" preCondition="integratedMode,runtimeVersionv2.0" />
+                <add name="WebServiceHandlerFactory-Integrated" path="*.asmx" verb="GET,HEAD,POST,DEBUG" type="System.Web.Services.Protocols.WebServiceHandlerFactory,System.Web.Services,Version=2.0.0.0,Culture=neutral,PublicKeyToken=b03f5f7f11d50a3a" preCondition="integratedMode,runtimeVersionv2.0" />
+                <add name="HttpRemotingHandlerFactory-rem-Integrated" path="*.rem" verb="GET,HEAD,POST,DEBUG" type="System.Runtime.Remoting.Channels.Http.HttpRemotingHandlerFactory,System.Runtime.Remoting,Version=2.0.0.0,Culture=neutral,PublicKeyToken=b77a5c561934e089" preCondition="integratedMode,runtimeVersionv2.0" />
+                <add name="HttpRemotingHandlerFactory-soap-Integrated" path="*.soap" verb="GET,HEAD,POST,DEBUG" type="System.Runtime.Remoting.Channels.Http.HttpRemotingHandlerFactory,System.Runtime.Remoting,Version=2.0.0.0,Culture=neutral,PublicKeyToken=b77a5c561934e089" preCondition="integratedMode,runtimeVersionv2.0" />
+                <add name="AXD-ISAPI-2.0" path="*.axd" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness32" responseBufferLimit="0" />
+                <add name="PageHandlerFactory-ISAPI-2.0" path="*.aspx" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness32" responseBufferLimit="0" />
+                <add name="SimpleHandlerFactory-ISAPI-2.0" path="*.ashx" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness32" responseBufferLimit="0" />
+                <add name="WebServiceHandlerFactory-ISAPI-2.0" path="*.asmx" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness32" responseBufferLimit="0" />
+                <add name="HttpRemotingHandlerFactory-rem-ISAPI-2.0" path="*.rem" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness32" responseBufferLimit="0" />
+                <add name="HttpRemotingHandlerFactory-soap-ISAPI-2.0" path="*.soap" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness32" responseBufferLimit="0" />
+                <add name="svc-ISAPI-2.0-64" path="*.svc" verb="*" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness64" />
+                <add name="AXD-ISAPI-2.0-64" path="*.axd" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness64" responseBufferLimit="0" />
+                <add name="PageHandlerFactory-ISAPI-2.0-64" path="*.aspx" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness64" responseBufferLimit="0" />
+                <add name="SimpleHandlerFactory-ISAPI-2.0-64" path="*.ashx" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness64" responseBufferLimit="0" />
+                <add name="WebServiceHandlerFactory-ISAPI-2.0-64" path="*.asmx" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness64" responseBufferLimit="0" />
+                <add name="HttpRemotingHandlerFactory-rem-ISAPI-2.0-64" path="*.rem" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness64" responseBufferLimit="0" />
+                <add name="HttpRemotingHandlerFactory-soap-ISAPI-2.0-64" path="*.soap" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness64" responseBufferLimit="0" />
+                <add name="rules-64-ISAPI-2.0" path="*.rules" verb="*" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness64" />
+                <add name="xoml-64-ISAPI-2.0" path="*.xoml" verb="*" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness64" />
+                <add name="CGI-exe" path="*.exe" verb="*" modules="CgiModule" resourceType="File" requireAccess="Execute" allowPathInfo="true" />
+                <add name="SSINC-stm" path="*.stm" verb="GET,HEAD,POST" modules="ServerSideIncludeModule" resourceType="File" />
+                <add name="SSINC-shtm" path="*.shtm" verb="GET,HEAD,POST" modules="ServerSideIncludeModule" resourceType="File" />
+                <add name="SSINC-shtml" path="*.shtml" verb="GET,HEAD,POST" modules="ServerSideIncludeModule" resourceType="File" />
+                <add name="TRACEVerbHandler" path="*" verb="TRACE" modules="ProtocolSupportModule" requireAccess="None" />
+                <add name="OPTIONSVerbHandler" path="*" verb="OPTIONS" modules="ProtocolSupportModule" requireAccess="None" />
+                <add name="ExtensionlessUrl-ISAPI-4.0_32bit" path="*." verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
+                <add name="ExtensionlessUrlHandler-ISAPI-4.0_64bit" path="*." verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
+                <add name="ExtensionlessUrl-Integrated-4.0" path="*." verb="GET,HEAD,POST,DEBUG" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" responseBufferLimit="0" />
+                <add name="StaticFile" path="*" verb="*" modules="StaticFileModule,DefaultDocumentModule,DirectoryListingModule" resourceType="Either" requireAccess="Read" />
+            </handlers>
+        </system.webServer>
+    </location>
+
+  <location path="NtlmAuthenticationTestSite">
+    <system.webServer>
+      <security>
+        <authentication>
+          <anonymousAuthentication enabled="true" />
+          <windowsAuthentication enabled="true" />
+        </authentication>
+      </security>
+    </system.webServer>
+  </location>
+</configuration>
diff --git a/src/IISIntegration/test/IISIntegration.FunctionalTests/AppHostConfig/WebsocketsNotSupported.config b/src/IISIntegration/test/IISIntegration.FunctionalTests/AppHostConfig/WebsocketsNotSupported.config
new file mode 100644
index 0000000000000000000000000000000000000000..541f91ad812370afa51cb316398e73cb194b7512
--- /dev/null
+++ b/src/IISIntegration/test/IISIntegration.FunctionalTests/AppHostConfig/WebsocketsNotSupported.config
@@ -0,0 +1,1029 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    IIS configuration sections.
+
+    For schema documentation, see
+    %IIS_BIN%\config\schema\IIS_schema.xml.
+    
+    Please make a backup of this file before making any changes to it.
+
+    NOTE: The following environment variables are available to be used
+          within this file and are understood by the IIS Express.
+
+          %IIS_USER_HOME% - The IIS Express home directory for the user
+          %IIS_SITES_HOME% - The default home directory for sites
+          %IIS_BIN% - The location of the IIS Express binaries
+          %SYSTEMDRIVE% - The drive letter of %IIS_BIN%
+
+-->
+
+<configuration>
+
+    <!--
+
+        The <configSections> section controls the registration of sections.
+        Section is the basic unit of deployment, locking, searching and
+        containment for configuration settings.
+        
+        Every section belongs to one section group.
+        A section group is a container of logically-related sections.
+        
+        Sections cannot be nested.
+        Section groups may be nested.
+        
+        <section
+            name=""  [Required, Collection Key] [XML name of the section]
+            allowDefinition="Everywhere" [MachineOnly|MachineToApplication|AppHostOnly|Everywhere] [Level where it can be set]
+            overrideModeDefault="Allow"  [Allow|Deny] [Default delegation mode]
+            allowLocation="true"  [true|false] [Allowed in location tags]
+        />
+        
+        The recommended way to unlock sections is by using a location tag:
+        <location path="Default Web Site" overrideMode="Allow">
+            <system.webServer>
+                <asp />
+            </system.webServer>
+        </location>
+
+    -->
+    <configSections>
+        <sectionGroup name="system.applicationHost">
+            <section name="applicationPools" allowDefinition="AppHostOnly" overrideModeDefault="Deny" />
+            <section name="configHistory" allowDefinition="AppHostOnly" overrideModeDefault="Deny" />
+            <section name="customMetadata" allowDefinition="AppHostOnly" overrideModeDefault="Deny" />
+            <section name="listenerAdapters" allowDefinition="AppHostOnly" overrideModeDefault="Deny" />
+            <section name="log" allowDefinition="AppHostOnly" overrideModeDefault="Deny" />
+            <section name="preloadProviders" allowDefinition="AppHostOnly" overrideModeDefault="Deny" />
+            <section name="sites" allowDefinition="AppHostOnly" overrideModeDefault="Deny" />
+            <section name="webLimits" allowDefinition="AppHostOnly" overrideModeDefault="Deny" />
+        </sectionGroup>
+
+        <sectionGroup name="system.webServer">
+            <section name="asp" overrideModeDefault="Deny" />
+            <section name="caching" overrideModeDefault="Allow" />
+            <section name="cgi" overrideModeDefault="Deny" />
+            <section name="defaultDocument" overrideModeDefault="Allow" />
+            <section name="directoryBrowse" overrideModeDefault="Allow" />
+            <section name="fastCgi" allowDefinition="AppHostOnly" overrideModeDefault="Deny" />
+            <section name="globalModules" allowDefinition="AppHostOnly" overrideModeDefault="Deny" />
+            <section name="handlers" overrideModeDefault="Deny" />
+            <section name="httpCompression" allowDefinition="AppHostOnly" overrideModeDefault="Deny" />
+            <section name="httpErrors" overrideModeDefault="Allow" />
+            <section name="httpLogging" overrideModeDefault="Deny" />
+            <section name="httpProtocol" overrideModeDefault="Allow" />
+            <section name="httpRedirect" overrideModeDefault="Allow" />
+            <section name="httpTracing" overrideModeDefault="Deny" />
+            <section name="isapiFilters" allowDefinition="MachineToApplication" overrideModeDefault="Deny" />
+            <section name="modules" allowDefinition="MachineToApplication" overrideModeDefault="Deny" />
+            <section name="odbcLogging" overrideModeDefault="Deny" />
+            <sectionGroup name="security">
+                <section name="access" overrideModeDefault="Deny" />
+                <section name="applicationDependencies" overrideModeDefault="Deny" />
+                <sectionGroup name="authentication">
+                    <section name="anonymousAuthentication" overrideModeDefault="Deny" />
+                    <section name="basicAuthentication" overrideModeDefault="Deny" />
+                    <section name="clientCertificateMappingAuthentication" overrideModeDefault="Deny" />
+                    <section name="digestAuthentication" overrideModeDefault="Deny" />
+                    <section name="iisClientCertificateMappingAuthentication" overrideModeDefault="Deny" />
+                    <section name="windowsAuthentication" overrideModeDefault="Deny" />
+                </sectionGroup>
+                <section name="authorization" overrideModeDefault="Allow" />
+                <section name="ipSecurity" overrideModeDefault="Deny" />
+                <section name="dynamicIpSecurity" overrideModeDefault="Deny" />
+                <section name="isapiCgiRestriction" allowDefinition="AppHostOnly" overrideModeDefault="Deny" />
+                <section name="requestFiltering" overrideModeDefault="Allow" />
+            </sectionGroup>
+            <section name="serverRuntime" overrideModeDefault="Deny" />
+            <section name="serverSideInclude" overrideModeDefault="Deny" />
+            <section name="staticContent" overrideModeDefault="Allow" />
+            <sectionGroup name="tracing">
+                <section name="traceFailedRequests" overrideModeDefault="Allow" />
+                <section name="traceProviderDefinitions" overrideModeDefault="Deny" />
+            </sectionGroup>
+            <section name="urlCompression" overrideModeDefault="Allow" />
+            <section name="validation" overrideModeDefault="Allow" />
+            <sectionGroup name="webdav">
+                <section name="globalSettings" overrideModeDefault="Deny" />
+                <section name="authoring" overrideModeDefault="Deny" />
+                <section name="authoringRules" overrideModeDefault="Deny" />
+            </sectionGroup>
+            <sectionGroup name="rewrite">
+                <section name="allowedServerVariables" overrideModeDefault="Deny" />
+                <section name="rules" overrideModeDefault="Allow" />
+                <section name="outboundRules" overrideModeDefault="Allow" />
+                <section name="globalRules" overrideModeDefault="Deny" allowDefinition="AppHostOnly" />
+                <section name="providers" overrideModeDefault="Allow" />
+                <section name="rewriteMaps" overrideModeDefault="Allow" />
+            </sectionGroup>
+            <section name="applicationInitialization" allowDefinition="MachineToApplication" overrideModeDefault="Allow" />
+            <section name="webSocket" overrideModeDefault="Deny" />
+            <section name="aspNetCore" overrideModeDefault="Allow" />
+        </sectionGroup>
+    </configSections>
+
+    <configProtectedData>
+        <providers>
+            <add name="IISWASOnlyRsaProvider" type="" description="Uses RsaCryptoServiceProvider to encrypt and decrypt" keyContainerName="iisWasKey" cspProviderName="" useMachineContainer="true" useOAEP="false" />
+            <add name="AesProvider" type="Microsoft.ApplicationHost.AesProtectedConfigurationProvider" description="Uses an AES session key to encrypt and decrypt" keyContainerName="iisConfigurationKey" cspProviderName="" useOAEP="false" useMachineContainer="true" sessionKey="AQIAAA5mAAAApAAAKmFQvWHDEETRz8l2bjZlRxIkwcqTFaCUnCLljn3Q1OkesrhEO9YyLyx4bUhsj1/DyShAv7OAFFhXlrlomaornnk5PLeyO4lIXxaiT33yOFUUgxDx4GSaygkqghVV0tO5yQ/XguUBp2juMfZyztnsNa4pLcz7ZNZQ6p4yn9hxwNs=" />
+            <add name="IISWASOnlyAesProvider" type="Microsoft.ApplicationHost.AesProtectedConfigurationProvider" description="Uses an AES session key to encrypt and decrypt" keyContainerName="iisWasKey" cspProviderName="" useOAEP="false" useMachineContainer="true" sessionKey="AQIAAA5mAAAApAAA4WoiRJ8KHwzAG8AgejPxEOO4/2Vhkolbwo/8gZeNdUDSD36m55hWv4uC9tr/MlKdnwRLL0NhT50Gccyftqz5xTZ0dg5FtvQhTw/he1NwexTKbV+I4Zrd+sZUqHZTsr7JiEr6OHGXL70qoISW5G2m9U8wKT3caPiDPNj2aAaYPLo=" />
+        </providers>
+    </configProtectedData>
+
+    <system.applicationHost>
+
+        <applicationPools>
+            <add name="Clr4IntegratedAppPool" managedRuntimeVersion="v4.0" managedPipelineMode="Integrated" CLRConfigFile="%IIS_BIN%\config\templates\PersonalWebServer\aspnet.config" autoStart="true" />
+            <add name="Clr4ClassicAppPool" managedRuntimeVersion="v4.0" managedPipelineMode="Classic" CLRConfigFile="%IIS_BIN%\config\templates\PersonalWebServer\aspnet.config" autoStart="true" />
+            <add name="Clr2IntegratedAppPool" managedRuntimeVersion="v2.0" managedPipelineMode="Integrated" CLRConfigFile="%IIS_BIN%\config\templates\PersonalWebServer\aspnet.config" autoStart="true" />
+            <add name="Clr2ClassicAppPool" managedRuntimeVersion="v2.0" managedPipelineMode="Classic" CLRConfigFile="%IIS_BIN%\config\templates\PersonalWebServer\aspnet.config" autoStart="true" />
+            <add name="UnmanagedClassicAppPool" managedRuntimeVersion="" managedPipelineMode="Classic" autoStart="true" />
+            <add name="IISExpressAppPool" managedRuntimeVersion="v4.0" managedPipelineMode="Integrated" CLRConfigFile="%IIS_BIN%\config\templates\PersonalWebServer\aspnet.config" autoStart="true" />
+            <applicationPoolDefaults managedRuntimeLoader="v4.0">
+                <processModel />
+            </applicationPoolDefaults>
+        </applicationPools>
+
+        <!--
+
+          The <listenerAdapters> section defines the protocols with which the
+          Windows Process Activation Service (WAS) binds.
+
+        -->
+        <listenerAdapters>
+            <add name="http" />
+        </listenerAdapters>
+
+        <sites>
+            <site name="HttpTestSite" id="1" serverAutoStart="true">
+                <application path="/">
+                    <virtualDirectory path="/" physicalPath="[ApplicationPhysicalPath]" />
+                </application>
+                <bindings>
+                    <binding protocol="http" bindingInformation=":[PORT]:localhost" />
+                </bindings>
+            </site>
+            <siteDefaults>
+                <logFile logFormat="W3C" directory="%IIS_USER_HOME%\Logs" />
+                <traceFailedRequestsLogging directory="%IIS_USER_HOME%\TraceLogFiles" enabled="true" maxLogFileSizeKB="1024" />
+            </siteDefaults>
+            <applicationDefaults applicationPool="IISExpressAppPool" />
+            <virtualDirectoryDefaults allowSubDirConfig="true" />
+        </sites>
+
+        <webLimits />
+
+    </system.applicationHost>
+
+    <system.webServer>
+
+        <serverRuntime />
+
+        <asp scriptErrorSentToBrowser="true">
+            <cache diskTemplateCacheDirectory="%TEMP%\iisexpress\ASP Compiled Templates" />
+            <limits />
+        </asp>
+
+        <caching enabled="true" enableKernelCache="true">
+        </caching>
+
+        <cgi />
+
+        <defaultDocument enabled="true">
+            <files>
+                <add value="Default.htm" />
+                <add value="Default.asp" />
+                <add value="index.htm" />
+                <add value="index.html" />
+                <add value="iisstart.htm" />
+                <add value="default.aspx" />
+            </files>
+        </defaultDocument>
+
+        <directoryBrowse enabled="false" />
+
+        <fastCgi />
+
+        <!--
+
+          The <globalModules> section defines all native-code modules.
+          To enable a module, specify it in the <modules> section.
+
+        -->
+        <globalModules>
+            <add name="UriCacheModule" image="%IIS_BIN%\cachuri.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="DynamicCompressionModule" image="%IIS_BIN%\compdyn.dll" />
+            <add name="StaticCompressionModule" image="%IIS_BIN%\compstat.dll" />
+            <add name="DefaultDocumentModule" image="%IIS_BIN%\defdoc.dll" />
+            <add name="DirectoryListingModule" image="%IIS_BIN%\dirlist.dll" />
+            <add name="ProtocolSupportModule" image="%IIS_BIN%\protsup.dll" />
+            <add name="HttpRedirectionModule" image="%IIS_BIN%\redirect.dll" />
+            <add name="ServerSideIncludeModule" image="%IIS_BIN%\iis_ssi.dll" />
+            <add name="StaticFileModule" image="%IIS_BIN%\static.dll" />
+            <add name="AnonymousAuthenticationModule" image="%IIS_BIN%\authanon.dll" />
+            <add name="CertificateMappingAuthenticationModule" image="%IIS_BIN%\authcert.dll" />
+            <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="IISCertificateMappingAuthenticationModule" image="%IIS_BIN%\authmap.dll" />
+            <add name="IpRestrictionModule" image="%IIS_BIN%\iprestr.dll" />
+            <add name="DynamicIpRestrictionModule" image="%IIS_BIN%\diprestr.dll" />
+            <add name="RequestFilteringModule" image="%IIS_BIN%\modrqflt.dll" />
+            <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="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="RewriteModule" image="%IIS_BIN%\rewrite.dll" />
+            <add name="ConfigurationValidationModule" image="%IIS_BIN%\validcfg.dll" />
+            <add name="ApplicationInitializationModule" image="%IIS_BIN%\warmup.dll" />
+            <add name="WebSocketModule" image="%IIS_BIN%\iiswsock.dll" />
+            <add name="WebMatrixSupportModule" image="%IIS_BIN%\webmatrixsup.dll" />
+            <add name="ManagedEngine" image="%windir%\Microsoft.NET\Framework\v2.0.50727\webengine.dll" preCondition="integratedMode,runtimeVersionv2.0,bitness32" />
+            <add name="ManagedEngine64" image="%windir%\Microsoft.NET\Framework64\v2.0.50727\webengine.dll" preCondition="integratedMode,runtimeVersionv2.0,bitness64" />
+            <add name="ManagedEngineV4.0_32bit" image="%windir%\Microsoft.NET\Framework\v4.0.30319\webengine4.dll" preCondition="integratedMode,runtimeVersionv4.0,bitness32" />
+            <add name="ManagedEngineV4.0_64bit" image="%windir%\Microsoft.NET\Framework64\v4.0.30319\webengine4.dll" preCondition="integratedMode,runtimeVersionv4.0,bitness64" />
+            <add name="AspNetCoreModule" image="[ANCMPath]" />
+        </globalModules>
+
+        <httpCompression directory="%TEMP%\iisexpress\IIS Temporary Compressed Files">
+            <scheme name="gzip" dll="%IIS_BIN%\gzip.dll" />
+            <dynamicTypes>
+                <add mimeType="text/*" enabled="true" />
+                <add mimeType="message/*" enabled="true" />
+                <add mimeType="application/x-javascript" enabled="true" />
+                <add mimeType="*/*" enabled="false" />
+            </dynamicTypes>
+            <staticTypes>
+                <add mimeType="text/*" enabled="true" />
+                <add mimeType="message/*" enabled="true" />
+                <add mimeType="application/x-javascript" enabled="true" />
+                <add mimeType="application/atom+xml" enabled="true" />
+                <add mimeType="application/xaml+xml" enabled="true" />
+                <add mimeType="*/*" enabled="false" />
+            </staticTypes>
+        </httpCompression>
+
+        <httpErrors lockAttributes="allowAbsolutePathsWhenDelegated,defaultPath">
+            <error statusCode="401" prefixLanguageFilePath="%IIS_BIN%\custerr" path="401.htm" />
+            <error statusCode="403" prefixLanguageFilePath="%IIS_BIN%\custerr" path="403.htm" />
+            <error statusCode="404" prefixLanguageFilePath="%IIS_BIN%\custerr" path="404.htm" />
+            <error statusCode="405" prefixLanguageFilePath="%IIS_BIN%\custerr" path="405.htm" />
+            <error statusCode="406" prefixLanguageFilePath="%IIS_BIN%\custerr" path="406.htm" />
+            <error statusCode="412" prefixLanguageFilePath="%IIS_BIN%\custerr" path="412.htm" />
+            <error statusCode="500" prefixLanguageFilePath="%IIS_BIN%\custerr" path="500.htm" />
+            <error statusCode="501" prefixLanguageFilePath="%IIS_BIN%\custerr" path="501.htm" />
+            <error statusCode="502" prefixLanguageFilePath="%IIS_BIN%\custerr" path="502.htm" />
+        </httpErrors>
+
+        <httpLogging dontLog="false" />
+
+        <httpProtocol>
+            <customHeaders>
+                <clear />
+                <add name="X-Powered-By" value="ASP.NET" />
+            </customHeaders>
+            <redirectHeaders>
+                <clear />
+            </redirectHeaders>
+        </httpProtocol>
+
+        <httpRedirect enabled="false" />
+
+        <httpTracing>
+        </httpTracing>
+
+        <isapiFilters>
+            <filter name="ASP.Net_2.0.50727-64" path="%windir%\Microsoft.NET\Framework64\v2.0.50727\aspnet_filter.dll" enableCache="true" preCondition="bitness64,runtimeVersionv2.0" />
+            <filter name="ASP.Net_2.0.50727.0" path="%windir%\Microsoft.NET\Framework\v2.0.50727\aspnet_filter.dll" enableCache="true" preCondition="bitness32,runtimeVersionv2.0" />
+            <filter name="ASP.Net_2.0_for_v1.1" path="%windir%\Microsoft.NET\Framework\v2.0.50727\aspnet_filter.dll" enableCache="true" preCondition="runtimeVersionv1.1" />
+            <filter name="ASP.Net_4.0_32bit" path="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_filter.dll" enableCache="true" preCondition="bitness32,runtimeVersionv4.0" />
+            <filter name="ASP.Net_4.0_64bit" path="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_filter.dll" enableCache="true" preCondition="bitness64,runtimeVersionv4.0" />
+        </isapiFilters>
+
+        <odbcLogging />
+
+        <security>
+
+            <access sslFlags="None" />
+
+            <applicationDependencies>
+                <application name="Active Server Pages" groupId="ASP" />
+            </applicationDependencies>
+
+            <authentication>
+
+                <anonymousAuthentication enabled="true" userName="" />
+
+                <basicAuthentication enabled="false" />
+
+                <clientCertificateMappingAuthentication enabled="false" />
+
+                <digestAuthentication enabled="false" />
+
+                <iisClientCertificateMappingAuthentication enabled="false">
+                </iisClientCertificateMappingAuthentication>
+
+                <windowsAuthentication enabled="false">
+                    <providers>
+                        <add value="Negotiate" />
+                        <add value="NTLM" />
+                    </providers>
+                </windowsAuthentication>
+
+            </authentication>
+
+            <authorization>
+                <add accessType="Allow" users="*" />
+            </authorization>
+
+            <ipSecurity allowUnlisted="true" />
+
+            <isapiCgiRestriction notListedIsapisAllowed="true" notListedCgisAllowed="true">
+                <add path="%windir%\Microsoft.NET\Framework64\v4.0.30319\webengine4.dll" allowed="true" groupId="ASP.NET_v4.0" description="ASP.NET_v4.0" />
+                <add path="%windir%\Microsoft.NET\Framework\v4.0.30319\webengine4.dll" allowed="true" groupId="ASP.NET_v4.0" description="ASP.NET_v4.0" />
+                <add path="%windir%\Microsoft.NET\Framework64\v2.0.50727\aspnet_isapi.dll" allowed="true" groupId="ASP.NET v2.0.50727" description="ASP.NET v2.0.50727" />
+                <add path="%windir%\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll" allowed="true" groupId="ASP.NET v2.0.50727" description="ASP.NET v2.0.50727" />
+            </isapiCgiRestriction>
+
+            <requestFiltering>
+                <fileExtensions allowUnlisted="true" applyToWebDAV="true">
+                    <add fileExtension=".asa" allowed="false" />
+                    <add fileExtension=".asax" allowed="false" />
+                    <add fileExtension=".ascx" allowed="false" />
+                    <add fileExtension=".master" allowed="false" />
+                    <add fileExtension=".skin" allowed="false" />
+                    <add fileExtension=".browser" allowed="false" />
+                    <add fileExtension=".sitemap" allowed="false" />
+                    <add fileExtension=".config" allowed="false" />
+                    <add fileExtension=".cs" allowed="false" />
+                    <add fileExtension=".csproj" allowed="false" />
+                    <add fileExtension=".vb" allowed="false" />
+                    <add fileExtension=".vbproj" allowed="false" />
+                    <add fileExtension=".webinfo" allowed="false" />
+                    <add fileExtension=".licx" allowed="false" />
+                    <add fileExtension=".resx" allowed="false" />
+                    <add fileExtension=".resources" allowed="false" />
+                    <add fileExtension=".mdb" allowed="false" />
+                    <add fileExtension=".vjsproj" allowed="false" />
+                    <add fileExtension=".java" allowed="false" />
+                    <add fileExtension=".jsl" allowed="false" />
+                    <add fileExtension=".ldb" allowed="false" />
+                    <add fileExtension=".dsdgm" allowed="false" />
+                    <add fileExtension=".ssdgm" allowed="false" />
+                    <add fileExtension=".lsad" allowed="false" />
+                    <add fileExtension=".ssmap" allowed="false" />
+                    <add fileExtension=".cd" allowed="false" />
+                    <add fileExtension=".dsprototype" allowed="false" />
+                    <add fileExtension=".lsaprototype" allowed="false" />
+                    <add fileExtension=".sdm" allowed="false" />
+                    <add fileExtension=".sdmDocument" allowed="false" />
+                    <add fileExtension=".mdf" allowed="false" />
+                    <add fileExtension=".ldf" allowed="false" />
+                    <add fileExtension=".ad" allowed="false" />
+                    <add fileExtension=".dd" allowed="false" />
+                    <add fileExtension=".ldd" allowed="false" />
+                    <add fileExtension=".sd" allowed="false" />
+                    <add fileExtension=".adprototype" allowed="false" />
+                    <add fileExtension=".lddprototype" allowed="false" />
+                    <add fileExtension=".exclude" allowed="false" />
+                    <add fileExtension=".refresh" allowed="false" />
+                    <add fileExtension=".compiled" allowed="false" />
+                    <add fileExtension=".msgx" allowed="false" />
+                    <add fileExtension=".vsdisco" allowed="false" />
+                    <add fileExtension=".rules" allowed="false" />
+                </fileExtensions>
+                <verbs allowUnlisted="true" applyToWebDAV="true" />
+                <hiddenSegments applyToWebDAV="true">
+                    <add segment="web.config" />
+                    <add segment="bin" />
+                    <add segment="App_code" />
+                    <add segment="App_GlobalResources" />
+                    <add segment="App_LocalResources" />
+                    <add segment="App_WebReferences" />
+                    <add segment="App_Data" />
+                    <add segment="App_Browsers" />
+                </hiddenSegments>
+            </requestFiltering>
+
+        </security>
+
+        <serverSideInclude ssiExecDisable="false" />
+
+        <staticContent lockAttributes="isDocFooterFileName">
+            <mimeMap fileExtension=".323" mimeType="text/h323" />
+            <mimeMap fileExtension=".3g2" mimeType="video/3gpp2" />
+            <mimeMap fileExtension=".3gp2" mimeType="video/3gpp2" />
+            <mimeMap fileExtension=".3gp" mimeType="video/3gpp" />
+            <mimeMap fileExtension=".3gpp" mimeType="video/3gpp" />
+            <mimeMap fileExtension=".aac" mimeType="audio/aac" />
+            <mimeMap fileExtension=".aaf" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".aca" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".accdb" mimeType="application/msaccess" />
+            <mimeMap fileExtension=".accde" mimeType="application/msaccess" />
+            <mimeMap fileExtension=".accdt" mimeType="application/msaccess" />
+            <mimeMap fileExtension=".acx" mimeType="application/internet-property-stream" />
+            <mimeMap fileExtension=".adt" mimeType="audio/vnd.dlna.adts" />
+            <mimeMap fileExtension=".adts" mimeType="audio/vnd.dlna.adts" />
+            <mimeMap fileExtension=".afm" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".ai" mimeType="application/postscript" />
+            <mimeMap fileExtension=".aif" mimeType="audio/x-aiff" />
+            <mimeMap fileExtension=".aifc" mimeType="audio/aiff" />
+            <mimeMap fileExtension=".aiff" mimeType="audio/aiff" />
+            <mimeMap fileExtension=".application" mimeType="application/x-ms-application" />
+            <mimeMap fileExtension=".art" mimeType="image/x-jg" />
+            <mimeMap fileExtension=".asd" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".asf" mimeType="video/x-ms-asf" />
+            <mimeMap fileExtension=".asi" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".asm" mimeType="text/plain" />
+            <mimeMap fileExtension=".asr" mimeType="video/x-ms-asf" />
+            <mimeMap fileExtension=".asx" mimeType="video/x-ms-asf" />
+            <mimeMap fileExtension=".atom" mimeType="application/atom+xml" />
+            <mimeMap fileExtension=".au" mimeType="audio/basic" />
+            <mimeMap fileExtension=".avi" mimeType="video/x-msvideo" />
+            <mimeMap fileExtension=".axs" mimeType="application/olescript" />
+            <mimeMap fileExtension=".bas" mimeType="text/plain" />
+            <mimeMap fileExtension=".bcpio" mimeType="application/x-bcpio" />
+            <mimeMap fileExtension=".bin" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".bmp" mimeType="image/bmp" />
+            <mimeMap fileExtension=".c" mimeType="text/plain" />
+            <mimeMap fileExtension=".cab" mimeType="application/vnd.ms-cab-compressed" />
+            <mimeMap fileExtension=".calx" mimeType="application/vnd.ms-office.calx" />
+            <mimeMap fileExtension=".cat" mimeType="application/vnd.ms-pki.seccat" />
+            <mimeMap fileExtension=".cdf" mimeType="application/x-cdf" />
+            <mimeMap fileExtension=".chm" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".class" mimeType="application/x-java-applet" />
+            <mimeMap fileExtension=".clp" mimeType="application/x-msclip" />
+            <mimeMap fileExtension=".cmx" mimeType="image/x-cmx" />
+            <mimeMap fileExtension=".cnf" mimeType="text/plain" />
+            <mimeMap fileExtension=".cod" mimeType="image/cis-cod" />
+            <mimeMap fileExtension=".cpio" mimeType="application/x-cpio" />
+            <mimeMap fileExtension=".cpp" mimeType="text/plain" />
+            <mimeMap fileExtension=".crd" mimeType="application/x-mscardfile" />
+            <mimeMap fileExtension=".crl" mimeType="application/pkix-crl" />
+            <mimeMap fileExtension=".crt" mimeType="application/x-x509-ca-cert" />
+            <mimeMap fileExtension=".csh" mimeType="application/x-csh" />
+            <mimeMap fileExtension=".css" mimeType="text/css" />
+            <mimeMap fileExtension=".csv" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".cur" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".dcr" mimeType="application/x-director" />
+            <mimeMap fileExtension=".deploy" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".der" mimeType="application/x-x509-ca-cert" />
+            <mimeMap fileExtension=".dib" mimeType="image/bmp" />
+            <mimeMap fileExtension=".dir" mimeType="application/x-director" />
+            <mimeMap fileExtension=".disco" mimeType="text/xml" />
+            <mimeMap fileExtension=".dll" mimeType="application/x-msdownload" />
+            <mimeMap fileExtension=".dll.config" mimeType="text/xml" />
+            <mimeMap fileExtension=".dlm" mimeType="text/dlm" />
+            <mimeMap fileExtension=".doc" mimeType="application/msword" />
+            <mimeMap fileExtension=".docm" mimeType="application/vnd.ms-word.document.macroEnabled.12" />
+            <mimeMap fileExtension=".docx" mimeType="application/vnd.openxmlformats-officedocument.wordprocessingml.document" />
+            <mimeMap fileExtension=".dot" mimeType="application/msword" />
+            <mimeMap fileExtension=".dotm" mimeType="application/vnd.ms-word.template.macroEnabled.12" />
+            <mimeMap fileExtension=".dotx" mimeType="application/vnd.openxmlformats-officedocument.wordprocessingml.template" />
+            <mimeMap fileExtension=".dsp" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".dtd" mimeType="text/xml" />
+            <mimeMap fileExtension=".dvi" mimeType="application/x-dvi" />
+            <mimeMap fileExtension=".dvr-ms" mimeType="video/x-ms-dvr" />
+            <mimeMap fileExtension=".dwf" mimeType="drawing/x-dwf" />
+            <mimeMap fileExtension=".dwp" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".dxr" mimeType="application/x-director" />
+            <mimeMap fileExtension=".eml" mimeType="message/rfc822" />
+            <mimeMap fileExtension=".emz" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".eot" mimeType="application/vnd.ms-fontobject" />
+            <mimeMap fileExtension=".eps" mimeType="application/postscript" />
+            <mimeMap fileExtension=".etx" mimeType="text/x-setext" />
+            <mimeMap fileExtension=".evy" mimeType="application/envoy" />
+            <mimeMap fileExtension=".exe" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".exe.config" mimeType="text/xml" />
+            <mimeMap fileExtension=".fdf" mimeType="application/vnd.fdf" />
+            <mimeMap fileExtension=".fif" mimeType="application/fractals" />
+            <mimeMap fileExtension=".fla" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".flr" mimeType="x-world/x-vrml" />
+            <mimeMap fileExtension=".flv" mimeType="video/x-flv" />
+            <mimeMap fileExtension=".gif" mimeType="image/gif" />
+            <mimeMap fileExtension=".gtar" mimeType="application/x-gtar" />
+            <mimeMap fileExtension=".gz" mimeType="application/x-gzip" />
+            <mimeMap fileExtension=".h" mimeType="text/plain" />
+            <mimeMap fileExtension=".hdf" mimeType="application/x-hdf" />
+            <mimeMap fileExtension=".hdml" mimeType="text/x-hdml" />
+            <mimeMap fileExtension=".hhc" mimeType="application/x-oleobject" />
+            <mimeMap fileExtension=".hhk" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".hhp" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".hlp" mimeType="application/winhlp" />
+            <mimeMap fileExtension=".hqx" mimeType="application/mac-binhex40" />
+            <mimeMap fileExtension=".hta" mimeType="application/hta" />
+            <mimeMap fileExtension=".htc" mimeType="text/x-component" />
+            <mimeMap fileExtension=".htm" mimeType="text/html" />
+            <mimeMap fileExtension=".html" mimeType="text/html" />
+            <mimeMap fileExtension=".htt" mimeType="text/webviewhtml" />
+            <mimeMap fileExtension=".hxt" mimeType="text/html" />
+            <mimeMap fileExtension=".ical" mimeType="text/calendar" />
+            <mimeMap fileExtension=".icalendar" mimeType="text/calendar" />
+            <mimeMap fileExtension=".ico" mimeType="image/x-icon" />
+            <mimeMap fileExtension=".ics" mimeType="text/calendar" />
+            <mimeMap fileExtension=".ief" mimeType="image/ief" />
+            <mimeMap fileExtension=".ifb" mimeType="text/calendar" />
+            <mimeMap fileExtension=".iii" mimeType="application/x-iphone" />
+            <mimeMap fileExtension=".inf" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".ins" mimeType="application/x-internet-signup" />
+            <mimeMap fileExtension=".isp" mimeType="application/x-internet-signup" />
+            <mimeMap fileExtension=".IVF" mimeType="video/x-ivf" />
+            <mimeMap fileExtension=".jar" mimeType="application/java-archive" />
+            <mimeMap fileExtension=".java" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".jck" mimeType="application/liquidmotion" />
+            <mimeMap fileExtension=".jcz" mimeType="application/liquidmotion" />
+            <mimeMap fileExtension=".jfif" mimeType="image/pjpeg" />
+            <mimeMap fileExtension=".jpb" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".jpe" mimeType="image/jpeg" />
+            <mimeMap fileExtension=".jpeg" mimeType="image/jpeg" />
+            <mimeMap fileExtension=".jpg" mimeType="image/jpeg" />
+            <mimeMap fileExtension=".js" mimeType="application/javascript" />
+            <mimeMap fileExtension=".jsx" mimeType="text/jscript" />
+            <mimeMap fileExtension=".latex" mimeType="application/x-latex" />
+            <mimeMap fileExtension=".lit" mimeType="application/x-ms-reader" />
+            <mimeMap fileExtension=".lpk" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".lsf" mimeType="video/x-la-asf" />
+            <mimeMap fileExtension=".lsx" mimeType="video/x-la-asf" />
+            <mimeMap fileExtension=".lzh" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".m13" mimeType="application/x-msmediaview" />
+            <mimeMap fileExtension=".m14" mimeType="application/x-msmediaview" />
+            <mimeMap fileExtension=".m1v" mimeType="video/mpeg" />
+            <mimeMap fileExtension=".m2ts" mimeType="video/vnd.dlna.mpeg-tts" />
+            <mimeMap fileExtension=".m3u" mimeType="audio/x-mpegurl" />
+            <mimeMap fileExtension=".m4a" mimeType="audio/mp4" />
+            <mimeMap fileExtension=".m4v" mimeType="video/mp4" />
+            <mimeMap fileExtension=".man" mimeType="application/x-troff-man" />
+            <mimeMap fileExtension=".manifest" mimeType="application/x-ms-manifest" />
+            <mimeMap fileExtension=".map" mimeType="text/plain" />
+            <mimeMap fileExtension=".mdb" mimeType="application/x-msaccess" />
+            <mimeMap fileExtension=".mdp" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".me" mimeType="application/x-troff-me" />
+            <mimeMap fileExtension=".mht" mimeType="message/rfc822" />
+            <mimeMap fileExtension=".mhtml" mimeType="message/rfc822" />
+            <mimeMap fileExtension=".mid" mimeType="audio/mid" />
+            <mimeMap fileExtension=".midi" mimeType="audio/mid" />
+            <mimeMap fileExtension=".mix" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".mmf" mimeType="application/x-smaf" />
+            <mimeMap fileExtension=".mno" mimeType="text/xml" />
+            <mimeMap fileExtension=".mny" mimeType="application/x-msmoney" />
+            <mimeMap fileExtension=".mov" mimeType="video/quicktime" />
+            <mimeMap fileExtension=".movie" mimeType="video/x-sgi-movie" />
+            <mimeMap fileExtension=".mp2" mimeType="video/mpeg" />
+            <mimeMap fileExtension=".mp3" mimeType="audio/mpeg" />
+            <mimeMap fileExtension=".mp4" mimeType="video/mp4" />
+            <mimeMap fileExtension=".mp4v" mimeType="video/mp4" />
+            <mimeMap fileExtension=".mpa" mimeType="video/mpeg" />
+            <mimeMap fileExtension=".mpe" mimeType="video/mpeg" />
+            <mimeMap fileExtension=".mpeg" mimeType="video/mpeg" />
+            <mimeMap fileExtension=".mpg" mimeType="video/mpeg" />
+            <mimeMap fileExtension=".mpp" mimeType="application/vnd.ms-project" />
+            <mimeMap fileExtension=".mpv2" mimeType="video/mpeg" />
+            <mimeMap fileExtension=".ms" mimeType="application/x-troff-ms" />
+            <mimeMap fileExtension=".msi" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".mso" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".mvb" mimeType="application/x-msmediaview" />
+            <mimeMap fileExtension=".mvc" mimeType="application/x-miva-compiled" />
+            <mimeMap fileExtension=".nc" mimeType="application/x-netcdf" />
+            <mimeMap fileExtension=".nsc" mimeType="video/x-ms-asf" />
+            <mimeMap fileExtension=".nws" mimeType="message/rfc822" />
+            <mimeMap fileExtension=".ocx" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".oda" mimeType="application/oda" />
+            <mimeMap fileExtension=".odc" mimeType="text/x-ms-odc" />
+            <mimeMap fileExtension=".ods" mimeType="application/oleobject" />
+            <mimeMap fileExtension=".oga" mimeType="audio/ogg" />
+            <mimeMap fileExtension=".ogg" mimeType="video/ogg" />
+            <mimeMap fileExtension=".ogv" mimeType="video/ogg" />
+            <mimeMap fileExtension=".ogx" mimeType="application/ogg" />
+            <mimeMap fileExtension=".one" mimeType="application/onenote" />
+            <mimeMap fileExtension=".onea" mimeType="application/onenote" />
+            <mimeMap fileExtension=".onetoc" mimeType="application/onenote" />
+            <mimeMap fileExtension=".onetoc2" mimeType="application/onenote" />
+            <mimeMap fileExtension=".onetmp" mimeType="application/onenote" />
+            <mimeMap fileExtension=".onepkg" mimeType="application/onenote" />
+            <mimeMap fileExtension=".osdx" mimeType="application/opensearchdescription+xml" />
+            <mimeMap fileExtension=".otf" mimeType="font/otf" />
+            <mimeMap fileExtension=".p10" mimeType="application/pkcs10" />
+            <mimeMap fileExtension=".p12" mimeType="application/x-pkcs12" />
+            <mimeMap fileExtension=".p7b" mimeType="application/x-pkcs7-certificates" />
+            <mimeMap fileExtension=".p7c" mimeType="application/pkcs7-mime" />
+            <mimeMap fileExtension=".p7m" mimeType="application/pkcs7-mime" />
+            <mimeMap fileExtension=".p7r" mimeType="application/x-pkcs7-certreqresp" />
+            <mimeMap fileExtension=".p7s" mimeType="application/pkcs7-signature" />
+            <mimeMap fileExtension=".pbm" mimeType="image/x-portable-bitmap" />
+            <mimeMap fileExtension=".pcx" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".pcz" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".pdf" mimeType="application/pdf" />
+            <mimeMap fileExtension=".pfb" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".pfm" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".pfx" mimeType="application/x-pkcs12" />
+            <mimeMap fileExtension=".pgm" mimeType="image/x-portable-graymap" />
+            <mimeMap fileExtension=".pko" mimeType="application/vnd.ms-pki.pko" />
+            <mimeMap fileExtension=".pma" mimeType="application/x-perfmon" />
+            <mimeMap fileExtension=".pmc" mimeType="application/x-perfmon" />
+            <mimeMap fileExtension=".pml" mimeType="application/x-perfmon" />
+            <mimeMap fileExtension=".pmr" mimeType="application/x-perfmon" />
+            <mimeMap fileExtension=".pmw" mimeType="application/x-perfmon" />
+            <mimeMap fileExtension=".png" mimeType="image/png" />
+            <mimeMap fileExtension=".pnm" mimeType="image/x-portable-anymap" />
+            <mimeMap fileExtension=".pnz" mimeType="image/png" />
+            <mimeMap fileExtension=".pot" mimeType="application/vnd.ms-powerpoint" />
+            <mimeMap fileExtension=".potm" mimeType="application/vnd.ms-powerpoint.template.macroEnabled.12" />
+            <mimeMap fileExtension=".potx" mimeType="application/vnd.openxmlformats-officedocument.presentationml.template" />
+            <mimeMap fileExtension=".ppam" mimeType="application/vnd.ms-powerpoint.addin.macroEnabled.12" />
+            <mimeMap fileExtension=".ppm" mimeType="image/x-portable-pixmap" />
+            <mimeMap fileExtension=".pps" mimeType="application/vnd.ms-powerpoint" />
+            <mimeMap fileExtension=".ppsm" mimeType="application/vnd.ms-powerpoint.slideshow.macroEnabled.12" />
+            <mimeMap fileExtension=".ppsx" mimeType="application/vnd.openxmlformats-officedocument.presentationml.slideshow" />
+            <mimeMap fileExtension=".ppt" mimeType="application/vnd.ms-powerpoint" />
+            <mimeMap fileExtension=".pptm" mimeType="application/vnd.ms-powerpoint.presentation.macroEnabled.12" />
+            <mimeMap fileExtension=".pptx" mimeType="application/vnd.openxmlformats-officedocument.presentationml.presentation" />
+            <mimeMap fileExtension=".prf" mimeType="application/pics-rules" />
+            <mimeMap fileExtension=".prm" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".prx" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".ps" mimeType="application/postscript" />
+            <mimeMap fileExtension=".psd" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".psm" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".psp" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".pub" mimeType="application/x-mspublisher" />
+            <mimeMap fileExtension=".qt" mimeType="video/quicktime" />
+            <mimeMap fileExtension=".qtl" mimeType="application/x-quicktimeplayer" />
+            <mimeMap fileExtension=".qxd" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".ra" mimeType="audio/x-pn-realaudio" />
+            <mimeMap fileExtension=".ram" mimeType="audio/x-pn-realaudio" />
+            <mimeMap fileExtension=".rar" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".ras" mimeType="image/x-cmu-raster" />
+            <mimeMap fileExtension=".rf" mimeType="image/vnd.rn-realflash" />
+            <mimeMap fileExtension=".rgb" mimeType="image/x-rgb" />
+            <mimeMap fileExtension=".rm" mimeType="application/vnd.rn-realmedia" />
+            <mimeMap fileExtension=".rmi" mimeType="audio/mid" />
+            <mimeMap fileExtension=".roff" mimeType="application/x-troff" />
+            <mimeMap fileExtension=".rpm" mimeType="audio/x-pn-realaudio-plugin" />
+            <mimeMap fileExtension=".rtf" mimeType="application/rtf" />
+            <mimeMap fileExtension=".rtx" mimeType="text/richtext" />
+            <mimeMap fileExtension=".scd" mimeType="application/x-msschedule" />
+            <mimeMap fileExtension=".sct" mimeType="text/scriptlet" />
+            <mimeMap fileExtension=".sea" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".setpay" mimeType="application/set-payment-initiation" />
+            <mimeMap fileExtension=".setreg" mimeType="application/set-registration-initiation" />
+            <mimeMap fileExtension=".sgml" mimeType="text/sgml" />
+            <mimeMap fileExtension=".sh" mimeType="application/x-sh" />
+            <mimeMap fileExtension=".shar" mimeType="application/x-shar" />
+            <mimeMap fileExtension=".sit" mimeType="application/x-stuffit" />
+            <mimeMap fileExtension=".sldm" mimeType="application/vnd.ms-powerpoint.slide.macroEnabled.12" />
+            <mimeMap fileExtension=".sldx" mimeType="application/vnd.openxmlformats-officedocument.presentationml.slide" />
+            <mimeMap fileExtension=".smd" mimeType="audio/x-smd" />
+            <mimeMap fileExtension=".smi" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".smx" mimeType="audio/x-smd" />
+            <mimeMap fileExtension=".smz" mimeType="audio/x-smd" />
+            <mimeMap fileExtension=".snd" mimeType="audio/basic" />
+            <mimeMap fileExtension=".snp" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".spc" mimeType="application/x-pkcs7-certificates" />
+            <mimeMap fileExtension=".spl" mimeType="application/futuresplash" />
+            <mimeMap fileExtension=".spx" mimeType="audio/ogg" />
+            <mimeMap fileExtension=".src" mimeType="application/x-wais-source" />
+            <mimeMap fileExtension=".ssm" mimeType="application/streamingmedia" />
+            <mimeMap fileExtension=".sst" mimeType="application/vnd.ms-pki.certstore" />
+            <mimeMap fileExtension=".stl" mimeType="application/vnd.ms-pki.stl" />
+            <mimeMap fileExtension=".sv4cpio" mimeType="application/x-sv4cpio" />
+            <mimeMap fileExtension=".sv4crc" mimeType="application/x-sv4crc" />
+            <mimeMap fileExtension=".svg" mimeType="image/svg+xml" />
+            <mimeMap fileExtension=".svgz" mimeType="image/svg+xml" />
+            <mimeMap fileExtension=".swf" mimeType="application/x-shockwave-flash" />
+            <mimeMap fileExtension=".t" mimeType="application/x-troff" />
+            <mimeMap fileExtension=".tar" mimeType="application/x-tar" />
+            <mimeMap fileExtension=".tcl" mimeType="application/x-tcl" />
+            <mimeMap fileExtension=".tex" mimeType="application/x-tex" />
+            <mimeMap fileExtension=".texi" mimeType="application/x-texinfo" />
+            <mimeMap fileExtension=".texinfo" mimeType="application/x-texinfo" />
+            <mimeMap fileExtension=".tgz" mimeType="application/x-compressed" />
+            <mimeMap fileExtension=".thmx" mimeType="application/vnd.ms-officetheme" />
+            <mimeMap fileExtension=".thn" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".tif" mimeType="image/tiff" />
+            <mimeMap fileExtension=".tiff" mimeType="image/tiff" />
+            <mimeMap fileExtension=".toc" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".tr" mimeType="application/x-troff" />
+            <mimeMap fileExtension=".trm" mimeType="application/x-msterminal" />
+            <mimeMap fileExtension=".ts" mimeType="video/vnd.dlna.mpeg-tts" />
+            <mimeMap fileExtension=".tsv" mimeType="text/tab-separated-values" />
+            <mimeMap fileExtension=".ttf" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".tts" mimeType="video/vnd.dlna.mpeg-tts" />
+            <mimeMap fileExtension=".txt" mimeType="text/plain" />
+            <mimeMap fileExtension=".u32" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".uls" mimeType="text/iuls" />
+            <mimeMap fileExtension=".ustar" mimeType="application/x-ustar" />
+            <mimeMap fileExtension=".vbs" mimeType="text/vbscript" />
+            <mimeMap fileExtension=".vcf" mimeType="text/x-vcard" />
+            <mimeMap fileExtension=".vcs" mimeType="text/plain" />
+            <mimeMap fileExtension=".vdx" mimeType="application/vnd.ms-visio.viewer" />
+            <mimeMap fileExtension=".vml" mimeType="text/xml" />
+            <mimeMap fileExtension=".vsd" mimeType="application/vnd.visio" />
+            <mimeMap fileExtension=".vss" mimeType="application/vnd.visio" />
+            <mimeMap fileExtension=".vst" mimeType="application/vnd.visio" />
+            <mimeMap fileExtension=".vsto" mimeType="application/x-ms-vsto" />
+            <mimeMap fileExtension=".vsw" mimeType="application/vnd.visio" />
+            <mimeMap fileExtension=".vsx" mimeType="application/vnd.visio" />
+            <mimeMap fileExtension=".vtx" mimeType="application/vnd.visio" />
+            <mimeMap fileExtension=".wav" mimeType="audio/wav" />
+            <mimeMap fileExtension=".wax" mimeType="audio/x-ms-wax" />
+            <mimeMap fileExtension=".wbmp" mimeType="image/vnd.wap.wbmp" />
+            <mimeMap fileExtension=".wcm" mimeType="application/vnd.ms-works" />
+            <mimeMap fileExtension=".wdb" mimeType="application/vnd.ms-works" />
+            <mimeMap fileExtension=".webm" mimeType="video/webm" />
+            <mimeMap fileExtension=".wks" mimeType="application/vnd.ms-works" />
+            <mimeMap fileExtension=".wm" mimeType="video/x-ms-wm" />
+            <mimeMap fileExtension=".wma" mimeType="audio/x-ms-wma" />
+            <mimeMap fileExtension=".wmd" mimeType="application/x-ms-wmd" />
+            <mimeMap fileExtension=".wmf" mimeType="application/x-msmetafile" />
+            <mimeMap fileExtension=".wml" mimeType="text/vnd.wap.wml" />
+            <mimeMap fileExtension=".wmlc" mimeType="application/vnd.wap.wmlc" />
+            <mimeMap fileExtension=".wmls" mimeType="text/vnd.wap.wmlscript" />
+            <mimeMap fileExtension=".wmlsc" mimeType="application/vnd.wap.wmlscriptc" />
+            <mimeMap fileExtension=".wmp" mimeType="video/x-ms-wmp" />
+            <mimeMap fileExtension=".wmv" mimeType="video/x-ms-wmv" />
+            <mimeMap fileExtension=".wmx" mimeType="video/x-ms-wmx" />
+            <mimeMap fileExtension=".wmz" mimeType="application/x-ms-wmz" />
+            <mimeMap fileExtension=".woff" mimeType="font/x-woff" />
+            <mimeMap fileExtension=".wps" mimeType="application/vnd.ms-works" />
+            <mimeMap fileExtension=".wri" mimeType="application/x-mswrite" />
+            <mimeMap fileExtension=".wrl" mimeType="x-world/x-vrml" />
+            <mimeMap fileExtension=".wrz" mimeType="x-world/x-vrml" />
+            <mimeMap fileExtension=".wsdl" mimeType="text/xml" />
+            <mimeMap fileExtension=".wtv" mimeType="video/x-ms-wtv" />
+            <mimeMap fileExtension=".wvx" mimeType="video/x-ms-wvx" />
+            <mimeMap fileExtension=".x" mimeType="application/directx" />
+            <mimeMap fileExtension=".xaf" mimeType="x-world/x-vrml" />
+            <mimeMap fileExtension=".xaml" mimeType="application/xaml+xml" />
+            <mimeMap fileExtension=".xap" mimeType="application/x-silverlight-app" />
+            <mimeMap fileExtension=".xbap" mimeType="application/x-ms-xbap" />
+            <mimeMap fileExtension=".xbm" mimeType="image/x-xbitmap" />
+            <mimeMap fileExtension=".xdr" mimeType="text/plain" />
+            <mimeMap fileExtension=".xht" mimeType="application/xhtml+xml" />
+            <mimeMap fileExtension=".xhtml" mimeType="application/xhtml+xml" />
+            <mimeMap fileExtension=".xla" mimeType="application/vnd.ms-excel" />
+            <mimeMap fileExtension=".xlam" mimeType="application/vnd.ms-excel.addin.macroEnabled.12" />
+            <mimeMap fileExtension=".xlc" mimeType="application/vnd.ms-excel" />
+            <mimeMap fileExtension=".xlm" mimeType="application/vnd.ms-excel" />
+            <mimeMap fileExtension=".xls" mimeType="application/vnd.ms-excel" />
+            <mimeMap fileExtension=".xlsb" mimeType="application/vnd.ms-excel.sheet.binary.macroEnabled.12" />
+            <mimeMap fileExtension=".xlsm" mimeType="application/vnd.ms-excel.sheet.macroEnabled.12" />
+            <mimeMap fileExtension=".xlsx" mimeType="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" />
+            <mimeMap fileExtension=".xlt" mimeType="application/vnd.ms-excel" />
+            <mimeMap fileExtension=".xltm" mimeType="application/vnd.ms-excel.template.macroEnabled.12" />
+            <mimeMap fileExtension=".xltx" mimeType="application/vnd.openxmlformats-officedocument.spreadsheetml.template" />
+            <mimeMap fileExtension=".xlw" mimeType="application/vnd.ms-excel" />
+            <mimeMap fileExtension=".xml" mimeType="text/xml" />
+            <mimeMap fileExtension=".xof" mimeType="x-world/x-vrml" />
+            <mimeMap fileExtension=".xpm" mimeType="image/x-xpixmap" />
+            <mimeMap fileExtension=".xps" mimeType="application/vnd.ms-xpsdocument" />
+            <mimeMap fileExtension=".xsd" mimeType="text/xml" />
+            <mimeMap fileExtension=".xsf" mimeType="text/xml" />
+            <mimeMap fileExtension=".xsl" mimeType="text/xml" />
+            <mimeMap fileExtension=".xslt" mimeType="text/xml" />
+            <mimeMap fileExtension=".xsn" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".xtp" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".xwd" mimeType="image/x-xwindowdump" />
+            <mimeMap fileExtension=".z" mimeType="application/x-compress" />
+            <mimeMap fileExtension=".zip" mimeType="application/x-zip-compressed" />
+        </staticContent>
+
+        <tracing>
+
+            <traceProviderDefinitions>
+                <add name="WWW Server" guid="{3a2a4e84-4c21-4981-ae10-3fda0d9b0f83}">
+                    <areas>
+                        <clear />
+                        <add name="Authentication" value="2" />
+                        <add name="Security" value="4" />
+                        <add name="Filter" value="8" />
+                        <add name="StaticFile" value="16" />
+                        <add name="CGI" value="32" />
+                        <add name="Compression" value="64" />
+                        <add name="Cache" value="128" />
+                        <add name="RequestNotifications" value="256" />
+                        <add name="Module" value="512" />
+                        <add name="Rewrite" value="1024" />
+                        <add name="FastCGI" value="4096" />
+                        <add name="WebSocket" value="16384" />
+                    </areas>
+                </add>
+                <add name="ASP" guid="{06b94d9a-b15e-456e-a4ef-37c984a2cb4b}">
+                    <areas>
+                        <clear />
+                    </areas>
+                </add>
+                <add name="ISAPI Extension" guid="{a1c2040e-8840-4c31-ba11-9871031a19ea}">
+                    <areas>
+                        <clear />
+                    </areas>
+                </add>
+                <add name="ASPNET" guid="{AFF081FE-0247-4275-9C4E-021F3DC1DA35}">
+                    <areas>
+                        <add name="Infrastructure" value="1" />
+                        <add name="Module" value="2" />
+                        <add name="Page" value="4" />
+                        <add name="AppServices" value="8" />
+                    </areas>
+                </add>
+            </traceProviderDefinitions>
+
+            <traceFailedRequests>
+                <add path="*">
+                    <traceAreas>
+                        <add provider="ASP" verbosity="Verbose" />
+                        <add provider="ASPNET" areas="Infrastructure,Module,Page,AppServices" verbosity="Verbose" />
+                        <add provider="ISAPI Extension" verbosity="Verbose" />
+                        <add provider="WWW Server" areas="Authentication,Security,Filter,StaticFile,CGI,Compression,Cache,RequestNotifications,Module,Rewrite,WebSocket" verbosity="Verbose" />
+                    </traceAreas>
+                    <failureDefinitions statusCodes="200-999" />
+                </add>
+            </traceFailedRequests>
+
+        </tracing>
+
+        <urlCompression />
+
+        <validation />
+        <webdav>
+            <globalSettings>
+                <propertyStores>
+                    <add name="webdav_simple_prop" image="%IIS_BIN%\webdav_simple_prop.dll" image32="%IIS_BIN%\webdav_simple_prop.dll" />
+                </propertyStores>
+                <lockStores>
+                    <add name="webdav_simple_lock" image="%IIS_BIN%\webdav_simple_lock.dll" image32="%IIS_BIN%\webdav_simple_lock.dll" />
+                </lockStores>
+
+            </globalSettings>
+            <authoring>
+                <locks enabled="true" lockStore="webdav_simple_lock" />
+            </authoring>
+            <authoringRules />
+        </webdav>
+        <applicationInitialization />
+        <webSocket enabled="false" />
+
+    </system.webServer>
+    <location path="" overrideMode="Allow">
+        <system.webServer>
+            <modules>
+              <add name="IsapiFilterModule" lockItem="true" />
+              <add name="BasicAuthenticationModule" lockItem="true" />
+              <add name="IsapiModule" lockItem="true" />
+              <add name="HttpLoggingModule" lockItem="true" />
+                <!--
+                <add name="HttpCacheModule" lockItem="true" />
+-->
+                <add name="DynamicCompressionModule" lockItem="true" />
+                <add name="StaticCompressionModule" lockItem="true" />
+                <add name="DefaultDocumentModule" lockItem="true" />
+                <add name="DirectoryListingModule" lockItem="true" />
+                <add name="ProtocolSupportModule" lockItem="true" />
+                <add name="HttpRedirectionModule" lockItem="true" />
+                <add name="ServerSideIncludeModule" lockItem="true" />
+                <add name="StaticFileModule" lockItem="true" />
+                <add name="AnonymousAuthenticationModule" lockItem="true" />
+                <add name="CertificateMappingAuthenticationModule" lockItem="true" />
+                <add name="UrlAuthorizationModule" lockItem="true" />
+                <add name="WindowsAuthenticationModule" lockItem="true" />
+                <!--
+                <add name="DigestAuthenticationModule" lockItem="true" />
+-->
+                <add name="IISCertificateMappingAuthenticationModule" lockItem="true" />
+                <add name="WebMatrixSupportModule" lockItem="true" />
+                <add name="IpRestrictionModule" lockItem="true" />
+                <add name="DynamicIpRestrictionModule" lockItem="true" />
+                <add name="RequestFilteringModule" lockItem="true" />
+                <add name="CustomLoggingModule" lockItem="true" />
+                <add name="CustomErrorModule" lockItem="true" />
+                <add name="FailedRequestsTracingModule" lockItem="true" />
+                <add name="CgiModule" lockItem="true" />
+                <add name="FastCgiModule" lockItem="true" />
+                <!--                <add name="WebDAVModule" /> -->
+                <add name="RewriteModule" />
+                <add name="OutputCache" type="System.Web.Caching.OutputCacheModule" preCondition="managedHandler" />
+                <add name="Session" type="System.Web.SessionState.SessionStateModule" preCondition="managedHandler" />
+                <add name="WindowsAuthentication" type="System.Web.Security.WindowsAuthenticationModule" preCondition="managedHandler" />
+                <add name="FormsAuthentication" type="System.Web.Security.FormsAuthenticationModule" preCondition="managedHandler" />
+                <add name="DefaultAuthentication" type="System.Web.Security.DefaultAuthenticationModule" preCondition="managedHandler" />
+                <add name="RoleManager" type="System.Web.Security.RoleManagerModule" preCondition="managedHandler" />
+                <add name="UrlAuthorization" type="System.Web.Security.UrlAuthorizationModule" preCondition="managedHandler" />
+                <add name="FileAuthorization" type="System.Web.Security.FileAuthorizationModule" preCondition="managedHandler" />
+                <add name="AnonymousIdentification" type="System.Web.Security.AnonymousIdentificationModule" preCondition="managedHandler" />
+                <add name="Profile" type="System.Web.Profile.ProfileModule" preCondition="managedHandler" />
+                <add name="UrlMappingsModule" type="System.Web.UrlMappingsModule" preCondition="managedHandler" />
+                <add name="ApplicationInitializationModule" lockItem="true" />
+                <add name="WebSocketModule" lockItem="true" />
+                <add name="ServiceModel-4.0" type="System.ServiceModel.Activation.ServiceHttpModule,System.ServiceModel.Activation,Version=4.0.0.0,Culture=neutral,PublicKeyToken=31bf3856ad364e35" preCondition="managedHandler,runtimeVersionv4.0" />
+                <add name="ConfigurationValidationModule" lockItem="true" />
+                <add name="UrlRoutingModule-4.0" type="System.Web.Routing.UrlRoutingModule" preCondition="managedHandler,runtimeVersionv4.0" />
+                <add name="ScriptModule-4.0" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" preCondition="managedHandler,runtimeVersionv4.0" />
+                <add name="ServiceModel" type="System.ServiceModel.Activation.HttpModule, System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" preCondition="managedHandler,runtimeVersionv2.0" />
+                <add name="AspNetCoreModule" />
+            </modules>
+            <handlers accessPolicy="Read, Script">
+                <!--                <add name="WebDAV" path="*" verb="PROPFIND,PROPPATCH,MKCOL,PUT,COPY,DELETE,MOVE,LOCK,UNLOCK" modules="WebDAVModule" resourceType="Unspecified" requireAccess="None" /> -->
+                <add name="AXD-ISAPI-4.0_64bit" path="*.axd" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
+                <add name="PageHandlerFactory-ISAPI-4.0_64bit" path="*.aspx" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
+                <add name="SimpleHandlerFactory-ISAPI-4.0_64bit" path="*.ashx" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
+                <add name="WebServiceHandlerFactory-ISAPI-4.0_64bit" path="*.asmx" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
+                <add name="HttpRemotingHandlerFactory-rem-ISAPI-4.0_64bit" path="*.rem" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
+                <add name="HttpRemotingHandlerFactory-soap-ISAPI-4.0_64bit" path="*.soap" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
+                <add name="svc-ISAPI-4.0_64bit" path="*.svc" verb="*" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" />
+                <add name="rules-ISAPI-4.0_64bit" path="*.rules" verb="*" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" />
+                <add name="xoml-ISAPI-4.0_64bit" path="*.xoml" verb="*" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" />
+                <add name="xamlx-ISAPI-4.0_64bit" path="*.xamlx" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" />
+                <add name="aspq-ISAPI-4.0_64bit" path="*.aspq" verb="*" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
+                <add name="cshtm-ISAPI-4.0_64bit" path="*.cshtm" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
+                <add name="cshtml-ISAPI-4.0_64bit" path="*.cshtml" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
+                <add name="vbhtm-ISAPI-4.0_64bit" path="*.vbhtm" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
+                <add name="vbhtml-ISAPI-4.0_64bit" path="*.vbhtml" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
+                <add name="svc-Integrated" path="*.svc" verb="*" type="System.ServiceModel.Activation.HttpHandler, System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" preCondition="integratedMode,runtimeVersionv2.0" />
+                <add name="svc-ISAPI-2.0" path="*.svc" verb="*" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness32" />
+                <add name="xoml-Integrated" path="*.xoml" verb="*" type="System.ServiceModel.Activation.HttpHandler, System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" preCondition="integratedMode,runtimeVersionv2.0" />
+                <add name="xoml-ISAPI-2.0" path="*.xoml" verb="*" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness32" />
+                <add name="rules-Integrated" path="*.rules" verb="*" type="System.ServiceModel.Activation.HttpHandler, System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" preCondition="integratedMode,runtimeVersionv2.0" />
+                <add name="rules-ISAPI-2.0" path="*.rules" verb="*" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness32" />
+                <add name="AXD-ISAPI-4.0_32bit" path="*.axd" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
+                <add name="PageHandlerFactory-ISAPI-4.0_32bit" path="*.aspx" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
+                <add name="SimpleHandlerFactory-ISAPI-4.0_32bit" path="*.ashx" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
+                <add name="WebServiceHandlerFactory-ISAPI-4.0_32bit" path="*.asmx" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
+                <add name="HttpRemotingHandlerFactory-rem-ISAPI-4.0_32bit" path="*.rem" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
+                <add name="HttpRemotingHandlerFactory-soap-ISAPI-4.0_32bit" path="*.soap" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
+                <add name="svc-ISAPI-4.0_32bit" path="*.svc" verb="*" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" />
+                <add name="rules-ISAPI-4.0_32bit" path="*.rules" verb="*" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" />
+                <add name="xoml-ISAPI-4.0_32bit" path="*.xoml" verb="*" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" />
+                <add name="xamlx-ISAPI-4.0_32bit" path="*.xamlx" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" />
+                <add name="aspq-ISAPI-4.0_32bit" path="*.aspq" verb="*" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
+                <add name="cshtm-ISAPI-4.0_32bit" path="*.cshtm" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
+                <add name="cshtml-ISAPI-4.0_32bit" path="*.cshtml" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
+                <add name="vbhtm-ISAPI-4.0_32bit" path="*.vbhtm" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
+                <add name="vbhtml-ISAPI-4.0_32bit" path="*.vbhtml" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
+                <add name="TraceHandler-Integrated-4.0" path="trace.axd" verb="GET,HEAD,POST,DEBUG" type="System.Web.Handlers.TraceHandler" preCondition="integratedMode,runtimeVersionv4.0" />
+                <add name="WebAdminHandler-Integrated-4.0" path="WebAdmin.axd" verb="GET,DEBUG" type="System.Web.Handlers.WebAdminHandler" preCondition="integratedMode,runtimeVersionv4.0" />
+                <add name="AssemblyResourceLoader-Integrated-4.0" path="WebResource.axd" verb="GET,DEBUG" type="System.Web.Handlers.AssemblyResourceLoader" preCondition="integratedMode,runtimeVersionv4.0" />
+                <add name="PageHandlerFactory-Integrated-4.0" path="*.aspx" verb="GET,HEAD,POST,DEBUG" type="System.Web.UI.PageHandlerFactory" preCondition="integratedMode,runtimeVersionv4.0" />
+                <add name="SimpleHandlerFactory-Integrated-4.0" path="*.ashx" verb="GET,HEAD,POST,DEBUG" type="System.Web.UI.SimpleHandlerFactory" preCondition="integratedMode,runtimeVersionv4.0" />
+                <add name="WebServiceHandlerFactory-Integrated-4.0" path="*.asmx" verb="GET,HEAD,POST,DEBUG" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" preCondition="integratedMode,runtimeVersionv4.0" />
+                <add name="HttpRemotingHandlerFactory-rem-Integrated-4.0" path="*.rem" verb="GET,HEAD,POST,DEBUG" type="System.Runtime.Remoting.Channels.Http.HttpRemotingHandlerFactory, System.Runtime.Remoting, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" preCondition="integratedMode,runtimeVersionv4.0" />
+                <add name="HttpRemotingHandlerFactory-soap-Integrated-4.0" path="*.soap" verb="GET,HEAD,POST,DEBUG" type="System.Runtime.Remoting.Channels.Http.HttpRemotingHandlerFactory, System.Runtime.Remoting, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" preCondition="integratedMode,runtimeVersionv4.0" />
+                <add name="svc-Integrated-4.0" path="*.svc" verb="*" type="System.ServiceModel.Activation.ServiceHttpHandlerFactory, System.ServiceModel.Activation, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" preCondition="integratedMode,runtimeVersionv4.0" />
+                <add name="rules-Integrated-4.0" path="*.rules" verb="*" type="System.ServiceModel.Activation.ServiceHttpHandlerFactory, System.ServiceModel.Activation, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" preCondition="integratedMode,runtimeVersionv4.0" />
+                <add name="xoml-Integrated-4.0" path="*.xoml" verb="*" type="System.ServiceModel.Activation.ServiceHttpHandlerFactory, System.ServiceModel.Activation, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" preCondition="integratedMode,runtimeVersionv4.0" />
+                <add name="xamlx-Integrated-4.0" path="*.xamlx" verb="GET,HEAD,POST,DEBUG" type="System.Xaml.Hosting.XamlHttpHandlerFactory, System.Xaml.Hosting, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" preCondition="integratedMode,runtimeVersionv4.0" />
+                <add name="aspq-Integrated-4.0" path="*.aspq" verb="GET,HEAD,POST,DEBUG" type="System.Web.HttpForbiddenHandler" preCondition="integratedMode,runtimeVersionv4.0" />
+                <add name="cshtm-Integrated-4.0" path="*.cshtm" verb="GET,HEAD,POST,DEBUG" type="System.Web.HttpForbiddenHandler" preCondition="integratedMode,runtimeVersionv4.0" />
+                <add name="cshtml-Integrated-4.0" path="*.cshtml" verb="GET,HEAD,POST,DEBUG" type="System.Web.HttpForbiddenHandler" preCondition="integratedMode,runtimeVersionv4.0" />
+                <add name="vbhtm-Integrated-4.0" path="*.vbhtm" verb="GET,HEAD,POST,DEBUG" type="System.Web.HttpForbiddenHandler" preCondition="integratedMode,runtimeVersionv4.0" />
+                <add name="vbhtml-Integrated-4.0" path="*.vbhtml" verb="GET,HEAD,POST,DEBUG" type="System.Web.HttpForbiddenHandler" preCondition="integratedMode,runtimeVersionv4.0" />
+                <add name="ScriptHandlerFactoryAppServices-Integrated-4.0" path="*_AppService.axd" verb="*" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" preCondition="integratedMode,runtimeVersionv4.0" />
+                <add name="ScriptResourceIntegrated-4.0" path="*ScriptResource.axd" verb="GET,HEAD" type="System.Web.Handlers.ScriptResourceHandler, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" preCondition="integratedMode,runtimeVersionv4.0" />
+                <add name="ASPClassic" path="*.asp" verb="GET,HEAD,POST" modules="IsapiModule" scriptProcessor="%IIS_BIN%\asp.dll" resourceType="File" />
+                <add name="SecurityCertificate" path="*.cer" verb="GET,HEAD,POST" modules="IsapiModule" scriptProcessor="%IIS_BIN%\asp.dll" resourceType="File" />
+                <add name="ISAPI-dll" path="*.dll" verb="*" modules="IsapiModule" resourceType="File" requireAccess="Execute" allowPathInfo="true" />
+                <add name="TraceHandler-Integrated" path="trace.axd" verb="GET,HEAD,POST,DEBUG" type="System.Web.Handlers.TraceHandler" preCondition="integratedMode,runtimeVersionv2.0" />
+                <add name="WebAdminHandler-Integrated" path="WebAdmin.axd" verb="GET,DEBUG" type="System.Web.Handlers.WebAdminHandler" preCondition="integratedMode,runtimeVersionv2.0" />
+                <add name="AssemblyResourceLoader-Integrated" path="WebResource.axd" verb="GET,DEBUG" type="System.Web.Handlers.AssemblyResourceLoader" preCondition="integratedMode,runtimeVersionv2.0" />
+                <add name="PageHandlerFactory-Integrated" path="*.aspx" verb="GET,HEAD,POST,DEBUG" type="System.Web.UI.PageHandlerFactory" preCondition="integratedMode,runtimeVersionv2.0" />
+                <add name="SimpleHandlerFactory-Integrated" path="*.ashx" verb="GET,HEAD,POST,DEBUG" type="System.Web.UI.SimpleHandlerFactory" preCondition="integratedMode,runtimeVersionv2.0" />
+                <add name="WebServiceHandlerFactory-Integrated" path="*.asmx" verb="GET,HEAD,POST,DEBUG" type="System.Web.Services.Protocols.WebServiceHandlerFactory,System.Web.Services,Version=2.0.0.0,Culture=neutral,PublicKeyToken=b03f5f7f11d50a3a" preCondition="integratedMode,runtimeVersionv2.0" />
+                <add name="HttpRemotingHandlerFactory-rem-Integrated" path="*.rem" verb="GET,HEAD,POST,DEBUG" type="System.Runtime.Remoting.Channels.Http.HttpRemotingHandlerFactory,System.Runtime.Remoting,Version=2.0.0.0,Culture=neutral,PublicKeyToken=b77a5c561934e089" preCondition="integratedMode,runtimeVersionv2.0" />
+                <add name="HttpRemotingHandlerFactory-soap-Integrated" path="*.soap" verb="GET,HEAD,POST,DEBUG" type="System.Runtime.Remoting.Channels.Http.HttpRemotingHandlerFactory,System.Runtime.Remoting,Version=2.0.0.0,Culture=neutral,PublicKeyToken=b77a5c561934e089" preCondition="integratedMode,runtimeVersionv2.0" />
+                <add name="AXD-ISAPI-2.0" path="*.axd" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness32" responseBufferLimit="0" />
+                <add name="PageHandlerFactory-ISAPI-2.0" path="*.aspx" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness32" responseBufferLimit="0" />
+                <add name="SimpleHandlerFactory-ISAPI-2.0" path="*.ashx" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness32" responseBufferLimit="0" />
+                <add name="WebServiceHandlerFactory-ISAPI-2.0" path="*.asmx" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness32" responseBufferLimit="0" />
+                <add name="HttpRemotingHandlerFactory-rem-ISAPI-2.0" path="*.rem" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness32" responseBufferLimit="0" />
+                <add name="HttpRemotingHandlerFactory-soap-ISAPI-2.0" path="*.soap" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness32" responseBufferLimit="0" />
+                <add name="svc-ISAPI-2.0-64" path="*.svc" verb="*" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness64" />
+                <add name="AXD-ISAPI-2.0-64" path="*.axd" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness64" responseBufferLimit="0" />
+                <add name="PageHandlerFactory-ISAPI-2.0-64" path="*.aspx" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness64" responseBufferLimit="0" />
+                <add name="SimpleHandlerFactory-ISAPI-2.0-64" path="*.ashx" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness64" responseBufferLimit="0" />
+                <add name="WebServiceHandlerFactory-ISAPI-2.0-64" path="*.asmx" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness64" responseBufferLimit="0" />
+                <add name="HttpRemotingHandlerFactory-rem-ISAPI-2.0-64" path="*.rem" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness64" responseBufferLimit="0" />
+                <add name="HttpRemotingHandlerFactory-soap-ISAPI-2.0-64" path="*.soap" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness64" responseBufferLimit="0" />
+                <add name="rules-64-ISAPI-2.0" path="*.rules" verb="*" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness64" />
+                <add name="xoml-64-ISAPI-2.0" path="*.xoml" verb="*" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness64" />
+                <add name="CGI-exe" path="*.exe" verb="*" modules="CgiModule" resourceType="File" requireAccess="Execute" allowPathInfo="true" />
+                <add name="SSINC-stm" path="*.stm" verb="GET,HEAD,POST" modules="ServerSideIncludeModule" resourceType="File" />
+                <add name="SSINC-shtm" path="*.shtm" verb="GET,HEAD,POST" modules="ServerSideIncludeModule" resourceType="File" />
+                <add name="SSINC-shtml" path="*.shtml" verb="GET,HEAD,POST" modules="ServerSideIncludeModule" resourceType="File" />
+                <add name="TRACEVerbHandler" path="*" verb="TRACE" modules="ProtocolSupportModule" requireAccess="None" />
+                <add name="OPTIONSVerbHandler" path="*" verb="OPTIONS" modules="ProtocolSupportModule" requireAccess="None" />
+                <add name="ExtensionlessUrl-ISAPI-4.0_32bit" path="*." verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
+                <add name="ExtensionlessUrlHandler-ISAPI-4.0_64bit" path="*." verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
+                <add name="ExtensionlessUrl-Integrated-4.0" path="*." verb="GET,HEAD,POST,DEBUG" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" responseBufferLimit="0" />
+                <add name="StaticFile" path="*" verb="*" modules="StaticFileModule,DefaultDocumentModule,DirectoryListingModule" resourceType="Either" requireAccess="Read" />
+            </handlers>
+        </system.webServer>
+    </location>
+</configuration>
diff --git a/src/IISIntegration/test/IISIntegration.FunctionalTests/IISIntegration.FunctionalTests.csproj b/src/IISIntegration/test/IISIntegration.FunctionalTests/IISIntegration.FunctionalTests.csproj
new file mode 100644
index 0000000000000000000000000000000000000000..d79a5ec5d9b1543214900f7775a941a948bbf4da
--- /dev/null
+++ b/src/IISIntegration/test/IISIntegration.FunctionalTests/IISIntegration.FunctionalTests.csproj
@@ -0,0 +1,29 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <TargetFrameworks>$(StandardTestTfms)</TargetFrameworks>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <Content Include="AppHostConfig\*.config" CopyToOutputDirectory="PreserveNewest" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <ProjectReference Include="..\..\src\Microsoft.AspNetCore.Server.IISIntegration\Microsoft.AspNetCore.Server.IISIntegration.csproj" />
+    <ProjectReference Include="..\WebSites\**\*.csproj" >
+      <ReferenceOutputAssembly>False</ReferenceOutputAssembly>
+    </ProjectReference>
+  </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>
diff --git a/src/IISIntegration/test/IISIntegration.FunctionalTests/OutOfProcess/HelloWorldTest.cs b/src/IISIntegration/test/IISIntegration.FunctionalTests/OutOfProcess/HelloWorldTest.cs
new file mode 100644
index 0000000000000000000000000000000000000000..370ce2cf630ae7fc61738d4bd05893903c7208d4
--- /dev/null
+++ b/src/IISIntegration/test/IISIntegration.FunctionalTests/OutOfProcess/HelloWorldTest.cs
@@ -0,0 +1,111 @@
+// 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.
+#if NETCOREAPP2_0 || NETCOREAPP2_1
+
+using System.IO;
+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 HelloWorldTests : LoggedTest
+    {
+        public HelloWorldTests(ITestOutputHelper output) : base(output)
+        {
+        }
+
+        [Theory(Skip = "Full framework web.config generation is currently incorrect. See https://github.com/aspnet/websdk/pull/322")]
+        [InlineData("V1")]
+        [InlineData("V2")]
+        public Task HelloWorld_IISExpress_Clr_X64_Portable(string ancmVersion)
+        {
+            return HelloWorld(RuntimeFlavor.Clr, ApplicationType.Portable, ancmVersion);
+        }
+
+        [Theory]
+        [InlineData("V1")]
+        [InlineData("V2")]
+        public Task HelloWorld_IISExpress_CoreClr_X64_Portable(string ancmVersion)
+        {
+            return HelloWorld(RuntimeFlavor.CoreClr, ApplicationType.Portable, ancmVersion);
+        }
+
+        private async Task HelloWorld(RuntimeFlavor runtimeFlavor, ApplicationType applicationType, string ancmVersion)
+        {
+            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.GetOutOfProcessTestSitesPath(), serverType, runtimeFlavor, architecture)
+                {
+                    EnvironmentName = "HelloWorld", // Will pick the Start class named 'StartupHelloWorld',
+                    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,
+                    Configuration =
+#if DEBUG
+                        "Debug",
+#else
+                        "Release",
+#endif
+                    AdditionalPublishParameters = $" /p:ANCMVersion={ancmVersion}"
+                };
+
+                using (var deployer = ApplicationDeployerFactory.Create(deploymentParameters, loggerFactory))
+                {
+                    var deploymentResult = await deployer.DeployAsync();
+
+                    // 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(string.Empty);
+                    }, logger, deploymentResult.HostShutdownToken, retryCount: 30);
+
+                    var responseText = await response.Content.ReadAsStringAsync();
+                    try
+                    {
+                        Assert.Equal("Hello World", responseText);
+
+                        response = await deploymentResult.HttpClient.GetAsync("/Path%3F%3F?query");
+                        responseText = await response.Content.ReadAsStringAsync();
+                        Assert.Equal("/Path??", responseText);
+
+                        response = await deploymentResult.HttpClient.GetAsync("/Query%3FPath?query?");
+                        responseText = await response.Content.ReadAsStringAsync();
+                        Assert.Equal("?query?", responseText);
+
+                        response = await deploymentResult.HttpClient.GetAsync("/BodyLimit");
+                        responseText = await response.Content.ReadAsStringAsync();
+                        Assert.Equal("null", responseText);
+
+                        response = await deploymentResult.HttpClient.GetAsync("/Auth");
+                        responseText = await response.Content.ReadAsStringAsync();
+
+                        // We adapted the Http.config file to be used for inprocess too. We specify WindowsAuth is enabled
+                        // We now expect that windows auth is enabled rather than disabled.
+                        Assert.True("backcompat;Windows".Equals(responseText) || "latest;Windows".Equals(responseText), "Auth");
+                    }
+                    catch (XunitException)
+                    {
+                        logger.LogWarning(response.ToString());
+                        logger.LogWarning(responseText);
+                        throw;
+                    }
+                }
+            }
+        }
+    }
+}
+#elif NET461
+#else
+#error Target frameworks need to be updated
+#endif
diff --git a/src/IISIntegration/test/IISIntegration.FunctionalTests/OutOfProcess/HttpsTest.cs b/src/IISIntegration/test/IISIntegration.FunctionalTests/OutOfProcess/HttpsTest.cs
new file mode 100644
index 0000000000000000000000000000000000000000..0e71a21fdccba8e9006c0fdca553fdec1b7a5175
--- /dev/null
+++ b/src/IISIntegration/test/IISIntegration.FunctionalTests/OutOfProcess/HttpsTest.cs
@@ -0,0 +1,248 @@
+// 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.
+#if NETCOREAPP2_0 || NETCOREAPP2_1
+
+using System;
+using System.IO;
+using System.Net.Http;
+using System.Security.Cryptography.X509Certificates;
+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
+{
+    // IIS Express preregisteres 44300-44399 ports with SSL bindings.
+    // So these tests always have to use ports in this range, and we can't rely on OS-allocated ports without a whole lot of ceremony around
+    // creating self-signed certificates and registering SSL bindings with HTTP.sys
+    public class HttpsTest : LoggedTest
+    {
+        public HttpsTest(ITestOutputHelper output) : base(output)
+        {
+        }
+
+        [Theory(Skip = "Full framework web.config generation is currently incorrect. See: https://github.com/aspnet/websdk/pull/322")]
+        [InlineData("V1")]
+        [InlineData("V2")]
+        public Task Https_HelloWorld_CLR_X64(string ancmVersion)
+        {
+            return HttpsHelloWorld(RuntimeFlavor.Clr, ApplicationType.Portable, port: 44396, ancmVersion);
+        }
+
+        [Theory]
+        [InlineData("V1")]
+        [InlineData("V2")]
+        public Task Https_HelloWorld_CoreCLR_X64_Portable(string ancmVersion)
+        {
+            return HttpsHelloWorld(RuntimeFlavor.CoreClr, ApplicationType.Portable, port: 44394, ancmVersion);
+        }
+
+        private async Task HttpsHelloWorld(RuntimeFlavor runtimeFlavor, ApplicationType applicationType, int port, string ancmVersion)
+        {
+            var serverType = ServerType.IISExpress;
+            var architecture = RuntimeArchitecture.x64;
+
+            var applicationBaseUrl = $"https://localhost:{port}/";
+            var testName = $"HttpsHelloWorld_{runtimeFlavor}";
+            using (StartLog(out var loggerFactory, testName))
+            {
+                var logger = loggerFactory.CreateLogger("HttpsHelloWorldTest");
+
+                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("AppHostConfig/Https.config") : null,
+                    SiteName = "HttpsTestSite", // This is configured in the Https.config
+                    TargetFramework = runtimeFlavor == RuntimeFlavor.Clr ? "net461" : "netcoreapp2.0",
+                    ApplicationType = applicationType,
+                    Configuration =
+#if DEBUG
+                        "Debug",
+#else
+                        "Release",
+#endif
+                    AdditionalPublishParameters = $" /p:ANCMVersion={ancmVersion}"
+
+                };
+
+                using (var deployer = ApplicationDeployerFactory.Create(deploymentParameters, loggerFactory))
+                {
+                    var deploymentResult = await deployer.DeployAsync();
+                    var handler = new HttpClientHandler();
+                    handler.ServerCertificateCustomValidationCallback = (a, b, c, d) => true;
+                    var httpClient = deploymentResult.CreateHttpClient(handler);
+                    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 httpClient.GetAsync(string.Empty);
+                    }, logger, deploymentResult.HostShutdownToken, retryCount: 30);
+
+                    var responseText = await response.Content.ReadAsStringAsync();
+                    try
+                    {
+                        Assert.Equal("Scheme:https; Original:http", responseText);
+                    }
+                    catch (XunitException)
+                    {
+                        logger.LogWarning(response.ToString());
+                        logger.LogWarning(responseText);
+                        throw;
+                    }
+                }
+            }
+        }
+
+        [Theory]
+        [InlineData("V1")]
+        [InlineData("V2")]
+        public Task Https_HelloWorld_NoClientCert_CoreCLR_X64_Portable(string ancmVersion)
+        {
+            return HttpsHelloWorldCerts(RuntimeFlavor.CoreClr, ApplicationType.Portable , port: 44397, sendClientCert: false, ancmVersion);
+        }
+
+        [Theory(Skip = "Full framework web.config generation is currently incorrect. See https://github.com/aspnet/websdk/pull/322")]
+        [InlineData("V1")]
+        [InlineData("V2")]
+        public Task Https_HelloWorld_NoClientCert_Clr_X64(string ancmVersion)
+        {
+            return HttpsHelloWorldCerts(RuntimeFlavor.Clr, ApplicationType.Portable, port: 44398, sendClientCert: false, ancmVersion);
+        }
+
+#pragma warning disable xUnit1004 // Test methods should not be skipped
+        [Theory(Skip = "Manual test only, selecting a client cert is non-determanistic on different machines.")]
+        [InlineData("V1")]
+        [InlineData("V2")]
+#pragma warning restore xUnit1004 // Test methods should not be skipped
+        public Task Https_HelloWorld_ClientCert_Clr_X64(string ancmVersion)
+        {
+            return HttpsHelloWorldCerts(RuntimeFlavor.Clr, ApplicationType.Portable, port: 44301, sendClientCert: true, ancmVersion);
+        }
+
+#pragma warning disable xUnit1004 // Test methods should not be skipped
+        [Theory(Skip = "Manual test only, selecting a client cert is non-determanistic on different machines.")]
+        [InlineData("V1")]
+        [InlineData("V2")]
+#pragma warning restore xUnit1004 // Test methods should not be skipped
+        public Task Https_HelloWorld_ClientCert_CoreCLR_X64_Portable(string ancmVersion)
+        {
+            return HttpsHelloWorldCerts(RuntimeFlavor.CoreClr, ApplicationType.Portable, port: 44302, sendClientCert: true, ancmVersion);
+        }
+
+        private async Task HttpsHelloWorldCerts(RuntimeFlavor runtimeFlavor, ApplicationType applicationType, int port, bool sendClientCert, string ancmVersion)
+        {
+            var serverType = ServerType.IISExpress;
+            var architecture = RuntimeArchitecture.x64;
+            var applicationBaseUrl = $"https://localhost:{port}/";
+            var testName = $"HttpsHelloWorldCerts_{runtimeFlavor}";
+            using (StartLog(out var loggerFactory, testName))
+            {
+                var logger = loggerFactory.CreateLogger("HttpsHelloWorldTest");
+
+                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("AppHostConfig/Https.config") : null,
+                    SiteName = "HttpsTestSite", // This is configured in the Https.config
+                    TargetFramework = runtimeFlavor == RuntimeFlavor.Clr ? "net461" : "netcoreapp2.0",
+                    ApplicationType = applicationType,
+                    Configuration =
+#if DEBUG
+                        "Debug",
+#else
+                        "Release",
+#endif
+                    AdditionalPublishParameters = $" /p:ANCMVersion={ancmVersion}"
+                };
+
+                using (var deployer = ApplicationDeployerFactory.Create(deploymentParameters, loggerFactory))
+                {
+                    var deploymentResult = await deployer.DeployAsync();
+                    var handler = new HttpClientHandler();
+                    handler.ServerCertificateCustomValidationCallback = (a, b, c, d) => true;
+                    handler.ClientCertificateOptions = ClientCertificateOption.Manual;
+                    if (sendClientCert)
+                    {
+                        X509Certificate2 clientCert = FindClientCert();
+                        Assert.NotNull(clientCert);
+                        handler.ClientCertificates.Add(clientCert);
+                    }
+                    var httpClient = deploymentResult.CreateHttpClient(handler);
+
+                    // 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 httpClient.GetAsync("checkclientcert");
+                    }, logger, deploymentResult.HostShutdownToken);
+
+                    var responseText = await response.Content.ReadAsStringAsync();
+                    try
+                    {
+                        if (sendClientCert)
+                        {
+                            Assert.Equal("Scheme:https; Original:http; has cert? True", responseText);
+                        }
+                        else
+                        {
+                            Assert.Equal("Scheme:https; Original:http; has cert? False", responseText);
+                        }
+                    }
+                    catch (XunitException)
+                    {
+                        logger.LogWarning(response.ToString());
+                        logger.LogWarning(responseText);
+                        throw;
+                    }
+                }
+            }
+        }
+
+        private X509Certificate2 FindClientCert()
+        {
+            var store = new X509Store();
+            store.Open(OpenFlags.ReadOnly);
+
+            foreach (var cert in store.Certificates)
+            {
+                bool isClientAuth = false;
+                bool isSmartCard = false;
+                foreach (var extension in cert.Extensions)
+                {
+                    var eku = extension as X509EnhancedKeyUsageExtension;
+                    if (eku != null)
+                    {
+                        foreach (var oid in eku.EnhancedKeyUsages)
+                        {
+                            if (oid.FriendlyName == "Client Authentication")
+                            {
+                                isClientAuth = true;
+                            }
+                            else if (oid.FriendlyName == "Smart Card Logon")
+                            {
+                                isSmartCard = true;
+                                break;
+                            }
+                        }
+                    }
+                }
+
+                if (isClientAuth && !isSmartCard)
+                {
+                    return cert;
+                }
+            }
+            return null;
+        }
+    }
+}
+#elif NET461
+#else
+#error Target frameworks need to be updated
+#endif
diff --git a/src/IISIntegration/test/IISIntegration.FunctionalTests/OutOfProcess/NtlmAuthentationTest.cs b/src/IISIntegration/test/IISIntegration.FunctionalTests/OutOfProcess/NtlmAuthentationTest.cs
new file mode 100644
index 0000000000000000000000000000000000000000..809c213b27f96e7c56d35aa04e8dc14f6082ddb5
--- /dev/null
+++ b/src/IISIntegration/test/IISIntegration.FunctionalTests/OutOfProcess/NtlmAuthentationTest.cs
@@ -0,0 +1,147 @@
+// 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.
+
+#if NET461
+// Per https://github.com/dotnet/corefx/issues/5045, HttpClientHandler.UseDefaultCredentials does not work correctly in CoreFx.
+// We'll require the desktop HttpClient to run these tests.
+
+using System;
+using System.IO;
+using System.Net;
+using System.Net.Http;
+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 NtlmAuthenticationTests : LoggedTest
+    {
+        public NtlmAuthenticationTests(ITestOutputHelper output) : base(output)
+        {
+        }
+
+        [Theory(Skip = "Full framework web.config generation is currently incorrect. See https://github.com/aspnet/websdk/pull/322")]
+        [InlineData("V1")]
+        [InlineData("V2")]
+        public Task NtlmAuthentication_Clr_X64(string ancmVersion)
+        {
+            return NtlmAuthentication(RuntimeFlavor.Clr, ApplicationType.Portable, port: 5051, ancmVersion);
+        }
+
+        [Theory]
+        [InlineData("V1")]
+        [InlineData("V2")]
+        public Task NtlmAuthentication_CoreClr_X64_Portable(string ancmVersion)
+        {
+            return NtlmAuthentication(RuntimeFlavor.CoreClr, ApplicationType.Portable, port: 5052, ancmVersion);
+        }
+
+        private async Task NtlmAuthentication(RuntimeFlavor runtimeFlavor, ApplicationType applicationType, int port, string ancmVersion)
+        {
+            var serverType = ServerType.IISExpress;
+            var architecture = RuntimeArchitecture.x64;
+            var testName = $"NtlmAuthentication_{runtimeFlavor}";
+            using (StartLog(out var loggerFactory, testName))
+            {
+                var logger = loggerFactory.CreateLogger("NtlmAuthenticationTest");
+
+                var windowsRid = architecture == RuntimeArchitecture.x64
+                    ? "win7-x64"
+                    : "win7-x86";
+                var additionalPublishParameters = $" /p:ANCMVersion={ancmVersion}";
+                if (ApplicationType.Standalone == applicationType && RuntimeFlavor.CoreClr == runtimeFlavor)
+                {
+                    additionalPublishParameters += " -r " + windowsRid;
+
+                }
+   
+                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("AppHostConfig/NtlmAuthentation.config") : null,
+                    SiteName = "NtlmAuthenticationTestSite", // This is configured in the NtlmAuthentication.config
+                    TargetFramework = runtimeFlavor == RuntimeFlavor.Clr ? "net461" : "netcoreapp2.0",
+                    ApplicationType = applicationType,
+                    AdditionalPublishParameters = additionalPublishParameters,
+                    Configuration =
+#if DEBUG
+                        "Debug"
+#else
+                        "Release"
+#endif
+                };
+
+                using (var deployer = ApplicationDeployerFactory.Create(deploymentParameters, loggerFactory))
+                {
+                    var deploymentResult = await deployer.DeployAsync();
+                    var httpClient = deploymentResult.HttpClient;
+                    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 httpClient.GetAsync(string.Empty);
+                    }, logger, deploymentResult.HostShutdownToken, retryCount: 30);
+
+                    var responseText = await response.Content.ReadAsStringAsync();
+                    try
+                    {
+                        Assert.Equal(HttpStatusCode.OK, response.StatusCode);
+                        Assert.Equal("Hello World", responseText);
+
+                        response = await httpClient.GetAsync("/Anonymous");
+                        responseText = await response.Content.ReadAsStringAsync();
+                        Assert.Equal(HttpStatusCode.OK, response.StatusCode);
+                        Assert.Equal("Anonymous?True", responseText);
+
+                        response = await httpClient.GetAsync("/Restricted");
+                        responseText = await response.Content.ReadAsStringAsync();
+                        Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode);
+                        Assert.Contains("NTLM", response.Headers.WwwAuthenticate.ToString());
+                        Assert.Contains("Negotiate", response.Headers.WwwAuthenticate.ToString());
+
+                        response = await httpClient.GetAsync("/RestrictedNTLM");
+                        responseText = await response.Content.ReadAsStringAsync();
+                        Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode);
+                        Assert.Contains("NTLM", response.Headers.WwwAuthenticate.ToString());
+                        // Note we can't restrict a challenge to a specific auth type, the native auth modules always add themselves.
+                        Assert.Contains("Negotiate", response.Headers.WwwAuthenticate.ToString());
+
+                        response = await httpClient.GetAsync("/Forbidden");
+                        responseText = await response.Content.ReadAsStringAsync();
+                        Assert.Equal(HttpStatusCode.Forbidden, response.StatusCode);
+
+                        var httpClientHandler = new HttpClientHandler() { UseDefaultCredentials = true };
+                        httpClient = deploymentResult.CreateHttpClient(httpClientHandler);
+
+                        response = await httpClient.GetAsync("/Anonymous");
+                        responseText = await response.Content.ReadAsStringAsync();
+                        Assert.Equal(HttpStatusCode.OK, response.StatusCode);
+                        Assert.Equal("Anonymous?True", responseText);
+
+                        response = await httpClient.GetAsync("/Restricted");
+                        responseText = await response.Content.ReadAsStringAsync();
+                        Assert.Equal(HttpStatusCode.OK, response.StatusCode);
+                        Assert.NotEmpty(responseText);
+                    }
+                    catch (XunitException)
+                    {
+                        logger.LogWarning(response.ToString());
+                        logger.LogWarning(responseText);
+                        throw;
+                    }
+                }
+            }
+        }
+    }
+}
+#elif NETCOREAPP2_0 || NETCOREAPP2_1
+#else
+#error Target frameworks need to be updated
+#endif
diff --git a/src/IISIntegration/test/IISIntegration.FunctionalTests/Properties/AssemblyInfo.cs b/src/IISIntegration/test/IISIntegration.FunctionalTests/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000000000000000000000000000000000000..240f2d35c057925be22c2d216202efc02a50243d
--- /dev/null
+++ b/src/IISIntegration/test/IISIntegration.FunctionalTests/Properties/AssemblyInfo.cs
@@ -0,0 +1,8 @@
+// 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
+using Xunit;
+
+[assembly: Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests.IISExpressSupportsInProcessHosting]
+[assembly: CollectionBehavior(DisableTestParallelization = true)]
diff --git a/src/IISIntegration/test/IISIntegration.FunctionalTests/UpgradeFeatureDetectionTests.cs b/src/IISIntegration/test/IISIntegration.FunctionalTests/UpgradeFeatureDetectionTests.cs
new file mode 100644
index 0000000000000000000000000000000000000000..8627334de705ac4971779478360298c0af309180
--- /dev/null
+++ b/src/IISIntegration/test/IISIntegration.FunctionalTests/UpgradeFeatureDetectionTests.cs
@@ -0,0 +1,99 @@
+// 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
+    {
+        private string _isWebsocketsSupported = Environment.OSVersion.Version >= new Version(6, 2) ? "Enabled" : "Disabled";
+
+        public UpgradeFeatureDetectionTests(ITestOutputHelper output) : base(output)
+        {
+        }
+
+        [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(),
+                _isWebsocketsSupported);
+        }
+
+        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(sitePath, 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.1",
+                    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;
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/src/IISIntegration/test/IISIntegration.FunctionalTests/Utilities/Helpers.cs b/src/IISIntegration/test/IISIntegration.FunctionalTests/Utilities/Helpers.cs
new file mode 100644
index 0000000000000000000000000000000000000000..5cda360005188ba5c52148ae346b62c5407b6e67
--- /dev/null
+++ b/src/IISIntegration/test/IISIntegration.FunctionalTests/Utilities/Helpers.cs
@@ -0,0 +1,41 @@
+// 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 Microsoft.AspNetCore.Server.IntegrationTesting;
+using System;
+using System.IO;
+using System.Linq;
+using System.Xml.Linq;
+
+namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
+{
+    public class Helpers
+    {
+        public static string GetTestWebSitePath(string name)
+        {   
+            return Path.GetFullPath(
+                Path.Combine(AppDomain.CurrentDomain.BaseDirectory,
+                    "..", // tfm
+                    "..", // debug
+                    "..", // obj
+                    "..", // projectfolder
+                    "WebSites",
+                    name));
+        }
+
+        public static string GetInProcessTestSitesPath() => GetTestWebSitePath("InProcessWebSite");
+
+        public static string GetOutOfProcessTestSitesPath() => GetTestWebSitePath("OutOfProcessWebSite");
+
+        public static void ModifyAspNetCoreSectionInWebConfig(DeploymentResult deploymentResult, string key, string value)
+        {
+            // modify the web.config after publish
+            var root = deploymentResult.ContentRoot;
+            var webConfigFile = $"{root}/web.config";
+            var config = XDocument.Load(webConfigFile);
+            var element = config.Descendants("aspNetCore").FirstOrDefault();
+            element.SetAttributeValue(key, value);
+            config.Save(webConfigFile);
+        }
+    }
+}
diff --git a/src/IISIntegration/test/IISIntegration.FunctionalTests/Utilities/IISExpressSupportsInProcessHostingAttribute.cs b/src/IISIntegration/test/IISIntegration.FunctionalTests/Utilities/IISExpressSupportsInProcessHostingAttribute.cs
new file mode 100644
index 0000000000000000000000000000000000000000..5f2edd22f6be99870f99e75d41512523dc7dd07a
--- /dev/null
+++ b/src/IISIntegration/test/IISIntegration.FunctionalTests/Utilities/IISExpressSupportsInProcessHostingAttribute.cs
@@ -0,0 +1,62 @@
+// 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.Linq;
+using System.Runtime.InteropServices;
+using System.Xml.Linq;
+using Microsoft.AspNetCore.Testing.xunit;
+
+namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
+{
+    [AttributeUsage(AttributeTargets.Method | AttributeTargets.Assembly | AttributeTargets.Class)]
+    public sealed class IISExpressSupportsInProcessHostingAttribute : Attribute, ITestCondition
+    {
+        public bool IsMet => AncmSchema.SupportsInProcessHosting;
+
+        public string SkipReason => AncmSchema.SkipReason;
+
+        private class AncmSchema
+        {
+            public static bool SupportsInProcessHosting { get; }
+            public static string SkipReason { get; } = "IIS Express must be upgraded to support in-process hosting.";
+
+            static AncmSchema()
+            {
+                if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+                {
+                    SkipReason = "IIS Express tests can only be run on Windows";
+                    return;
+                }
+
+                var ancmConfigPath = Path.Combine(
+                    Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles),
+                    "IIS Express", "config", "schema", "aspnetcore_schema.xml");
+
+                if (!File.Exists(ancmConfigPath))
+                {
+                    SkipReason = "IIS Express is not installed.";
+                    return;
+                }
+
+                XDocument ancmConfig;
+
+                try
+                {
+                    ancmConfig = XDocument.Load(ancmConfigPath);
+                }
+                catch
+                {
+                    SkipReason = "Could not read ANCM schema configuration";
+                    return;
+                }
+
+                SupportsInProcessHosting = ancmConfig
+                    .Root
+                    .Descendants("attribute")
+                    .Any(n => "hostingModel".Equals(n.Attribute("name")?.Value, StringComparison.Ordinal));
+            }
+        }
+    }
+}
diff --git a/src/IISIntegration/test/IISIntegration.FunctionalTests/Utilities/IISTestSiteCollection.cs b/src/IISIntegration/test/IISIntegration.FunctionalTests/Utilities/IISTestSiteCollection.cs
new file mode 100644
index 0000000000000000000000000000000000000000..8d53affc9870a2dadbef37f913eff89e2348c34e
--- /dev/null
+++ b/src/IISIntegration/test/IISIntegration.FunctionalTests/Utilities/IISTestSiteCollection.cs
@@ -0,0 +1,16 @@
+// 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 Xunit;
+
+namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
+{
+    /// <summary>
+    /// This type just maps collection names to available fixtures
+    /// </summary>
+    [CollectionDefinition(Name)]
+    public class IISTestSiteCollection : ICollectionFixture<IISTestSiteFixture>
+    {
+        public const string Name = nameof(IISTestSiteCollection);
+    }
+}
diff --git a/src/IISIntegration/test/IISIntegration.FunctionalTests/Utilities/IISTestSiteFixture.cs b/src/IISIntegration/test/IISIntegration.FunctionalTests/Utilities/IISTestSiteFixture.cs
new file mode 100644
index 0000000000000000000000000000000000000000..763603508d2935fa8e540ff40b962830ef053258
--- /dev/null
+++ b/src/IISIntegration/test/IISIntegration.FunctionalTests/Utilities/IISTestSiteFixture.cs
@@ -0,0 +1,53 @@
+// 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.Net.Http;
+using System.Threading;
+using Microsoft.AspNetCore.Server.IntegrationTesting;
+using Microsoft.Extensions.Logging.Abstractions;
+
+namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
+{
+    public class IISTestSiteFixture : IDisposable
+    {
+        private readonly IApplicationDeployer _deployer;
+
+        public IISTestSiteFixture()
+        {
+            var deploymentParameters = new DeploymentParameters(Helpers.GetInProcessTestSitesPath(),
+                ServerType.IISExpress,
+                RuntimeFlavor.CoreClr,
+                RuntimeArchitecture.x64)
+            {
+                ServerConfigTemplateContent = File.ReadAllText("AppHostConfig/Http.config"),
+                SiteName = "HttpTestSite",
+                TargetFramework = "netcoreapp2.1",
+                ApplicationType = ApplicationType.Portable,
+                Configuration =
+#if DEBUG
+                        "Debug"
+#else
+                        "Release"
+#endif
+            };
+
+            _deployer = ApplicationDeployerFactory.Create(deploymentParameters, NullLoggerFactory.Instance);
+            DeploymentResult = _deployer.DeployAsync().Result;
+            Client = DeploymentResult.HttpClient;
+            BaseUri = DeploymentResult.ApplicationBaseUri;
+            ShutdownToken = DeploymentResult.HostShutdownToken;
+        }
+
+        public string BaseUri { get; }
+        public HttpClient Client { get; }
+        public CancellationToken ShutdownToken { get; }
+        public DeploymentResult DeploymentResult { get; }
+
+        public void Dispose()
+        {
+            _deployer.Dispose();
+        }
+    }
+}
diff --git a/src/IISIntegration/test/Microsoft.AspNetCore.Server.IISIntegration.Tests/IISExtensionTests.cs b/src/IISIntegration/test/Microsoft.AspNetCore.Server.IISIntegration.Tests/IISExtensionTests.cs
new file mode 100644
index 0000000000000000000000000000000000000000..772fbde2c31cfc5e038420298f2c20ad69c89f62
--- /dev/null
+++ b/src/IISIntegration/test/Microsoft.AspNetCore.Server.IISIntegration.Tests/IISExtensionTests.cs
@@ -0,0 +1,33 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System.Linq;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.AspNetCore.TestHost;
+using Microsoft.Extensions.DependencyInjection;
+using Xunit;
+
+namespace Microsoft.AspNetCore.Server.IISIntegration
+{
+    public class IISExtensionTests
+    {
+        [Fact]
+        public void CallingUseIISIntegrationMultipleTimesWorks()
+        {
+
+            var builder = new WebHostBuilder()
+                .UseSetting("TOKEN", "TestToken")
+                .UseSetting("PORT", "12345")
+                .UseSetting("APPL_PATH", "/")
+                .UseIISIntegration()
+                .UseIISIntegration()
+                .Configure(app => { });
+            var server = new TestServer(builder);
+
+            var filters = server.Host.Services.GetServices<IStartupFilter>()
+                .OfType<IISSetupFilter>();
+
+            Assert.Single(filters);
+        }
+    }
+}
diff --git a/src/IISIntegration/test/Microsoft.AspNetCore.Server.IISIntegration.Tests/IISMiddlewareTests.cs b/src/IISIntegration/test/Microsoft.AspNetCore.Server.IISIntegration.Tests/IISMiddlewareTests.cs
new file mode 100644
index 0000000000000000000000000000000000000000..0898b7ae21aa1dd36b9a7f2e9cb98d1facf2065e
--- /dev/null
+++ b/src/IISIntegration/test/Microsoft.AspNetCore.Server.IISIntegration.Tests/IISMiddlewareTests.cs
@@ -0,0 +1,420 @@
+// 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.Net;
+using System.Net.Http;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Authentication;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.AspNetCore.Http.Features.Authentication;
+using Microsoft.AspNetCore.TestHost;
+using Microsoft.Extensions.DependencyInjection;
+using Xunit;
+
+namespace Microsoft.AspNetCore.Server.IISIntegration
+{
+    public class IISMiddlewareTests
+    {
+        [Fact]
+        public async Task MiddlewareSkippedIfTokenIsMissing()
+        {
+            var assertsExecuted = false;
+
+            var builder = new WebHostBuilder()
+                .UseSetting("PORT", "12345")
+                .UseSetting("APPL_PATH", "/")
+                .UseIISIntegration()
+                .Configure(app =>
+                {
+                    app.Run(context =>
+                    {
+                        var auth = context.Features.Get<IHttpAuthenticationFeature>();
+                        Assert.Null(auth);
+                        assertsExecuted = true;
+                        return Task.FromResult(0);
+                    });
+                });
+            var server = new TestServer(builder);
+
+            var req = new HttpRequestMessage(HttpMethod.Get, "");
+            req.Headers.TryAddWithoutValidation("MS-ASPNETCORE-TOKEN", "TestToken");
+            var response = await server.CreateClient().SendAsync(req);
+            Assert.True(assertsExecuted);
+            response.EnsureSuccessStatusCode();
+        }
+
+        [Fact]
+        public async Task MiddlewareRejectsRequestIfTokenHeaderIsMissing()
+        {
+            var assertsExecuted = false;
+
+            var builder = new WebHostBuilder()
+                .UseSetting("TOKEN", "TestToken")
+                .UseSetting("PORT", "12345")
+                .UseSetting("APPL_PATH", "/")
+                .UseIISIntegration()
+                .Configure(app =>
+                {
+                    app.Run(context =>
+                    {
+                        var auth = context.Features.Get<IHttpAuthenticationFeature>();
+                        Assert.Null(auth);
+                        assertsExecuted = true;
+                        return Task.FromResult(0);
+                    });
+                });
+            var server = new TestServer(builder);
+
+            var req = new HttpRequestMessage(HttpMethod.Get, "");
+            var response = await server.CreateClient().SendAsync(req);
+            Assert.False(assertsExecuted);
+            Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
+        }
+
+        [Theory]
+        [InlineData("/", "/iisintegration", "shutdown")]
+        [InlineData("/", "/iisintegration", "Shutdown")]
+        [InlineData("/pathBase", "/pathBase/iisintegration", "shutdown")]
+        [InlineData("/pathBase", "/pathBase/iisintegration", "Shutdown")]
+        public async Task MiddlewareShutsdownGivenANCMShutdown(string pathBase, string requestPath, string shutdownEvent)
+        {
+            var requestExecuted = new ManualResetEvent(false);
+            var applicationStoppingFired = new ManualResetEvent(false);
+            var builder = new WebHostBuilder()
+                .UseSetting("TOKEN", "TestToken")
+                .UseSetting("PORT", "12345")
+                .UseSetting("APPL_PATH", pathBase)
+                .UseIISIntegration()
+                .Configure(app =>
+                {
+                    var appLifetime = app.ApplicationServices.GetRequiredService<IApplicationLifetime>();
+                    appLifetime.ApplicationStopping.Register(() => applicationStoppingFired.Set());
+
+                    app.Run(context =>
+                    {
+                        requestExecuted.Set();
+                        return Task.FromResult(0);
+                    });
+                });
+            var server = new TestServer(builder);
+
+            var request = new HttpRequestMessage(HttpMethod.Post, requestPath);
+            request.Headers.TryAddWithoutValidation("MS-ASPNETCORE-TOKEN", "TestToken");
+            request.Headers.TryAddWithoutValidation("MS-ASPNETCORE-EVENT", shutdownEvent);
+            var response = await server.CreateClient().SendAsync(request);
+
+            Assert.True(applicationStoppingFired.WaitOne(TimeSpan.FromSeconds(5)));
+            Assert.False(requestExecuted.WaitOne(0));
+            Assert.Equal(HttpStatusCode.Accepted, response.StatusCode);
+        }
+
+        public static TheoryData<HttpMethod> InvalidShutdownMethods
+        {
+            get
+            {
+                return new TheoryData<HttpMethod>
+                {
+                    HttpMethod.Put,
+                    HttpMethod.Trace,
+                    HttpMethod.Head,
+                    HttpMethod.Get,
+                    HttpMethod.Delete,
+                    HttpMethod.Options
+                };
+            }
+        }
+
+        [Theory]
+        [MemberData(nameof(InvalidShutdownMethods))]
+        public async Task MiddlewareIgnoresShutdownGivenWrongMethod(HttpMethod method)
+        {
+            var requestExecuted = new ManualResetEvent(false);
+            var applicationStoppingFired = new ManualResetEvent(false);
+            var builder = new WebHostBuilder()
+                .UseSetting("TOKEN", "TestToken")
+                .UseSetting("PORT", "12345")
+                .UseSetting("APPL_PATH", "/")
+                .UseIISIntegration()
+                .Configure(app =>
+                {
+                    var appLifetime = app.ApplicationServices.GetRequiredService<IApplicationLifetime>();
+                    appLifetime.ApplicationStopping.Register(() => applicationStoppingFired.Set());
+
+                    app.Run(context =>
+                    {
+                        requestExecuted.Set();
+                        return Task.FromResult(0);
+                    });
+                });
+            var server = new TestServer(builder);
+
+            var request = new HttpRequestMessage(method, "/iisintegration");
+            request.Headers.TryAddWithoutValidation("MS-ASPNETCORE-TOKEN", "TestToken");
+            request.Headers.TryAddWithoutValidation("MS-ASPNETCORE-EVENT", "shutdown");
+            var response = await server.CreateClient().SendAsync(request);
+
+            Assert.False(applicationStoppingFired.WaitOne(TimeSpan.FromSeconds(1)));
+            Assert.True(requestExecuted.WaitOne(0));
+            Assert.Equal(HttpStatusCode.OK, response.StatusCode);
+        }
+
+        [Theory]
+        [InlineData("/")]
+        [InlineData("/path")]
+        [InlineData("/path/iisintegration")]
+        public async Task MiddlewareIgnoresShutdownGivenWrongPath(string path)
+        {
+            var requestExecuted = new ManualResetEvent(false);
+            var applicationStoppingFired = new ManualResetEvent(false);
+            var builder = new WebHostBuilder()
+                .UseSetting("TOKEN", "TestToken")
+                .UseSetting("PORT", "12345")
+                .UseSetting("APPL_PATH", "/")
+                .UseIISIntegration()
+                .Configure(app =>
+                {
+                    var appLifetime = app.ApplicationServices.GetRequiredService<IApplicationLifetime>();
+                    appLifetime.ApplicationStopping.Register(() => applicationStoppingFired.Set());
+
+                    app.Run(context =>
+                    {
+                        requestExecuted.Set();
+                        return Task.FromResult(0);
+                    });
+                });
+            var server = new TestServer(builder);
+
+            var request = new HttpRequestMessage(HttpMethod.Post, path);
+            request.Headers.TryAddWithoutValidation("MS-ASPNETCORE-TOKEN", "TestToken");
+            request.Headers.TryAddWithoutValidation("MS-ASPNETCORE-EVENT", "shutdown");
+            var response = await server.CreateClient().SendAsync(request);
+
+            Assert.False(applicationStoppingFired.WaitOne(TimeSpan.FromSeconds(1)));
+            Assert.True(requestExecuted.WaitOne(0));
+            Assert.Equal(HttpStatusCode.OK, response.StatusCode);
+        }
+
+        [Theory]
+        [InlineData("event")]
+        [InlineData("")]
+        [InlineData(null)]
+        public async Task MiddlewareIgnoresShutdownGivenWrongEvent(string shutdownEvent)
+        {
+            var requestExecuted = new ManualResetEvent(false);
+            var applicationStoppingFired = new ManualResetEvent(false);
+            var builder = new WebHostBuilder()
+                .UseSetting("TOKEN", "TestToken")
+                .UseSetting("PORT", "12345")
+                .UseSetting("APPL_PATH", "/")
+                .UseIISIntegration()
+                .Configure(app =>
+                {
+                    var appLifetime = app.ApplicationServices.GetRequiredService<IApplicationLifetime>();
+                    appLifetime.ApplicationStopping.Register(() => applicationStoppingFired.Set());
+
+                    app.Run(context =>
+                    {
+                        requestExecuted.Set();
+                        return Task.FromResult(0);
+                    });
+                });
+            var server = new TestServer(builder);
+
+            var request = new HttpRequestMessage(HttpMethod.Post, "/iisintegration");
+            request.Headers.TryAddWithoutValidation("MS-ASPNETCORE-TOKEN", "TestToken");
+            request.Headers.TryAddWithoutValidation("MS-ASPNETCORE-EVENT", shutdownEvent);
+            var response = await server.CreateClient().SendAsync(request);
+
+            Assert.False(applicationStoppingFired.WaitOne(TimeSpan.FromSeconds(1)));
+            Assert.True(requestExecuted.WaitOne(0));
+            Assert.Equal(HttpStatusCode.OK, response.StatusCode);
+        }
+
+        [Fact]
+        public void UrlDelayRegisteredAndPreferHostingUrlsSet()
+        {
+            var builder = new WebHostBuilder()
+                .UseSetting("TOKEN", "TestToken")
+                .UseSetting("PORT", "12345")
+                .UseSetting("APPL_PATH", "/")
+                .UseIISIntegration()
+                .Configure(app =>
+                {
+                    app.Run(context => Task.FromResult(0));
+                });
+
+            Assert.Null(builder.GetSetting(WebHostDefaults.ServerUrlsKey));
+            Assert.Null(builder.GetSetting(WebHostDefaults.PreferHostingUrlsKey));
+
+            // Adds a server and calls Build()
+            var server = new TestServer(builder);
+
+            Assert.Equal("http://127.0.0.1:12345", builder.GetSetting(WebHostDefaults.ServerUrlsKey));
+            Assert.Equal("true", builder.GetSetting(WebHostDefaults.PreferHostingUrlsKey));
+        }
+
+        [Fact]
+        public void PathBaseHiddenFromServer()
+        {
+            var builder = new WebHostBuilder()
+                .UseSetting("TOKEN", "TestToken")
+                .UseSetting("PORT", "12345")
+                .UseSetting("APPL_PATH", "/pathBase")
+                .UseIISIntegration()
+                .Configure(app =>
+                {
+                    app.Run(context => Task.FromResult(0));
+                });
+            new TestServer(builder);
+
+            Assert.Equal("http://127.0.0.1:12345", builder.GetSetting(WebHostDefaults.ServerUrlsKey));
+        }
+
+        [Fact]
+        public async Task AddsUsePathBaseMiddlewareWhenPathBaseSpecified()
+        {
+            var requestPathBase = string.Empty;
+            var requestPath = string.Empty;
+            var builder = new WebHostBuilder()
+                .UseSetting("TOKEN", "TestToken")
+                .UseSetting("PORT", "12345")
+                .UseSetting("APPL_PATH", "/pathbase")
+                .UseIISIntegration()
+                .Configure(app =>
+                {
+                    app.Run(context =>
+                    {
+                        requestPathBase = context.Request.PathBase.Value;
+                        requestPath = context.Request.Path.Value;
+                        return Task.FromResult(0);
+                    });
+                });
+            var server = new TestServer(builder);
+
+            var request = new HttpRequestMessage(HttpMethod.Get, "/PathBase/Path");
+            request.Headers.TryAddWithoutValidation("MS-ASPNETCORE-TOKEN", "TestToken");
+            var response = await server.CreateClient().SendAsync(request);
+
+            Assert.Equal("/PathBase", requestPathBase);
+            Assert.Equal("/Path", requestPath);
+        }
+
+        [Fact]
+        public async Task AddsAuthenticationHandlerByDefault()
+        {
+            var assertsExecuted = false;
+
+            var builder = new WebHostBuilder()
+                .UseSetting("TOKEN", "TestToken")
+                .UseSetting("PORT", "12345")
+                .UseSetting("APPL_PATH", "/")
+                .UseIISIntegration()
+                .Configure(app =>
+                {
+                    app.Run(async context => 
+                    {
+                        var auth = context.RequestServices.GetRequiredService<IAuthenticationSchemeProvider>();
+                        var windows = await auth.GetSchemeAsync(IISDefaults.AuthenticationScheme);
+                        Assert.NotNull(windows);
+                        Assert.Null(windows.DisplayName);
+                        Assert.Equal("Microsoft.AspNetCore.Server.IISIntegration.AuthenticationHandler", windows.HandlerType.FullName);
+                        assertsExecuted = true;
+                    });
+                });
+            var server = new TestServer(builder);
+
+            var req = new HttpRequestMessage(HttpMethod.Get, "");
+            req.Headers.TryAddWithoutValidation("MS-ASPNETCORE-TOKEN", "TestToken");
+            await server.CreateClient().SendAsync(req);
+
+            Assert.True(assertsExecuted);
+        }
+
+        [Theory]
+        [InlineData(true)]
+        [InlineData(false)]
+        public async Task OnlyAddAuthenticationHandlerIfForwardWindowsAuthentication(bool forward)
+        {
+            var assertsExecuted = false;
+
+            var builder = new WebHostBuilder()
+                .UseSetting("TOKEN", "TestToken")
+                .UseSetting("PORT", "12345")
+                .UseSetting("APPL_PATH", "/")
+                .UseIISIntegration()
+                .ConfigureServices(services =>
+                {
+                    services.Configure<IISOptions>(options =>
+                    {
+                        options.ForwardWindowsAuthentication = forward;
+                    });
+                })
+                .Configure(app =>
+                {
+                    app.Run(async context => 
+                    {
+                        var auth = context.RequestServices.GetService<IAuthenticationSchemeProvider>();
+                        Assert.NotNull(auth);
+                        var windowsAuth = await auth.GetSchemeAsync(IISDefaults.AuthenticationScheme);
+                        if (forward)
+                        {
+                            Assert.NotNull(windowsAuth);
+                            Assert.Null(windowsAuth.DisplayName);
+                            Assert.Equal("AuthenticationHandler", windowsAuth.HandlerType.Name);
+                        }
+                        else
+                        {
+                            Assert.Null(windowsAuth);
+                        }
+                        assertsExecuted = true;
+                    });
+                });
+            var server = new TestServer(builder);
+
+            var req = new HttpRequestMessage(HttpMethod.Get, "");
+            req.Headers.TryAddWithoutValidation("MS-ASPNETCORE-TOKEN", "TestToken");
+            await server.CreateClient().SendAsync(req);
+
+            Assert.True(assertsExecuted);
+        }
+
+        [Theory]
+        [InlineData(true)]
+        [InlineData(false)]
+        public async Task DoesNotBlowUpWithoutAuth(bool forward)
+        {
+            var assertsExecuted = false;
+
+            var builder = new WebHostBuilder()
+                .UseSetting("TOKEN", "TestToken")
+                .UseSetting("PORT", "12345")
+                .UseSetting("APPL_PATH", "/")
+                .UseIISIntegration()
+                .ConfigureServices(services =>
+                {
+                    services.Configure<IISOptions>(options =>
+                    {
+                        options.ForwardWindowsAuthentication = forward;
+                    });
+                })
+                .Configure(app =>
+                {
+                    app.Run(context =>
+                    {
+                        assertsExecuted = true;
+                        return Task.FromResult(0);
+                    });
+                });
+            var server = new TestServer(builder);
+
+            var req = new HttpRequestMessage(HttpMethod.Get, "");
+            req.Headers.TryAddWithoutValidation("MS-ASPNETCORE-TOKEN", "TestToken");
+            await server.CreateClient().SendAsync(req);
+
+            Assert.True(assertsExecuted);
+        }
+    }
+}
diff --git a/src/IISIntegration/test/Microsoft.AspNetCore.Server.IISIntegration.Tests/Microsoft.AspNetCore.Server.IISIntegration.Tests.csproj b/src/IISIntegration/test/Microsoft.AspNetCore.Server.IISIntegration.Tests/Microsoft.AspNetCore.Server.IISIntegration.Tests.csproj
new file mode 100644
index 0000000000000000000000000000000000000000..ea19c2a1fc8924b2d04a5610691fbf986ae43a0f
--- /dev/null
+++ b/src/IISIntegration/test/Microsoft.AspNetCore.Server.IISIntegration.Tests/Microsoft.AspNetCore.Server.IISIntegration.Tests.csproj
@@ -0,0 +1,18 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <TargetFrameworks>$(StandardTestTfms)</TargetFrameworks>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <ProjectReference Include="..\..\src\Microsoft.AspNetCore.Server.IISIntegration\Microsoft.AspNetCore.Server.IISIntegration.csproj" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <PackageReference Include="Microsoft.AspNetCore.TestHost" Version="$(MicrosoftAspNetCoreTestHostPackageVersion)" />
+    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="$(MicrosoftNETTestSdkPackageVersion)" />
+    <PackageReference Include="xunit.runner.visualstudio" Version="$(XunitRunnerVisualStudioPackageVersion)" />
+    <PackageReference Include="xunit" Version="$(XunitPackageVersion)" />
+  </ItemGroup>
+
+</Project>
diff --git a/src/IISIntegration/test/TestTasks/InjectRequestHandler.cs b/src/IISIntegration/test/TestTasks/InjectRequestHandler.cs
new file mode 100644
index 0000000000000000000000000000000000000000..639428ebd1aa7b68e28f0c0c0478b30681fb0537
--- /dev/null
+++ b/src/IISIntegration/test/TestTasks/InjectRequestHandler.cs
@@ -0,0 +1,62 @@
+// 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.Diagnostics;
+using System.IO;
+using System.Linq;
+using Newtonsoft.Json;
+using Newtonsoft.Json.Linq;
+
+namespace TestTasks
+{
+    public class InjectRequestHandler
+    {
+        private static void Main(string[] args)
+        {
+            var depsFile = args[2];
+            var rid = args[0];
+            var libraryLocation = args[1];
+
+            JToken deps;
+            using (var file = File.OpenText(depsFile))
+            using (JsonTextReader reader = new JsonTextReader(file))
+            {
+                deps = JObject.ReadFrom(reader);
+            }
+
+            var libraryName = "ANCMRH/1.0";
+            var libraries = (JObject)deps["libraries"];
+            var targetName = (JValue)deps["runtimeTarget"]["name"];
+
+            var target = (JObject)deps["targets"][targetName.Value];
+            var targetLibrary = target.Properties().FirstOrDefault(p => p.Name == libraryName);
+            targetLibrary?.Remove();
+            targetLibrary =
+                new JProperty(libraryName, new JObject(
+                    new JProperty("runtimeTargets", new JObject(
+                        new JProperty(libraryLocation.Replace('\\', '/'), new JObject(
+                            new JProperty("rid", rid),
+                            new JProperty("assetType", "native")
+                        ))))));
+            target.AddFirst(targetLibrary);
+
+            var library = libraries.Properties().FirstOrDefault(p => p.Name == libraryName);
+            library?.Remove();
+            library =
+                new JProperty(libraryName, new JObject(
+                    new JProperty("type", "package"),
+                    new JProperty("serviceable", true),
+                    new JProperty("sha512", ""),
+                    new JProperty("path", libraryName),
+                    new JProperty("hashPath", "")));
+            libraries.AddFirst(library);
+            
+            using (var file = File.CreateText(depsFile))
+            using (var writer = new JsonTextWriter(file) { Formatting = Formatting.Indented })
+            {
+                deps.WriteTo(writer);
+            }
+        }
+    }
+}
diff --git a/src/IISIntegration/test/TestTasks/TestTasks.csproj b/src/IISIntegration/test/TestTasks/TestTasks.csproj
new file mode 100644
index 0000000000000000000000000000000000000000..aa4c144936ed01dfef867504051e2955347c7c7a
--- /dev/null
+++ b/src/IISIntegration/test/TestTasks/TestTasks.csproj
@@ -0,0 +1,12 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <OutputType>Exe</OutputType>
+    <TargetFrameworks>$(StandardTestTfms)</TargetFrameworks>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <PackageReference Include="Newtonsoft.Json" Version="$(Tooling_NewtonsoftJsonPackageVersion)" />
+  </ItemGroup>
+
+</Project>
diff --git a/src/IISIntegration/test/WebSites/InProcessWebSite/InProcessWebSite.csproj b/src/IISIntegration/test/WebSites/InProcessWebSite/InProcessWebSite.csproj
new file mode 100644
index 0000000000000000000000000000000000000000..c615d460eebe23c66c23d906167ecca33cb2d7ee
--- /dev/null
+++ b/src/IISIntegration/test/WebSites/InProcessWebSite/InProcessWebSite.csproj
@@ -0,0 +1,21 @@
+<Project Sdk="Microsoft.NET.Sdk.Web">
+  <Import Project="..\..\..\build\testsite.props" />
+
+  <PropertyGroup>
+    <TargetFrameworks>$(StandardTestTfms)</TargetFrameworks>
+  </PropertyGroup>
+  
+  <ItemGroup>
+    <ProjectReference Include="..\..\..\src\Microsoft.AspNetCore.Server.IISIntegration\Microsoft.AspNetCore.Server.IISIntegration.csproj" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <PackageReference Include="Microsoft.AspNetCore.Hosting" Version="$(MicrosoftAspNetCoreHostingPackageVersion)" />
+    <PackageReference Include="Microsoft.AspNetCore.WebUtilities" Version="$(MicrosoftAspNetCoreWebUtilitiesPackageVersion)" />
+    <PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="$(MicrosoftExtensionsConfigurationEnvironmentVariablesPackageVersion)" />
+    <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="$(MicrosoftExtensionsConfigurationJsonPackageVersion)" />
+    <PackageReference Include="Microsoft.Extensions.Logging.Console" Version="$(MicrosoftExtensionsLoggingConsolePackageVersion)" />
+    <PackageReference Include="xunit" Version="$(XunitPackageVersion)" />
+  </ItemGroup>
+
+</Project>
diff --git a/src/IISIntegration/test/WebSites/InProcessWebSite/Program.cs b/src/IISIntegration/test/WebSites/InProcessWebSite/Program.cs
new file mode 100644
index 0000000000000000000000000000000000000000..0550f0f1fdff1267f2a849d79c98f27754c0d13c
--- /dev/null
+++ b/src/IISIntegration/test/WebSites/InProcessWebSite/Program.cs
@@ -0,0 +1,26 @@
+// 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 Microsoft.AspNetCore.Hosting;
+using Microsoft.Extensions.Logging;
+
+namespace IISTestSite
+{
+    public static class Program
+    {
+        public static void Main(string[] args)
+        {
+            var host = new WebHostBuilder()
+                .ConfigureLogging((_, factory) =>
+                {
+                    factory.AddConsole();
+                    factory.AddFilter("Console", level => level >= LogLevel.Information);
+                })
+                .UseIISIntegration()
+                .UseStartup(typeof(Program).Assembly.FullName)
+                .Build();
+
+            host.Run();
+        }
+    }
+}
diff --git a/src/IISIntegration/test/WebSites/InProcessWebSite/Properties/launchSettings.json b/src/IISIntegration/test/WebSites/InProcessWebSite/Properties/launchSettings.json
new file mode 100644
index 0000000000000000000000000000000000000000..6d5ce43f737ab71fa52d0d89e97557c31e99bdc3
--- /dev/null
+++ b/src/IISIntegration/test/WebSites/InProcessWebSite/Properties/launchSettings.json
@@ -0,0 +1,37 @@
+{
+  "iisSettings": {
+    "windowsAuthentication": true,
+    "anonymousAuthentication": true,
+    "iisExpress": {
+      "applicationUrl": "http://localhost:5762/",
+      "sslPort": 0
+    }
+  },
+  "profiles": {
+    "ANCM IIS Express": {
+      "commandName": "Executable",
+      "executablePath": "$(IISExpressPath)",
+      "commandLineArgs": "$(IISExpressArguments)",
+      "nativeDebugging": true,
+      "environmentVariables": {
+        "IIS_SITE_PATH": "$(MSBuildThisFileDirectory)",
+        "ANCM_PATH": "$(TargetDir)$(AncmPath)",
+        "LAUNCHER_ARGS": "$(TargetPath)",
+        "ASPNETCORE_ENVIRONMENT": "Development",
+        "LAUNCHER_PATH": "$(DotNetPath)"
+      }
+    },
+    "ANCM IIS": {
+      "commandName": "Executable",
+      "executablePath": "$(IISPath)",
+      "commandLineArgs": "$(IISArguments)",
+      "environmentVariables": {
+        "IIS_SITE_PATH": "$(MSBuildThisFileDirectory)",
+        "ANCM_PATH": "$(TargetDir)$(AncmPath)",
+        "LAUNCHER_ARGS": "$(TargetPath)",
+        "ASPNETCORE_ENVIRONMENT": "Development",
+        "LAUNCHER_PATH": "$(DotNetPath)"
+      }
+    }
+  }
+}
diff --git a/src/IISIntegration/test/WebSites/InProcessWebSite/Startup.cs b/src/IISIntegration/test/WebSites/InProcessWebSite/Startup.cs
new file mode 100644
index 0000000000000000000000000000000000000000..23cec82f790e64807dcf75e38ca7817976de3d3b
--- /dev/null
+++ b/src/IISIntegration/test/WebSites/InProcessWebSite/Startup.cs
@@ -0,0 +1,684 @@
+// 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.Diagnostics;
+using System.IO;
+using System.Net;
+using System.Reflection;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Authentication;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Http.Features;
+using Microsoft.AspNetCore.Server.IIS;
+using Microsoft.AspNetCore.Server.IISIntegration;
+using Microsoft.Extensions.Primitives;
+using Xunit;
+
+namespace IISTestSite
+{
+    public class Startup
+    {
+        public void Configure(IApplicationBuilder app)
+        {
+            foreach (var method in GetType().GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance))
+            {
+                var parameters = method.GetParameters();
+                if (method.Name != nameof(Configure) &&
+                    parameters.Length == 1 &&
+                    parameters[0].ParameterType == typeof(IApplicationBuilder))
+                {
+                    app.Map("/" + method.Name, innerAppBuilder => method.Invoke(this, new[] { innerAppBuilder }));
+                }
+            }
+        }
+
+        private void ServerVariable(IApplicationBuilder app)
+        {
+            app.Run(async ctx =>
+            {
+                var varName = ctx.Request.Query["q"];
+                await ctx.Response.WriteAsync($"{varName}: {ctx.GetIISServerVariable(varName) ?? "(null)"}");
+            });
+        }
+
+        public void AuthenticationAnonymous(IApplicationBuilder app)
+        {
+            app.Run(async ctx =>
+            {
+                await ctx.Response.WriteAsync("Anonymous?" + !ctx.User.Identity.IsAuthenticated);
+            });
+        }
+
+        private void AuthenticationRestricted(IApplicationBuilder app)
+        {
+            app.Run(async ctx =>
+            {
+                if (ctx.User.Identity.IsAuthenticated)
+                {
+                    await ctx.Response.WriteAsync(ctx.User.Identity.AuthenticationType);
+                }
+                else
+                {
+                    await ctx.ChallengeAsync(IISDefaults.AuthenticationScheme);
+                }
+            });
+        }
+
+        public void AuthenticationForbidden(IApplicationBuilder app)
+        {
+            app.Run(async ctx =>
+            {
+                await ctx.ForbidAsync(IISDefaults.AuthenticationScheme);
+            });
+        }
+
+        public void AuthenticationRestrictedNTLM(IApplicationBuilder app)
+        {
+            app.Run(async ctx =>
+            {
+                if (string.Equals("NTLM", ctx.User.Identity.AuthenticationType, StringComparison.Ordinal))
+                {
+                    await ctx.Response.WriteAsync("NTLM");
+                }
+                else
+                {
+                    await ctx.ChallengeAsync(IISDefaults.AuthenticationScheme);
+                }
+            });
+        }
+
+        private void FeatureCollectionSetRequestFeatures(IApplicationBuilder app)
+        {
+            app.Run(async context =>
+            {
+                try
+                {
+                    Assert.Equal("GET", context.Request.Method);
+                    context.Request.Method = "test";
+                    Assert.Equal("test", context.Request.Method);
+
+                    Assert.Equal("http", context.Request.Scheme);
+                    context.Request.Scheme = "test";
+                    Assert.Equal("test", context.Request.Scheme);
+
+                    Assert.Equal("/FeatureCollectionSetRequestFeatures", context.Request.PathBase);
+                    context.Request.PathBase = "/base";
+                    Assert.Equal("/base", context.Request.PathBase);
+
+                    Assert.Equal("/path", context.Request.Path);
+                    context.Request.Path = "/path";
+                    Assert.Equal("/path", context.Request.Path);
+
+                    Assert.Equal("?query", context.Request.QueryString.Value);
+                    context.Request.QueryString = QueryString.Empty;
+                    Assert.Equal("", context.Request.QueryString.Value);
+
+                    Assert.Equal("HTTP/1.1", context.Request.Protocol);
+                    context.Request.Protocol = "HTTP/1.0";
+                    Assert.Equal("HTTP/1.0", context.Request.Protocol);
+
+                    Assert.NotNull(context.Request.Headers);
+                    var headers = new HeaderDictionary();
+                    context.Features.Get<IHttpRequestFeature>().Headers = headers;
+                    Assert.Same(headers, context.Features.Get<IHttpRequestFeature>().Headers);
+
+                    Assert.NotNull(context.Request.Body);
+                    var body = new MemoryStream();
+                    context.Request.Body = body;
+                    Assert.Same(body, context.Request.Body);
+
+                    //Assert.NotNull(context.Features.Get<IHttpRequestIdentifierFeature>().TraceIdentifier);
+                    //Assert.NotEqual(CancellationToken.None, context.RequestAborted);
+                    //var token = new CancellationTokenSource().Token;
+                    //context.RequestAborted = token;
+                    //Assert.Equal(token, context.RequestAborted);
+
+                    await context.Response.WriteAsync("Success");
+                    return;
+                }
+                catch (Exception exception)
+                {
+                    context.Response.StatusCode = 500;
+                    await context.Response.WriteAsync(exception.ToString());
+                }
+                await context.Response.WriteAsync("_Failure");
+            });
+        }
+
+        private void FeatureCollectionSetResponseFeatures(IApplicationBuilder app)
+        {
+            app.Run(async context =>
+            {
+                try
+                {
+                    Assert.Equal(200, context.Response.StatusCode);
+                    context.Response.StatusCode = 404;
+                    Assert.Equal(404, context.Response.StatusCode);
+                    context.Response.StatusCode = 200;
+
+                    Assert.Null(context.Features.Get<IHttpResponseFeature>().ReasonPhrase);
+                    context.Features.Get<IHttpResponseFeature>().ReasonPhrase = "Set Response";
+                    Assert.Equal("Set Response", context.Features.Get<IHttpResponseFeature>().ReasonPhrase);
+
+                    Assert.NotNull(context.Response.Headers);
+                    var headers = new HeaderDictionary();
+                    context.Features.Get<IHttpResponseFeature>().Headers = headers;
+                    Assert.Same(headers, context.Features.Get<IHttpResponseFeature>().Headers);
+
+                    var originalBody = context.Response.Body;
+                    Assert.NotNull(originalBody);
+                    var body = new MemoryStream();
+                    context.Response.Body = body;
+                    Assert.Same(body, context.Response.Body);
+                    context.Response.Body = originalBody;
+
+                    await context.Response.WriteAsync("Success");
+                    return;
+                }
+                catch (Exception exception)
+                {
+                    context.Response.StatusCode = 500;
+                    await context.Response.WriteAsync(exception.ToString());
+                }
+                await context.Response.WriteAsync("_Failure");
+            });
+        }
+
+        private void FeatureCollectionSetConnectionFeatures(IApplicationBuilder app)
+        {
+            app.Run(async context =>
+            {
+                try
+                {
+                    Assert.True(IPAddress.IsLoopback(context.Connection.LocalIpAddress));
+                    context.Connection.LocalIpAddress = IPAddress.IPv6Any;
+                    Assert.Equal(IPAddress.IPv6Any, context.Connection.LocalIpAddress);
+
+                    Assert.True(IPAddress.IsLoopback(context.Connection.RemoteIpAddress));
+                    context.Connection.RemoteIpAddress = IPAddress.IPv6Any;
+                    Assert.Equal(IPAddress.IPv6Any, context.Connection.RemoteIpAddress);
+                    await context.Response.WriteAsync("Success");
+                    return;
+                }
+                catch (Exception exception)
+                {
+                    context.Response.StatusCode = 500;
+                    await context.Response.WriteAsync(exception.ToString());
+                }
+                await context.Response.WriteAsync("_Failure");
+            });
+        }
+
+        private void Throw(IApplicationBuilder app)
+        {
+            app.Run(ctx => { throw new Exception(); });
+        }
+
+        private void SetCustomErorCode(IApplicationBuilder app)
+        {
+            app.Run(async ctx => {
+                    var feature = ctx.Features.Get<IHttpResponseFeature>();
+                    feature.ReasonPhrase = ctx.Request.Query["reason"];
+                    feature.StatusCode = int.Parse(ctx.Request.Query["code"]);
+                    await ctx.Response.WriteAsync("Body");
+                });
+        }
+
+        private void HelloWorld(IApplicationBuilder app)
+        {
+            app.Run(async ctx =>
+            {
+                if (ctx.Request.Path.Value.StartsWith("/Path"))
+                {
+                    await ctx.Response.WriteAsync(ctx.Request.Path.Value);
+                    return;
+                }
+                if (ctx.Request.Path.Value.StartsWith("/Query"))
+                {
+                    await ctx.Response.WriteAsync(ctx.Request.QueryString.Value);
+                    return;
+                }
+
+                await ctx.Response.WriteAsync("Hello World");
+            });
+        }
+
+        private void LargeResponseBody(IApplicationBuilder app)
+        {
+            app.Run(async context =>
+            {
+                if (int.TryParse(context.Request.Query["length"], out var length))
+                {
+                    await context.Response.WriteAsync(new string('a', length));
+                }
+            });
+        }
+
+        private void ResponseHeaders(IApplicationBuilder app)
+        {
+            app.Run(async context =>
+            {
+                context.Response.Headers["UnknownHeader"] = "test123=foo";
+                context.Response.ContentType = "text/plain";
+                context.Response.Headers["MultiHeader"] = new StringValues(new string[] { "1", "2" });
+                await context.Response.WriteAsync("Request Complete");
+            });
+        }
+
+        private void ResponseInvalidOrdering(IApplicationBuilder app)
+        {
+            app.Run(async context =>
+            {
+                if (context.Request.Path.Equals("/SetStatusCodeAfterWrite"))
+                {
+                    await context.Response.WriteAsync("Started_");
+                    try
+                    {
+                        context.Response.StatusCode = 200;
+                    }
+                    catch (InvalidOperationException)
+                    {
+                        await context.Response.WriteAsync("SetStatusCodeAfterWriteThrew_");
+                    }
+                    await context.Response.WriteAsync("Finished");
+                    return;
+                }
+                else if (context.Request.Path.Equals("/SetHeaderAfterWrite"))
+                {
+                    await context.Response.WriteAsync("Started_");
+                    try
+                    {
+                        context.Response.Headers["This will fail"] = "some value";
+                    }
+                    catch (InvalidOperationException)
+                    {
+                        await context.Response.WriteAsync("SetHeaderAfterWriteThrew_");
+                    }
+                    await context.Response.WriteAsync("Finished");
+                    return;
+                }
+            });
+        }
+
+        private void CheckEnvironmentVariable(IApplicationBuilder app)
+        {
+            app.Run(async context =>
+            {
+                var variable = Environment.GetEnvironmentVariable("ASPNETCORE_INPROCESS_TESTING_VALUE");
+                await context.Response.WriteAsync(variable);
+            });
+        }
+
+        private void CheckEnvironmentLongValueVariable(IApplicationBuilder app)
+        {
+            app.Run(async context =>
+            {
+                var variable = Environment.GetEnvironmentVariable("ASPNETCORE_INPROCESS_TESTING_LONG_VALUE");
+                await context.Response.WriteAsync(variable);
+            });
+        }
+
+        private void CheckAppendedEnvironmentVariable(IApplicationBuilder app)
+        {
+            app.Run(async context =>
+            {
+                var variable = Environment.GetEnvironmentVariable("ProgramFiles");
+                await context.Response.WriteAsync(variable);
+            });
+        }
+
+        private void CheckRemoveAuthEnvironmentVariable(IApplicationBuilder app)
+        {
+            app.Run(async context =>
+            {
+                var variable = Environment.GetEnvironmentVariable("ASPNETCORE_IIS_HTTPAUTH");
+                await context.Response.WriteAsync(variable);
+            });
+        }
+        private void ReadAndWriteSynchronously(IApplicationBuilder app)
+        {
+            app.Run(async context =>
+            {
+                var t2 = Task.Run(() => WriteManyTimesToResponseBody(context));
+                var t1 = Task.Run(() => ReadRequestBody(context));
+                await Task.WhenAll(t1, t2);
+            });
+        }
+
+        private async Task ReadRequestBody(HttpContext context)
+        {
+            var readBuffer = new byte[1];
+            var result = await context.Request.Body.ReadAsync(readBuffer, 0, 1);
+            while (result != 0)
+            {
+                result = await context.Request.Body.ReadAsync(readBuffer, 0, 1);
+            }
+        }
+
+        private async Task WriteManyTimesToResponseBody(HttpContext context)
+        {
+            for (var i = 0; i < 10000; i++)
+            {
+                await context.Response.WriteAsync("hello world");
+            }
+        }
+
+        private void ReadAndWriteEcho(IApplicationBuilder app)
+        {
+            app.Run(async context =>
+            {
+                var readBuffer = new byte[4096];
+                var result = await context.Request.Body.ReadAsync(readBuffer, 0, readBuffer.Length);
+                while (result != 0)
+                {
+                    await context.Response.WriteAsync(Encoding.UTF8.GetString(readBuffer, 0, result));
+                    result = await context.Request.Body.ReadAsync(readBuffer, 0, readBuffer.Length);
+                }
+            });
+        }
+
+        private void ReadAndWriteEchoTwice(IApplicationBuilder app)
+        {
+            app.Run(async context =>
+            {
+                var readBuffer = new byte[4096];
+                var result = await context.Request.Body.ReadAsync(readBuffer, 0, readBuffer.Length);
+                while (result != 0)
+                {
+                    await context.Response.WriteAsync(Encoding.UTF8.GetString(readBuffer, 0, result));
+                    await context.Response.Body.FlushAsync();
+                    await context.Response.WriteAsync(Encoding.UTF8.GetString(readBuffer, 0, result));
+                    await context.Response.Body.FlushAsync();
+                    result = await context.Request.Body.ReadAsync(readBuffer, 0, readBuffer.Length);
+                }
+            });
+        }
+
+        private void ReadAndWriteSlowConnection(IApplicationBuilder app)
+        {
+            app.Run(async context =>
+            {
+                var t2 = Task.Run(() => WriteResponseBodyAFewTimes(context));
+                var t1 = Task.Run(() => ReadRequestBody(context));
+                await Task.WhenAll(t1, t2);
+            });
+        }
+
+        private async Task WriteResponseBodyAFewTimes(HttpContext context)
+        {
+            for (var i = 0; i < 100; i++)
+            {
+                await context.Response.WriteAsync("hello world");
+            }
+        }
+
+        private void WebsocketRequest(IApplicationBuilder app)
+        {
+            app.Run(async context =>
+            {
+                await context.Response.WriteAsync("test");
+            });
+        }
+
+        private void ReadAndWriteCopyToAsync(IApplicationBuilder app)
+        {
+            app.Run(async context =>
+            {
+                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");
+                }
+            });
+        }
+
+        private void TestReadOffsetWorks(IApplicationBuilder app)
+        {
+            app.Run(async ctx =>
+            {
+                var buffer = new byte[11];
+                ctx.Request.Body.Read(buffer, 0, 6);
+                ctx.Request.Body.Read(buffer, 6, 5);
+
+                await ctx.Response.WriteAsync(Encoding.UTF8.GetString(buffer));
+            });
+        }
+
+        private void TestInvalidReadOperations(IApplicationBuilder app)
+        {
+            app.Run(async context =>
+            {
+                var success = false;
+                if (context.Request.Path.StartsWithSegments("/NullBuffer"))
+                {
+                    try
+                    {
+                        await context.Request.Body.ReadAsync(null, 0, 0);
+                    }
+                    catch (Exception)
+                    {
+                        success = true;
+                    }
+                }
+                else if (context.Request.Path.StartsWithSegments("/InvalidOffsetSmall"))
+                {
+                    try
+                    {
+                        await context.Request.Body.ReadAsync(new byte[1], -1, 0);
+                    }
+                    catch (ArgumentOutOfRangeException)
+                    {
+                        success = true;
+                    }
+                }
+                else if (context.Request.Path.StartsWithSegments("/InvalidOffsetLarge"))
+                {
+                    try
+                    {
+                        await context.Request.Body.ReadAsync(new byte[1], 2, 0);
+                    }
+                    catch (ArgumentOutOfRangeException)
+                    {
+                        success = true;
+                    }
+                }
+                else if (context.Request.Path.StartsWithSegments("/InvalidCountSmall"))
+                {
+                    try
+                    {
+                        await context.Request.Body.ReadAsync(new byte[1], 0, -1);
+                    }
+                    catch (ArgumentOutOfRangeException)
+                    {
+                        success = true;
+                    }
+                }
+                else if (context.Request.Path.StartsWithSegments("/InvalidCountLarge"))
+                {
+                    try
+                    {
+                        await context.Request.Body.ReadAsync(new byte[1], 0, -1);
+                    }
+                    catch (ArgumentOutOfRangeException)
+                    {
+                        success = true;
+                    }
+                }
+                else if (context.Request.Path.StartsWithSegments("/InvalidCountWithOffset"))
+                {
+                    try
+                    {
+                        await context.Request.Body.ReadAsync(new byte[3], 1, 3);
+                    }
+                    catch (ArgumentOutOfRangeException)
+                    {
+                        success = true;
+                    }
+                }
+
+
+                await context.Response.WriteAsync(success ? "Success" : "Failure");
+            });
+        }
+
+        private void TestValidReadOperations(IApplicationBuilder app)
+        {
+            app.Run(async context =>
+            {
+                var count = -1;
+
+                if (context.Request.Path.StartsWithSegments("/NullBuffer"))
+                {
+                    count = await context.Request.Body.ReadAsync(null, 0, 0);
+                }
+                else if (context.Request.Path.StartsWithSegments("/NullBufferPost"))
+                {
+                    count = await context.Request.Body.ReadAsync(null, 0, 0);
+                }
+                else if (context.Request.Path.StartsWithSegments("/InvalidCountZeroRead"))
+                {
+                    count = await context.Request.Body.ReadAsync(new byte[1], 0, 0);
+                }
+                else if (context.Request.Path.StartsWithSegments("/InvalidCountZeroReadPost"))
+                {
+                    count = await context.Request.Body.ReadAsync(new byte[1], 0, 0);
+                }
+
+                await context.Response.WriteAsync(count == 0 ? "Success" : "Failure");
+            });
+        }
+
+        private void TestInvalidWriteOperations(IApplicationBuilder app)
+        {
+            app.Run(async context =>
+            {
+                var success = false;
+
+                if (context.Request.Path.StartsWithSegments("/InvalidOffsetSmall"))
+                {
+                    try
+                    {
+                        await context.Response.Body.WriteAsync(new byte[1], -1, 0);
+                    }
+                    catch (ArgumentOutOfRangeException)
+                    {
+                        success = true;
+                    }
+                }
+                else if (context.Request.Path.StartsWithSegments("/InvalidOffsetLarge"))
+                {
+                    try
+                    {
+                        await context.Response.Body.WriteAsync(new byte[1], 2, 0);
+                    }
+                    catch (ArgumentOutOfRangeException)
+                    {
+                        success = true;
+                    }
+                }
+                else if (context.Request.Path.StartsWithSegments("/InvalidCountSmall"))
+                {
+                    try
+                    {
+                        await context.Response.Body.WriteAsync(new byte[1], 0, -1);
+                    }
+                    catch (ArgumentOutOfRangeException)
+                    {
+                        success = true;
+                    }
+                }
+                else if (context.Request.Path.StartsWithSegments("/InvalidCountLarge"))
+                {
+                    try
+                    {
+                        await context.Response.Body.WriteAsync(new byte[1], 0, -1);
+                    }
+                    catch (ArgumentOutOfRangeException)
+                    {
+                        success = true;
+                    }
+                }
+                else if (context.Request.Path.StartsWithSegments("/InvalidCountWithOffset"))
+                {
+                    try
+                    {
+                        await context.Response.Body.WriteAsync(new byte[3], 1, 3);
+                    }
+                    catch (ArgumentOutOfRangeException)
+                    {
+                        success = true;
+                    }
+                }
+
+                await context.Response.WriteAsync(success ? "Success" : "Failure");
+            });
+        }
+
+        private void TestValidWriteOperations(IApplicationBuilder app)
+        {
+            app.Run(async context =>
+            {
+
+                if (context.Request.Path.StartsWithSegments("/NullBuffer"))
+                {
+                    await context.Response.Body.WriteAsync(null, 0, 0);
+                }
+                else if (context.Request.Path.StartsWithSegments("/NullBufferPost"))
+                {
+                    await context.Response.Body.WriteAsync(null, 0, 0);
+                }
+
+                await context.Response.WriteAsync("Success");
+            });
+        }
+
+        private void LargeResponseFile(IApplicationBuilder app)
+        {
+            app.Run(async ctx =>
+            {
+                var tempFile = Path.GetTempFileName();
+                var fileContent = new string('a', 200000);
+                var fileStream = File.OpenWrite(tempFile);
+
+                for (var i = 0; i < 1000; i++)
+                {
+                    await fileStream.WriteAsync(Encoding.UTF8.GetBytes(fileContent), 0, fileContent.Length);
+                }
+                fileStream.Close();
+
+                await ctx.Response.SendFileAsync(tempFile, 0, null);
+
+                // Try to delete the file from the temp directory. If it fails, don't report an error
+                // to the application. File should eventually be cleaned up from the temp directory
+                // by OS.
+                try
+                {
+                    File.Delete(tempFile);
+                }
+                catch (Exception)
+                {
+                }
+            });
+        }
+
+        private void BasePath(IApplicationBuilder app)
+        {
+            app.Run(async ctx => { await ctx.Response.WriteAsync(AppDomain.CurrentDomain.BaseDirectory); });
+        }
+    }
+}
diff --git a/src/IISIntegration/test/WebSites/InProcessWebSite/web.config b/src/IISIntegration/test/WebSites/InProcessWebSite/web.config
new file mode 100644
index 0000000000000000000000000000000000000000..8ba96a4e9ecbef249cb92dd19af5b0d911fe4130
--- /dev/null
+++ b/src/IISIntegration/test/WebSites/InProcessWebSite/web.config
@@ -0,0 +1,16 @@
+<?xml version="1.0"?>
+<configuration>
+  <system.webServer>
+    <handlers>
+      <add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModule" resourceType="Unspecified" />
+    </handlers>
+    <aspNetCore processPath="%LAUNCHER_PATH%" arguments="%LAUNCHER_ARGS%" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" forwardWindowsAuthToken="false" hostingModel="inprocess">
+      <environmentVariables>
+        <environmentVariable name="ASPNETCORE_INPROCESS_TESTING_VALUE" value="foobar" />
+        <environmentVariable name="ASPNETCORE_INPROCESS_TESTING_LONG_VALUE" value="AReallyLongValueThatIsGreaterThan300CharactersToForceResizeInNativeAReallyLongValueThatIsGreaterThan300CharactersToForceResizeInNativeAReallyLongValueThatIsGreaterThan300CharactersToForceResizeInNativeAReallyLongValueThatIsGreaterThan300CharactersToForceResizeInNativeAReallyLongValueThatIsGreaterThan300CharactersToForceResizeInNativeAReallyLongValueThatIsGreaterThan300CharactersToForceResizeInNative" />
+        <environmentVariable name="ProgramFiles" value="foobarbaz" />
+        <environmentVariable name="ASPNETCORE_IIS_HTTPAUTH" value="shouldberemoved"/>
+      </environmentVariables>
+    </aspNetCore>
+  </system.webServer>
+</configuration>
diff --git a/src/IISIntegration/test/WebSites/OutOfProcessWebSite/OutOfProcessWebSite.csproj b/src/IISIntegration/test/WebSites/OutOfProcessWebSite/OutOfProcessWebSite.csproj
new file mode 100644
index 0000000000000000000000000000000000000000..0b96c98c36fda8478e75c31731669e4af344695c
--- /dev/null
+++ b/src/IISIntegration/test/WebSites/OutOfProcessWebSite/OutOfProcessWebSite.csproj
@@ -0,0 +1,22 @@
+<Project Sdk="Microsoft.NET.Sdk.Web">
+
+  <Import Project="..\..\..\build\testsite.props" />
+
+  <PropertyGroup>
+    <TargetFrameworks>$(StandardTestTfms)</TargetFrameworks>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <ProjectReference Include="..\..\..\src\Microsoft.AspNetCore.Server.IISIntegration\Microsoft.AspNetCore.Server.IISIntegration.csproj" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="$(MicrosoftAspNetCoreServerKestrelPackageVersion)" />
+    <PackageReference Include="Microsoft.AspNetCore.WebUtilities" Version="$(MicrosoftAspNetCoreWebUtilitiesPackageVersion)" />
+    <PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="$(MicrosoftExtensionsConfigurationEnvironmentVariablesPackageVersion)" />
+    <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="$(MicrosoftExtensionsConfigurationJsonPackageVersion)" />
+    <PackageReference Include="Microsoft.Extensions.Logging.Console" Version="$(MicrosoftExtensionsLoggingConsolePackageVersion)" />
+    <PackageReference Include="xunit" Version="$(XunitPackageVersion)" />
+  </ItemGroup>
+
+</Project>
diff --git a/src/IISIntegration/test/WebSites/OutOfProcessWebSite/Program.cs b/src/IISIntegration/test/WebSites/OutOfProcessWebSite/Program.cs
new file mode 100644
index 0000000000000000000000000000000000000000..18104fa30a59888561bc1b946d53d96522d5d093
--- /dev/null
+++ b/src/IISIntegration/test/WebSites/OutOfProcessWebSite/Program.cs
@@ -0,0 +1,28 @@
+// 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 Microsoft.AspNetCore.Hosting;
+using Microsoft.Extensions.Logging;
+
+namespace TestSites
+{
+    public static class Program
+    {
+        public static void Main(string[] args)
+        {
+            var host = new WebHostBuilder()
+                .ConfigureLogging((_, factory) =>
+                {
+                    factory.AddConsole();
+                    factory.AddFilter("Console", level => level >= LogLevel.Information);
+                })
+                .UseIISIntegration()
+                .UseStartup(typeof(Program).Assembly.FullName)
+                .UseKestrel()
+                .Build();
+
+            host.Run();
+        }
+    }
+}
+
diff --git a/src/IISIntegration/test/WebSites/OutOfProcessWebSite/Properties/launchSettings.json b/src/IISIntegration/test/WebSites/OutOfProcessWebSite/Properties/launchSettings.json
new file mode 100644
index 0000000000000000000000000000000000000000..6d5ce43f737ab71fa52d0d89e97557c31e99bdc3
--- /dev/null
+++ b/src/IISIntegration/test/WebSites/OutOfProcessWebSite/Properties/launchSettings.json
@@ -0,0 +1,37 @@
+{
+  "iisSettings": {
+    "windowsAuthentication": true,
+    "anonymousAuthentication": true,
+    "iisExpress": {
+      "applicationUrl": "http://localhost:5762/",
+      "sslPort": 0
+    }
+  },
+  "profiles": {
+    "ANCM IIS Express": {
+      "commandName": "Executable",
+      "executablePath": "$(IISExpressPath)",
+      "commandLineArgs": "$(IISExpressArguments)",
+      "nativeDebugging": true,
+      "environmentVariables": {
+        "IIS_SITE_PATH": "$(MSBuildThisFileDirectory)",
+        "ANCM_PATH": "$(TargetDir)$(AncmPath)",
+        "LAUNCHER_ARGS": "$(TargetPath)",
+        "ASPNETCORE_ENVIRONMENT": "Development",
+        "LAUNCHER_PATH": "$(DotNetPath)"
+      }
+    },
+    "ANCM IIS": {
+      "commandName": "Executable",
+      "executablePath": "$(IISPath)",
+      "commandLineArgs": "$(IISArguments)",
+      "environmentVariables": {
+        "IIS_SITE_PATH": "$(MSBuildThisFileDirectory)",
+        "ANCM_PATH": "$(TargetDir)$(AncmPath)",
+        "LAUNCHER_ARGS": "$(TargetPath)",
+        "ASPNETCORE_ENVIRONMENT": "Development",
+        "LAUNCHER_PATH": "$(DotNetPath)"
+      }
+    }
+  }
+}
diff --git a/src/IISIntegration/test/WebSites/OutOfProcessWebSite/StartupHelloWorld.cs b/src/IISIntegration/test/WebSites/OutOfProcessWebSite/StartupHelloWorld.cs
new file mode 100644
index 0000000000000000000000000000000000000000..a406626ede590e4819db20dd91157ddf0d67dae5
--- /dev/null
+++ b/src/IISIntegration/test/WebSites/OutOfProcessWebSite/StartupHelloWorld.cs
@@ -0,0 +1,58 @@
+// 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 StartupHelloWorld
+    {
+        public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory)
+        {
+            app.Run(async ctx =>
+            {
+                if (ctx.Request.Path.Value.StartsWith("/Path"))
+                {
+                    await ctx.Response.WriteAsync(ctx.Request.Path.Value);
+                    return;
+                }
+                if (ctx.Request.Path.Value.StartsWith("/Query"))
+                {
+                    await ctx.Response.WriteAsync(ctx.Request.QueryString.Value);
+                    return;
+                }
+                if (ctx.Request.Path.Value.StartsWith("/BodyLimit"))
+                {
+                    await ctx.Response.WriteAsync(
+                        ctx.Features.Get<IHttpMaxRequestBodySizeFeature>()?.MaxRequestBodySize?.ToString() ?? "null");
+                    return;
+                }
+
+                if (ctx.Request.Path.StartsWithSegments("/Auth"))
+                {
+                    var iisAuth = Environment.GetEnvironmentVariable("ASPNETCORE_IIS_HTTPAUTH");
+                    var authProvider = ctx.RequestServices.GetService<IAuthenticationSchemeProvider>();
+                    var authScheme = (await authProvider.GetAllSchemesAsync()).SingleOrDefault();
+                    if (string.IsNullOrEmpty(iisAuth))
+                    {
+                        await ctx.Response.WriteAsync("backcompat;" + (authScheme?.Name ?? "null"));
+                    }
+                    else
+                    {
+                        await ctx.Response.WriteAsync("latest;" + (authScheme?.Name ?? "null"));
+                    }
+                    return;
+                }
+
+                await ctx.Response.WriteAsync("Hello World");
+            });
+        }
+    }
+}
diff --git a/src/IISIntegration/test/WebSites/OutOfProcessWebSite/StartupHttpsHelloWorld.cs b/src/IISIntegration/test/WebSites/OutOfProcessWebSite/StartupHttpsHelloWorld.cs
new file mode 100644
index 0000000000000000000000000000000000000000..3d9c7a92f73001a20f5f9f1971e4a33a73210098
--- /dev/null
+++ b/src/IISIntegration/test/WebSites/OutOfProcessWebSite/StartupHttpsHelloWorld.cs
@@ -0,0 +1,25 @@
+// 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 Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Http;
+using Microsoft.Extensions.Logging;
+
+namespace TestSites
+{
+    public class StartupHttpsHelloWorld
+    {
+        public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory)
+        {
+            app.Run(ctx =>
+            {
+                if (ctx.Request.Path.Equals(new PathString("/checkclientcert")))
+                {
+                    return ctx.Response.WriteAsync("Scheme:" + ctx.Request.Scheme + "; Original:" + ctx.Request.Headers["x-original-proto"]
+                        + "; has cert? " + (ctx.Connection.ClientCertificate != null));
+                }
+                return ctx.Response.WriteAsync("Scheme:" + ctx.Request.Scheme + "; Original:" + ctx.Request.Headers["x-original-proto"]);
+            });
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/IISIntegration/test/WebSites/OutOfProcessWebSite/StartupNtlmAuthentication.cs b/src/IISIntegration/test/WebSites/OutOfProcessWebSite/StartupNtlmAuthentication.cs
new file mode 100644
index 0000000000000000000000000000000000000000..29098ca70276dc4d05a82c4ef1c3eaf06ac94649
--- /dev/null
+++ b/src/IISIntegration/test/WebSites/OutOfProcessWebSite/StartupNtlmAuthentication.cs
@@ -0,0 +1,80 @@
+// 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.Security.Principal;
+using Microsoft.AspNetCore.Authentication;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Server.IISIntegration;
+using Microsoft.Extensions.Logging;
+using Xunit;
+
+namespace TestSites
+{
+    public class StartupNtlmAuthentication
+    {
+        public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory)
+        {
+            // Simple error page without depending on Diagnostics.
+            app.Use(async (context, next) =>
+            {
+                try
+                {
+                    await next();
+                }
+                catch (Exception ex)
+                {
+                    if (context.Response.HasStarted)
+                    {
+                        throw;
+                    }
+
+                    context.Response.Clear();
+                    context.Response.StatusCode = 500;
+                    await context.Response.WriteAsync(ex.ToString());
+                }
+            });
+
+            app.Use((context, next) =>
+            {
+                if (context.Request.Path.Equals("/Anonymous"))
+                {
+                    return context.Response.WriteAsync("Anonymous?" + !context.User.Identity.IsAuthenticated);
+                }
+
+                if (context.Request.Path.Equals("/Restricted"))
+                {
+                    if (context.User.Identity.IsAuthenticated)
+                    {
+                        Assert.IsType<WindowsPrincipal>(context.User);
+                        return context.Response.WriteAsync(context.User.Identity.AuthenticationType);
+                    }
+                    else
+                    {
+                        return context.ChallengeAsync(IISDefaults.AuthenticationScheme);
+                    }
+                }
+
+                if (context.Request.Path.Equals("/Forbidden"))
+                {
+                    return context.ForbidAsync(IISDefaults.AuthenticationScheme);
+                }
+
+                if (context.Request.Path.Equals("/RestrictedNTLM"))
+                {
+                    if (string.Equals("NTLM", context.User.Identity.AuthenticationType, StringComparison.Ordinal))
+                    {
+                        return context.Response.WriteAsync("NTLM");
+                    }
+                    else
+                    {
+                        return context.ChallengeAsync(IISDefaults.AuthenticationScheme);
+                    }
+                }
+
+                return context.Response.WriteAsync("Hello World");
+            });
+        }
+    }
+}
diff --git a/src/IISIntegration/test/WebSites/OutOfProcessWebSite/StartupUpgradeFeatureDetection.cs b/src/IISIntegration/test/WebSites/OutOfProcessWebSite/StartupUpgradeFeatureDetection.cs
new file mode 100644
index 0000000000000000000000000000000000000000..81bc3149a005345c00cce8f65e0c8b3a6aa3ed3d
--- /dev/null
+++ b/src/IISIntegration/test/WebSites/OutOfProcessWebSite/StartupUpgradeFeatureDetection.cs
@@ -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");
+                }
+            });
+        }
+    }
+}
diff --git a/src/IISIntegration/test/WebSites/OutOfProcessWebSite/web.config b/src/IISIntegration/test/WebSites/OutOfProcessWebSite/web.config
new file mode 100644
index 0000000000000000000000000000000000000000..8286b650fe40eb09e2c61bb1e56d925002618902
--- /dev/null
+++ b/src/IISIntegration/test/WebSites/OutOfProcessWebSite/web.config
@@ -0,0 +1,9 @@
+<?xml version="1.0"?>
+<configuration>
+  <system.webServer>
+    <handlers>
+      <add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModule" resourceType="Unspecified" />
+    </handlers>
+    <aspNetCore processPath="%LAUNCHER_PATH%" arguments="%LAUNCHER_ARGS%" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" />
+  </system.webServer>
+</configuration>
diff --git a/src/IISIntegration/test/WebSites/OverriddenServerWebSite/OverriddenServerWebSite.csproj b/src/IISIntegration/test/WebSites/OverriddenServerWebSite/OverriddenServerWebSite.csproj
new file mode 100644
index 0000000000000000000000000000000000000000..4332ea3fd1f34ff17a4f607886b0bc9f594b8bf7
--- /dev/null
+++ b/src/IISIntegration/test/WebSites/OverriddenServerWebSite/OverriddenServerWebSite.csproj
@@ -0,0 +1,17 @@
+<Project Sdk="Microsoft.NET.Sdk.Web">
+
+  <Import Project="..\..\..\build\testsite.props" />
+
+  <PropertyGroup>
+    <TargetFrameworks>$(StandardTestTfms)</TargetFrameworks>
+  </PropertyGroup>
+  
+  <ItemGroup>
+    <ProjectReference Include="..\..\..\src\Microsoft.AspNetCore.Server.IISIntegration\Microsoft.AspNetCore.Server.IISIntegration.csproj" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <PackageReference Include="Microsoft.AspNetCore.Hosting" Version="$(MicrosoftAspNetCoreHostingPackageVersion)" />
+  </ItemGroup>
+
+</Project>
diff --git a/src/IISIntegration/test/WebSites/OverriddenServerWebSite/Program.cs b/src/IISIntegration/test/WebSites/OverriddenServerWebSite/Program.cs
new file mode 100644
index 0000000000000000000000000000000000000000..bb65e0300494d0a40100c96db7835027a7fdfd9d
--- /dev/null
+++ b/src/IISIntegration/test/WebSites/OverriddenServerWebSite/Program.cs
@@ -0,0 +1,48 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.AspNetCore.Hosting.Server;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Http.Features;
+using Microsoft.Extensions.DependencyInjection;
+
+namespace IISTestSite
+{
+    public static class Program
+    {
+        public static void Main(string[] args)
+        {
+            var host = new WebHostBuilder()
+                .UseIISIntegration()
+                .ConfigureServices(services => services.AddSingleton<IServer, DummyServer>())
+                .Configure(builder => builder.Run(async context => { await context.Response.WriteAsync("I shouldn't work"); }))
+                .Build();
+
+            host.Run();
+        }
+    }
+
+    public class DummyServer: IServer
+    {
+        public void Dispose()
+        {
+        }
+
+        public Task StartAsync<TContext>(IHttpApplication<TContext> application, CancellationToken cancellationToken)
+        {
+            return Task.Delay(TimeSpan.MaxValue);
+        }
+
+        public Task StopAsync(CancellationToken cancellationToken)
+        {
+            return Task.Delay(TimeSpan.MaxValue);
+        }
+
+        public IFeatureCollection Features { get; }
+    }
+}
diff --git a/src/IISIntegration/test/WebSites/OverriddenServerWebSite/Properties/launchSettings.json b/src/IISIntegration/test/WebSites/OverriddenServerWebSite/Properties/launchSettings.json
new file mode 100644
index 0000000000000000000000000000000000000000..6d5ce43f737ab71fa52d0d89e97557c31e99bdc3
--- /dev/null
+++ b/src/IISIntegration/test/WebSites/OverriddenServerWebSite/Properties/launchSettings.json
@@ -0,0 +1,37 @@
+{
+  "iisSettings": {
+    "windowsAuthentication": true,
+    "anonymousAuthentication": true,
+    "iisExpress": {
+      "applicationUrl": "http://localhost:5762/",
+      "sslPort": 0
+    }
+  },
+  "profiles": {
+    "ANCM IIS Express": {
+      "commandName": "Executable",
+      "executablePath": "$(IISExpressPath)",
+      "commandLineArgs": "$(IISExpressArguments)",
+      "nativeDebugging": true,
+      "environmentVariables": {
+        "IIS_SITE_PATH": "$(MSBuildThisFileDirectory)",
+        "ANCM_PATH": "$(TargetDir)$(AncmPath)",
+        "LAUNCHER_ARGS": "$(TargetPath)",
+        "ASPNETCORE_ENVIRONMENT": "Development",
+        "LAUNCHER_PATH": "$(DotNetPath)"
+      }
+    },
+    "ANCM IIS": {
+      "commandName": "Executable",
+      "executablePath": "$(IISPath)",
+      "commandLineArgs": "$(IISArguments)",
+      "environmentVariables": {
+        "IIS_SITE_PATH": "$(MSBuildThisFileDirectory)",
+        "ANCM_PATH": "$(TargetDir)$(AncmPath)",
+        "LAUNCHER_ARGS": "$(TargetPath)",
+        "ASPNETCORE_ENVIRONMENT": "Development",
+        "LAUNCHER_PATH": "$(DotNetPath)"
+      }
+    }
+  }
+}
diff --git a/src/IISIntegration/test/WebSites/OverriddenServerWebSite/web.config b/src/IISIntegration/test/WebSites/OverriddenServerWebSite/web.config
new file mode 100644
index 0000000000000000000000000000000000000000..f125d57107371d8dfc4e0a981d66c904ddf28b0c
--- /dev/null
+++ b/src/IISIntegration/test/WebSites/OverriddenServerWebSite/web.config
@@ -0,0 +1,9 @@
+<?xml version="1.0"?>
+<configuration>
+  <system.webServer>
+    <handlers>
+      <add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModule" resourceType="Unspecified" />
+    </handlers>
+    <aspNetCore processPath="%LAUNCHER_PATH%" arguments="%LAUNCHER_ARGS%" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" forwardWindowsAuthToken="false" hostingModel="inprocess" />
+  </system.webServer>
+</configuration>
diff --git a/src/IISIntegration/test/WebSites/StressTestWebSite/Program.cs b/src/IISIntegration/test/WebSites/StressTestWebSite/Program.cs
new file mode 100644
index 0000000000000000000000000000000000000000..e8e5392c2c7269b067b512e442dc7ca8ea5adda2
--- /dev/null
+++ b/src/IISIntegration/test/WebSites/StressTestWebSite/Program.cs
@@ -0,0 +1,26 @@
+// 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 Microsoft.AspNetCore.Hosting;
+using Microsoft.Extensions.Logging;
+
+namespace ANCMStressTestApp
+{
+    public class Program
+    {
+        public static void Main(string[] args)
+        {
+            var host = new WebHostBuilder()
+                .ConfigureLogging((_, factory) =>
+                {
+                    factory.AddConsole();
+                })
+                .UseKestrel()
+                .UseIISIntegration()
+                .UseStartup<Startup>()
+                .Build();
+
+            host.Run();
+        }
+    }
+}
diff --git a/src/IISIntegration/test/WebSites/StressTestWebSite/Properties/launchSettings.json b/src/IISIntegration/test/WebSites/StressTestWebSite/Properties/launchSettings.json
new file mode 100644
index 0000000000000000000000000000000000000000..6d5ce43f737ab71fa52d0d89e97557c31e99bdc3
--- /dev/null
+++ b/src/IISIntegration/test/WebSites/StressTestWebSite/Properties/launchSettings.json
@@ -0,0 +1,37 @@
+{
+  "iisSettings": {
+    "windowsAuthentication": true,
+    "anonymousAuthentication": true,
+    "iisExpress": {
+      "applicationUrl": "http://localhost:5762/",
+      "sslPort": 0
+    }
+  },
+  "profiles": {
+    "ANCM IIS Express": {
+      "commandName": "Executable",
+      "executablePath": "$(IISExpressPath)",
+      "commandLineArgs": "$(IISExpressArguments)",
+      "nativeDebugging": true,
+      "environmentVariables": {
+        "IIS_SITE_PATH": "$(MSBuildThisFileDirectory)",
+        "ANCM_PATH": "$(TargetDir)$(AncmPath)",
+        "LAUNCHER_ARGS": "$(TargetPath)",
+        "ASPNETCORE_ENVIRONMENT": "Development",
+        "LAUNCHER_PATH": "$(DotNetPath)"
+      }
+    },
+    "ANCM IIS": {
+      "commandName": "Executable",
+      "executablePath": "$(IISPath)",
+      "commandLineArgs": "$(IISArguments)",
+      "environmentVariables": {
+        "IIS_SITE_PATH": "$(MSBuildThisFileDirectory)",
+        "ANCM_PATH": "$(TargetDir)$(AncmPath)",
+        "LAUNCHER_ARGS": "$(TargetPath)",
+        "ASPNETCORE_ENVIRONMENT": "Development",
+        "LAUNCHER_PATH": "$(DotNetPath)"
+      }
+    }
+  }
+}
diff --git a/src/IISIntegration/test/WebSites/StressTestWebSite/Startup.cs b/src/IISIntegration/test/WebSites/StressTestWebSite/Startup.cs
new file mode 100644
index 0000000000000000000000000000000000000000..be0969ec77640f0607717d690ea9f42ed84c6358
--- /dev/null
+++ b/src/IISIntegration/test/WebSites/StressTestWebSite/Startup.cs
@@ -0,0 +1,231 @@
+// 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.Linq;
+using System.Threading.Tasks;
+using System.Threading;
+using System.Text;
+using System.Net.WebSockets;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Http.Features;
+using Microsoft.Net.Http.Headers;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Primitives;
+
+namespace ANCMStressTestApp
+{
+    public class Startup
+    {
+        // This method gets called by the runtime. Use this method to add services to the container.
+        // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
+        public void ConfigureServices(IServiceCollection services)
+        {
+        }
+
+        public void Configure(IApplicationBuilder app)
+        {
+            app.Map("/HelloWorld", HelloWorld);
+            app.Map("/ConnectionClose", ConnectionClose);
+            app.Map("/EchoPostData", EchoPostData);
+            app.Map("/LargeResponseBody", LargeResponseBody);
+            app.Map("/ResponseHeaders", ResponseHeaders);
+            app.Map("/EnvironmentVariables", EnvironmentVariables);
+            app.Map("/RequestInformation", RequestInformation);
+            app.Map("/WebSocket", WebSocket);
+
+            app.Run(async context =>
+            {
+                await context.Response.WriteAsync("Default Page");
+            });
+        }
+
+        private void HelloWorld(IApplicationBuilder app)
+        {
+            app.Run(async context =>
+            {
+                await context.Response.WriteAsync("Hello World");
+            });
+        }
+
+        private void ConnectionClose(IApplicationBuilder app)
+        {
+            app.Run(async context =>
+            {
+                context.Response.Headers[HeaderNames.Connection] = "close";
+                await context.Response.WriteAsync("Connnection Close");
+                await context.Response.Body.FlushAsync();
+            });
+        }
+
+        private void EchoPostData(IApplicationBuilder app)
+        {
+            app.Run(async context =>
+            {
+                string responseBody = string.Empty;
+
+                if (string.Equals(context.Request.Method, "POST", StringComparison.OrdinalIgnoreCase))
+                {
+                    using (StreamReader reader = new StreamReader(context.Request.Body, Encoding.UTF8))
+                    {
+                        responseBody = await reader.ReadToEndAsync();
+                    }
+                }
+                else
+                {
+                    responseBody = "NoAction";
+                }
+
+                await context.Response.WriteAsync(responseBody);
+            });
+        }
+
+        private void LargeResponseBody(IApplicationBuilder app)
+        {
+            app.Run(async context =>
+            {
+                if (int.TryParse(context.Request.Query["length"], out var length))
+                {
+                    await context.Response.WriteAsync(new string('a', length));
+                }
+            });
+        }
+
+        private void ResponseHeaders(IApplicationBuilder app)
+        {
+            app.Run(async context =>
+            {
+                context.Response.Headers["UnknownHeader"] = "test123=foo";
+                context.Response.ContentType = "text/plain";
+                context.Response.Headers["MultiHeader"] = new StringValues(new string[] { "1", "2" });
+                await context.Response.WriteAsync("Request Complete");
+            });
+        }
+
+        private void EnvironmentVariables(IApplicationBuilder app)
+        {
+            app.Run(async context =>
+            {
+                context.Response.ContentType = "text/plain";
+                await context.Response.WriteAsync("Environment Variables:" + Environment.NewLine);
+                var vars = Environment.GetEnvironmentVariables();
+                foreach (var key in vars.Keys.Cast<string>().OrderBy(key => key, StringComparer.OrdinalIgnoreCase))
+                {
+                    var value = vars[key];
+                    await context.Response.WriteAsync(key + ": " + value + Environment.NewLine);
+                }
+                await context.Response.WriteAsync(Environment.NewLine);
+            });
+        }
+
+        private void RequestInformation(IApplicationBuilder app)
+        {
+            app.Run(async context =>
+            {
+                context.Response.ContentType = "text/plain";
+
+                await context.Response.WriteAsync("Address:" + Environment.NewLine);
+                await context.Response.WriteAsync("Scheme: " + context.Request.Scheme + Environment.NewLine);
+                await context.Response.WriteAsync("Host: " + context.Request.Headers["Host"] + Environment.NewLine);
+                await context.Response.WriteAsync("PathBase: " + context.Request.PathBase.Value + Environment.NewLine);
+                await context.Response.WriteAsync("Path: " + context.Request.Path.Value + Environment.NewLine);
+                await context.Response.WriteAsync("Query: " + context.Request.QueryString.Value + Environment.NewLine);
+                await context.Response.WriteAsync(Environment.NewLine);
+
+                await context.Response.WriteAsync("Connection:" + Environment.NewLine);
+                await context.Response.WriteAsync("RemoteIp: " + context.Connection.RemoteIpAddress + Environment.NewLine);
+                await context.Response.WriteAsync("RemotePort: " + context.Connection.RemotePort + Environment.NewLine);
+                await context.Response.WriteAsync("LocalIp: " + context.Connection.LocalIpAddress + Environment.NewLine);
+                await context.Response.WriteAsync("LocalPort: " + context.Connection.LocalPort + Environment.NewLine);
+                await context.Response.WriteAsync(Environment.NewLine);
+
+                await context.Response.WriteAsync("Headers:" + Environment.NewLine);
+                foreach (var header in context.Request.Headers)
+                {
+                    await context.Response.WriteAsync(header.Key + ": " + header.Value + Environment.NewLine);
+                }
+                await context.Response.WriteAsync(Environment.NewLine);
+            });
+        }
+
+        private void WebSocket(IApplicationBuilder app)
+        {
+            app.Run(async context =>
+            {
+                var upgradeFeature = context.Features.Get<IHttpUpgradeFeature>();
+
+                // Generate WebSocket response headers
+                string key = context.Request.Headers[Constants.Headers.SecWebSocketKey].ToString();
+                var responseHeaders = HandshakeHelpers.GenerateResponseHeaders(key);
+                foreach (var headerPair in responseHeaders)
+                {
+                    context.Response.Headers[headerPair.Key] = headerPair.Value;
+                }
+
+                // Upgrade the connection
+                Stream opaqueTransport = await upgradeFeature.UpgradeAsync();
+
+                // Get the WebSocket object
+                var ws = WebSocketProtocol.CreateFromStream(opaqueTransport, isServer: true, subProtocol: null, keepAliveInterval: TimeSpan.FromMinutes(2));
+
+                var appLifetime = app.ApplicationServices.GetRequiredService<IApplicationLifetime>();
+
+                await Echo(ws, appLifetime.ApplicationStopping);
+            });
+        }
+
+        private async Task Echo(WebSocket webSocket, CancellationToken token)
+        {
+            try
+            {
+                var buffer = new byte[1024 * 4];
+                var result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), token);
+                bool closeFromServer = false;
+                string closeFromServerCmd = "CloseFromServer";
+                int closeFromServerLength = closeFromServerCmd.Length;
+
+                while (!result.CloseStatus.HasValue && !token.IsCancellationRequested && !closeFromServer)
+                {
+                    if (result.Count == closeFromServerLength &&
+                        Encoding.ASCII.GetString(buffer).Substring(0, result.Count) == closeFromServerCmd)
+                    {
+                        // The client sent "CloseFromServer" text message to request the server to close (a test scenario).
+                        closeFromServer = true;
+                    }
+                    else
+                    {
+                        await webSocket.SendAsync(new ArraySegment<byte>(buffer, 0, result.Count), result.MessageType, result.EndOfMessage, token);
+                        result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), token);
+                    }
+                }
+
+                if (result.CloseStatus.HasValue)
+                {
+                    // Client-initiated close handshake
+                    await webSocket.CloseAsync(result.CloseStatus.Value, result.CloseStatusDescription, CancellationToken.None);
+                }
+                else
+                {
+                    // Server-initiated close handshake due to either of the two conditions:
+                    // (1) The applicaton host is performing a graceful shutdown.
+                    // (2) The client sent "CloseFromServer" text message to request the server to close (a test scenario).
+                    await webSocket.CloseOutputAsync(WebSocketCloseStatus.NormalClosure, closeFromServerCmd, CancellationToken.None);
+
+                    // The server has sent the Close frame.
+                    // Stop sending but keep receiving until we get the Close frame from the client.
+                    while (!result.CloseStatus.HasValue)
+                    {
+                        result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
+                    }
+                }
+            }
+            catch (Exception e)
+            {
+                Console.WriteLine("{0} Exception caught!", e);
+            }
+        }
+    }
+}
diff --git a/src/IISIntegration/test/WebSites/StressTestWebSite/StressTestWebSite.csproj b/src/IISIntegration/test/WebSites/StressTestWebSite/StressTestWebSite.csproj
new file mode 100644
index 0000000000000000000000000000000000000000..3566143fcdf3ca5522fefb000182c8a7c2aac5f4
--- /dev/null
+++ b/src/IISIntegration/test/WebSites/StressTestWebSite/StressTestWebSite.csproj
@@ -0,0 +1,19 @@
+<Project Sdk="Microsoft.NET.Sdk.Web">
+
+  <Import Project="..\..\..\build\testsite.props" />
+
+  <PropertyGroup>
+    <TargetFrameworks>$(StandardTestTfms)</TargetFrameworks>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <ProjectReference Include="..\..\..\src\Microsoft.AspNetCore.Server.IISIntegration\Microsoft.AspNetCore.Server.IISIntegration.csproj" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="$(MicrosoftAspNetCoreServerKestrelPackageVersion)" />
+    <PackageReference Include="Microsoft.Extensions.Logging.Console" Version="$(MicrosoftExtensionsLoggingConsolePackageVersion)" />
+    <PackageReference Include="System.Net.WebSockets.WebSocketProtocol" Version="$(SystemNetWebSocketsWebSocketProtocolPackageVersion)" />
+  </ItemGroup>
+
+</Project>
diff --git a/src/IISIntegration/test/WebSites/StressTestWebSite/WebSockets/Constants.cs b/src/IISIntegration/test/WebSites/StressTestWebSite/WebSockets/Constants.cs
new file mode 100644
index 0000000000000000000000000000000000000000..bcf54625582301b762126384fd66881ca74cf11c
--- /dev/null
+++ b/src/IISIntegration/test/WebSites/StressTestWebSite/WebSockets/Constants.cs
@@ -0,0 +1,17 @@
+// 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.
+
+namespace ANCMStressTestApp
+{
+    public static class Constants
+    {
+        public static class Headers
+        {
+            public const string Upgrade = "Upgrade";
+            public const string UpgradeWebSocket = "websocket";
+            public const string Connection = "Connection";
+            public const string SecWebSocketKey = "Sec-WebSocket-Key";
+            public const string SecWebSocketAccept = "Sec-WebSocket-Accept";
+        }
+    }
+}
diff --git a/src/IISIntegration/test/WebSites/StressTestWebSite/WebSockets/HandshakeHelpers.cs b/src/IISIntegration/test/WebSites/StressTestWebSite/WebSockets/HandshakeHelpers.cs
new file mode 100644
index 0000000000000000000000000000000000000000..331f415013d3ede6e819ffb82bd97eb177112aff
--- /dev/null
+++ b/src/IISIntegration/test/WebSites/StressTestWebSite/WebSockets/HandshakeHelpers.cs
@@ -0,0 +1,42 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.Collections.Generic;
+using System.Security.Cryptography;
+using System.Text;
+
+namespace ANCMStressTestApp
+{
+    // Removed all the 
+    internal static class HandshakeHelpers
+    {
+        public static IEnumerable<KeyValuePair<string, string>> GenerateResponseHeaders(string key)
+        {
+            yield return new KeyValuePair<string, string>(Constants.Headers.Connection, Constants.Headers.Upgrade);
+            yield return new KeyValuePair<string, string>(Constants.Headers.Upgrade, Constants.Headers.UpgradeWebSocket);
+            yield return new KeyValuePair<string, string>(Constants.Headers.SecWebSocketAccept, CreateResponseKey(key));
+        }
+
+        public static string CreateResponseKey(string requestKey)
+        {
+            // "The value of this header field is constructed by concatenating /key/, defined above in step 4
+            // in Section 4.2.2, with the string "258EAFA5- E914-47DA-95CA-C5AB0DC85B11", taking the SHA-1 hash of
+            // this concatenated value to obtain a 20-byte value and base64-encoding"
+            // https://tools.ietf.org/html/rfc6455#section-4.2.2
+
+            if (requestKey == null)
+            {
+                throw new ArgumentNullException(nameof(requestKey));
+            }
+
+            using (var algorithm = SHA1.Create())
+            {
+                string merged = requestKey + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
+                byte[] mergedBytes = Encoding.UTF8.GetBytes(merged);
+                byte[] hashedBytes = algorithm.ComputeHash(mergedBytes);
+                return Convert.ToBase64String(hashedBytes);
+            }
+        }
+    }
+}
diff --git a/src/IISIntegration/tools/certificate.ps1 b/src/IISIntegration/tools/certificate.ps1
new file mode 100644
index 0000000000000000000000000000000000000000..52c881779665acc8b145ae1ecd33bf8dbdb062a5
--- /dev/null
+++ b/src/IISIntegration/tools/certificate.ps1
@@ -0,0 +1,499 @@
+# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+<##############################################################################
+ Example
+ 
+ ###############################################################################
+ # Create a new root certificate on "Cert:\LocalMachine\My" and export it to "Cert:\LocalMachine\Root"
+ # FYI, you can do the same thing with one of the following commands:
+ #   %sdxroot\tools\amd64\MakeCert.exe -r -pe -n "CN=ANCMTest_Root" -b 12/22/2013 -e 12/23/2020 -ss root -sr localmachine -len 2048 -a sha256
+ #   $thumbPrint = (New-SelfSignedCertificate -DnsName "ANCMTest_Root", "ANCMTest_Roo3" -CertStoreLocation "cert:\LocalMachine\My").Thumbprint
+ ###############################################################################
+ $rootSubject = "ANCMTest_Root"
+ $thumbPrint = .\certificate.ps1 -Command Create-SelfSignedCertificate -Subject $rootSubject
+ .\certificate.ps1 -Command Export-CertificateTo -TargetThumbPrint $thumbPrint -TargetSSLStore "Cert:\LocalMachine\My" -ExportToSSLStore "Cert:\LocalMachine\Root"
+ .\certificate.ps1 -Command Get-CertificateThumbPrint -Subject $rootSubject -TargetSSLStore "Cert:\LocalMachine\Root"
+  
+ ###############################################################################
+ # Create a new certificate setting issuer with the root certicate's subject name on "Cert:\LocalMachine\My" and export it to "Cert:\LocalMachine\Root"
+ # FYI, you can do the same thing with one of the following commands:
+ #   %sdxroot\tools\amd64\MakeCert.exe -pe -n "CN=ANCMTestWebServer" -b 12/22/2013 -e 12/23/2020  -eku 1.3.6.1.5.5.7.3.1 -is root -ir localmachine -in $rootSubject -len 2048 -ss my -sr localmachine -a sha256
+ #   %sdxroot\tools\amd64\MakeCert.exe -pe -n "CN=ANCMTest_Client" -eku 1.3.6.1.5.5.7.3.2 -is root -ir localmachine -in ANCMTest_Root -ss my -sr currentuser -len 2048 -a sha256
+ ###############################################################################
+ $childSubject = "ANCMTest_Client"
+ $thumbPrint2 = .\certificate.ps1 -Command Create-SelfSignedCertificate -Subject $childSubject -IssuerName $rootSubject
+ ("Result: $thumbPrint2")
+ .\certificate.ps1 -Command Export-CertificateTo -TargetThumbPrint $thumbPrint2 -TargetSSLStore "Cert:\LocalMachine\My" -ExportToSSLStore "Cert:\CurrentUser\My"
+
+ .\certificate.ps1 -Command Export-CertificateTo -TargetThumbPrint $thumbPrint2 -TargetSSLStore "Cert:\LocalMachine\My" -ExportToSSLStore C:\gitroot\AspNetCoreModule\tools\test.pfx -PfxPassword test
+
+
+ # Clean up
+ .\certificate.ps1 -Command Delete-Certificate -TargetThumbPrint $thumbPrint2 -TargetSSLStore "Cert:\LocalMachine\My"
+ .\certificate.ps1 -Command Delete-Certificate -TargetThumbPrint $thumbPrint2 -TargetSSLStore "Cert:\CurrentUser\Root"
+ .\certificate.ps1 -Command Delete-Certificate -TargetThumbPrint $thumbPrint -TargetSSLStore "Cert:\LocalMachine\My"
+ .\certificate.ps1 -Command Delete-Certificate -TargetThumbPrint $thumbPrint -TargetSSLStore "Cert:\LocalMachine\Root"
+
+###############################################################################>
+
+
+Param(
+    [parameter(Mandatory=$true , Position=0)]
+    [ValidateSet("Create-SelfSignedCertificate",
+                 "Delete-Certificate",
+                 "Export-CertificateTo",
+                 "Get-CertificateThumbPrint",
+                 "Get-CertificatePublicKey")]
+    [string]
+    $Command,
+
+    [parameter()]
+    [string]
+    $Subject,
+
+    [parameter()]
+    [string]
+    $IssuerName,
+
+    [Parameter()]
+    [string]
+    $FriendlyName = "", 
+
+    [Parameter()]
+    [string[]]
+    $AlternativeNames = "",
+
+    [Parameter()]
+    [string]
+    $TargetSSLStore = "",
+    
+    [Parameter()]
+    [string]
+    $ExportToSSLStore = "",
+    
+    [Parameter()]
+    [string]
+    $PfxPassword = "",
+
+    [Parameter()]
+    [string]
+    $TargetThumbPrint = ""
+)
+
+function Create-SelfSignedCertificate($_subject, $_friendlyName, $_alternativeNames, $_issuerName) {
+
+    if (-not $_subject)
+    {
+        return ("Error!!! _subject is required")
+    }
+
+    #
+    # $_issuerName should be set with the value subject and its certificate path will be root path
+    if (-not $_issuerName)
+    {
+        $_issuerName = $_subject
+    }
+
+    #
+    # Create $subjectDn and $issuerDn
+    $subjectDn = new-object -com "X509Enrollment.CX500DistinguishedName"
+    $subjectDn.Encode( "CN=" + $_subject, $subjectDn.X500NameFlags.X500NameFlags.XCN_CERT_NAME_STR_NONE)
+    $issuerDn = new-object -com "X509Enrollment.CX500DistinguishedName"
+    $issuerDn.Encode("CN=" + $_issuerName, $subjectDn.X500NameFlags.X500NameFlags.XCN_CERT_NAME_STR_NONE)
+    
+    #
+    # Create a new Private Key
+    $key = new-object -com "X509Enrollment.CX509PrivateKey"
+    $key.ProviderName =  "Microsoft Enhanced RSA and AES Cryptographic Provider"    
+    # XCN_AT_SIGNATURE, The key can be used for signing
+    $key.KeySpec = 2
+    $key.Length = 2048
+    # MachineContext 0: Current User, 1: Local Machine
+    $key.MachineContext = 1
+    $key.Create() 
+
+    # 
+    # Create a cert object with the newly created private key
+    $cert = new-object -com "X509Enrollment.CX509CertificateRequestCertificate"
+    $cert.InitializeFromPrivateKey(2, $key, "")
+    $cert.Subject = $subjectDn
+    $cert.Issuer = $issuerDn
+    $cert.NotBefore = (get-date).AddMinutes(-10)
+    $cert.NotAfter = $cert.NotBefore.AddYears(2)
+            
+    #Use Sha256
+    $hashAlgorithm = New-Object -ComObject X509Enrollment.CObjectId
+    $hashAlgorithm.InitializeFromAlgorithmName(1,0,0,"SHA256")
+    $cert.HashAlgorithm = $hashAlgorithm    
+	 
+    #
+    # Key usage should be set for non-root certificate
+    if ($_issuerName -ne $_subject)
+    {
+        #
+        # Extended key usage 
+        $clientAuthOid = New-Object -ComObject "X509Enrollment.CObjectId"
+        $clientAuthOid.InitializeFromValue("1.3.6.1.5.5.7.3.2")
+        $serverAuthOid = new-object -com "X509Enrollment.CObjectId"
+        $serverAuthOid.InitializeFromValue("1.3.6.1.5.5.7.3.1")
+        $ekuOids = new-object -com "X509Enrollment.CObjectIds.1"
+        $ekuOids.add($clientAuthOid)
+        $ekuOids.add($serverAuthOid)
+        $ekuExt = new-object -com "X509Enrollment.CX509ExtensionEnhancedKeyUsage"
+        $ekuExt.InitializeEncode($ekuOids)
+        $cert.X509Extensions.Add($ekuext)
+    	
+        #
+        #Set Key usage
+        $keyUsage = New-Object -com "X509Enrollment.cx509extensionkeyusage"
+        # XCN_CERT_KEY_ENCIPHERMENT_KEY_USAGE
+        $flags = 0x20
+        # XCN_CERT_DIGITAL_SIGNATURE_KEY_USAGE
+        $flags = $flags -bor 0x80
+        $keyUsage.InitializeEncode($flags)
+        $cert.X509Extensions.Add($keyUsage)
+    }
+        
+    #
+    # Subject alternative names
+    if ($_alternativeNames -ne $null) {
+        $names =  new-object -com "X509Enrollment.CAlternativeNames"
+        $altNames = new-object -com "X509Enrollment.CX509ExtensionAlternativeNames"
+        foreach ($n in $_alternativeNames) {
+            $name = new-object -com "X509Enrollment.CAlternativeName"
+            # Dns Alternative Name
+            $name.InitializeFromString(3, $n)
+            $names.Add($name)
+        }
+        $altNames.InitializeEncode($names)
+        $cert.X509Extensions.Add($altNames)
+    }
+
+    $cert.Encode()
+
+    #$locator = $(New-Object "System.Guid").ToString()
+    $locator = [guid]::NewGuid().ToString()
+    $enrollment = new-object -com "X509Enrollment.CX509Enrollment"    
+    $enrollment.CertificateFriendlyName = $locator        
+    $enrollment.InitializeFromRequest($cert)
+    $certdata = $enrollment.CreateRequest(0)
+    $enrollment.InstallResponse(2, $certdata, 0, "")
+
+    # Wait for certificate to be populated
+    $end = $(Get-Date).AddSeconds(1)
+    do {
+        $Certificates = Get-ChildItem Cert:\LocalMachine\My
+        foreach ($item in $Certificates)
+        {
+            if ($item.FriendlyName -eq $locator)
+            {
+                $CACertificate = $item
+            }
+        }
+    } while ($CACertificate -eq $null -and $(Get-Date) -lt $end)
+
+    $thumbPrint = ""
+    if ($CACertificate -and $CACertificate.Thumbprint)
+    {
+        $thumbPrint = $CACertificate.Thumbprint.Trim()
+    }
+    return $thumbPrint
+}
+
+function Delete-Certificate($_targetThumbPrint, $_targetSSLStore = $TargetSSLStore) {
+
+    if (-not $_targetThumbPrint)
+    {
+        return ("Error!!! _targetThumbPrint is required")
+    }
+
+    if (Test-Path "$_targetSSLStore\$_targetThumbPrint")
+    {
+        Remove-Item "$_targetSSLStore\$_targetThumbPrint" -Force -Confirm:$false
+    }
+
+    if (Test-Path "$_targetSSLStore\$_targetThumbPrint")
+    {
+        return ("Error!!! Failed to delete a certificate of $_targetThumbPrint")
+    }
+}
+
+function Export-CertificateTo($_targetThumbPrint, $_exportToSSLStore, $_password)
+{
+    if (-not $_targetThumbPrint)
+    {
+        return ("Error!!! _targetThumbPrint is required")
+    }
+
+    if (-not (Test-Path "$TargetSSLStore\$_targetThumbPrint"))
+    {
+        return ("Error!!! Export failed. Can't find target certificate: $TargetSSLStore\$_targetThumbPrint")
+    }
+        
+    $cert = Get-Item "$TargetSSLStore\$_targetThumbPrint"
+    $tempExportFile = "$env:temp\_tempCertificate.cer"
+    if (Test-Path $tempExportFile)
+    {
+        Remove-Item $tempExportFile -Force -Confirm:$false
+    }
+    
+    $isThisWin7 = $false
+    $exportToSSLStoreName = $null
+    $exportToSSLStoreLocation = $null
+    $targetSSLStoreName = $null
+    $targetSSLStoreLocation = $null
+    
+    if ((Get-Command Export-Certificate 2> out-null) -eq $null)
+    {
+        $isThisWin7 = $true
+    }
+    
+    # if _exportToSSLStore points to a .pfx file
+    if ($exportToSSLStore.ToLower().EndsWith(".pfx"))
+    {
+        if (-not $_password)
+        {
+            return ("Error!!! _password is required")
+        }
+
+        if ($isThisWin7)
+        {  
+            if ($TargetSSLStore.ToLower().Contains("my"))
+            {
+                $targetSSLStoreName = "My"
+            }
+            elseif ($_exportToSSLStore.ToLower().Contains("root"))
+            {
+                $targetSSLStoreName = "Root"
+            }
+            else
+            {
+                throw ("Unsupported store name " + $TargetSSLStore)
+            }
+            if ($TargetSSLStore.ToLower().Contains("localmachine"))
+            {
+                $targetSSLStoreLocation = "LocalMachine"
+            }
+            else
+            {
+                throw ("Unsupported store location name " + $TargetSSLStore)
+            }
+
+            &certutil.exe @('-exportpfx', '-p', $_password, $targetSSLStoreName, $_targetThumbPrint, $_exportToSSLStore) | out-null
+            
+            if ( Test-Path $_exportToSSLStore )
+            {
+                # Succeeded to export to .pfx file
+                return 
+            }
+            else
+            {
+                return ("Error!!! Can't export $TargetSSLStore\$_targetThumbPrint to $tempExportFile")
+            }
+        }
+        else
+        {
+            $securedPassword = ConvertTo-SecureString -String $_password -Force –AsPlainText 
+            $exportedPfxFile = Export-PfxCertificate -FilePath $_exportToSSLStore -Cert $TargetSSLStore\$_targetThumbPrint -Password $securedPassword
+            if ( ($exportedPfxFile -ne $null) -and (Test-Path $exportedPfxFile.FullName) )
+            {
+                # Succeeded to export to .pfx file
+                return 
+            }
+            else
+            {
+                return ("Error!!! Can't export $TargetSSLStore\$_targetThumbPrint to $tempExportFile")
+            }
+        }
+    }
+
+    if ($isThisWin7)
+    {
+        # Initialize variables for Win7
+        if ($_exportToSSLStore.ToLower().Contains("my"))
+        {
+            $exportToSSLStoreName = [System.Security.Cryptography.X509Certificates.StoreName]::My
+        }
+        elseif ($_exportToSSLStore.ToLower().Contains("root"))
+        {
+            $exportToSSLStoreName = [System.Security.Cryptography.X509Certificates.StoreName]::Root
+        }
+        else
+        {
+            throw ("Unsupported store name " + $_exportToSSLStore)
+        }
+        if ($_exportToSSLStore.ToLower().Contains("localmachine"))
+        {
+            $exportToSSLStoreLocation = [System.Security.Cryptography.X509Certificates.StoreLocation]::LocalMachine
+        }
+        elseif ($_exportToSSLStore.ToLower().Contains("currentuser"))
+        {
+            $exportToSSLStoreLocation = [System.Security.Cryptography.X509Certificates.StoreLocation]::CurrentUser
+        }
+        else
+        {
+            throw ("Unsupported store location name " + $_exportToSSLStore)
+        }
+
+        # Export-Certificate is not available. 
+        $isThisWin7 = $true
+        $certificate = Get-Item "$TargetSSLStore\$_targetThumbPrint"
+        $base64certificate = @"
+-----BEGIN CERTIFICATE-----
+$([Convert]::ToBase64String($certificate.Export('Cert'), [System.Base64FormattingOptions]::InsertLineBreaks)))
+-----END CERTIFICATE-----
+"@
+        Set-Content -Path $tempExportFile -Value $base64certificate | Out-Null
+    }
+    else 
+    {
+        Export-Certificate -Cert $cert -FilePath $tempExportFile | Out-Null
+        if (-not (Test-Path $tempExportFile))
+        {
+            return ("Error!!! Can't export $TargetSSLStore\$_targetThumbPrint to $tempExportFile")
+        }
+    }
+
+    if ($isThisWin7)
+    {
+        [Reflection.Assembly]::Load("System.Security, Version=2.0.0.0, Culture=Neutral, PublicKeyToken=b03f5f7f11d50a3a") | Out-Null
+        $cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2($tempExportFile)
+        $store = New-Object System.Security.Cryptography.X509Certificates.X509Store($exportToSSLStoreName,$exportToSSLStoreLocation)
+        $store.Open([System.Security.Cryptography.X509Certificates.OpenFlags]::ReadWrite) | Out-Null
+        $store.Add($cert) | Out-Null
+    }
+    else
+    {
+        # clean up destination SSL store
+        Delete-Certificate $_targetThumbPrint $_exportToSSLStore
+        if (Test-Path "$_exportToSSLStore\$_targetThumbPrint")
+        {
+            return ("Error!!! Can't delete already existing one $_exportToSSLStore\$_targetThumbPrint")
+        }
+        Import-Certificate -CertStoreLocation $_exportToSSLStore -FilePath $tempExportFile | Out-Null
+    }
+
+    Sleep 3
+    if (-not (Test-Path "$_exportToSSLStore\$_targetThumbPrint"))
+    {
+        return ("Error!!! Can't copy $TargetSSLStore\$_targetThumbPrint to $_exportToSSLStore")
+    }
+}
+
+function Get-CertificateThumbPrint($_subject, $_issuerName, $_targetSSLStore)
+{
+    if (-not $_subject)
+    {
+        return ("Error!!! _subject is required")
+    }
+    if (-not $_targetSSLStore)
+    {
+        return ("Error!!! _targetSSLStore is required")
+    }
+
+    if (-not (Test-Path "$_targetSSLStore"))
+    {
+        return ("Error!!! Can't find target store")
+    }
+
+    $targetCertificate = $null
+    
+    $Certificates = Get-ChildItem $_targetSSLStore
+    foreach ($item in $Certificates)
+    {
+        $findItem = $false
+        # check subject name first
+        if ($item.Subject.ToLower() -eq "CN=$_subject".ToLower())
+        {            
+            $findItem = $true
+        }
+
+        # check issuerName as well
+        if ($_issuerName -and $item.Issuer.ToLower() -ne "CN=$_issuerName".ToLower())
+        {
+            $findItem = $false
+        }
+
+        if ($findItem)
+        {
+            $targetCertificate = $item
+            break
+        }
+    }
+    $result = ""
+    if ($targetCertificate)
+    {
+        $result = $targetCertificate.Thumbprint
+    }
+    else
+    {
+        ("Error!!! Can't find target certificate")
+    }
+    return $result
+}
+
+function Get-CertificatePublicKey($_targetThumbPrint)
+{
+    if (-not $_targetThumbPrint)
+    {
+        return ("Error!!! _targetThumbPrint is required")
+    }
+
+    if (-not (Test-Path "$TargetSSLStore\$_targetThumbPrint"))
+    {
+        return ("Error!!! Can't find target certificate")
+    }
+
+    $cert = Get-Item "$TargetSSLStore\$_targetThumbPrint"
+    $byteArray = $cert.Export([System.Security.Cryptography.X509Certificates.X509ContentType]::Cert)
+    $publicKey = [System.Convert]::ToBase64String($byteArray).Trim()
+
+    return $publicKey
+}
+
+# Error handling and initializing default values
+if (-not $TargetSSLStore)
+{
+    $TargetSSLStore = "Cert:\LocalMachine\My"
+}
+else
+{
+    if ($Command -eq "Create-SelfSignedCertificate")
+    {
+        return ("Error!!! Create-SelfSignedCertificate should use default value for -TargetSSLStore if -Issuer is not provided")
+    }
+}
+
+if (-not $ExportToSSLStore)
+{
+    $ExportToSSLStore = "Cert:\LocalMachine\Root"
+}
+
+switch ($Command)
+{
+    "Create-SelfSignedCertificate"
+    {
+        return Create-SelfSignedCertificate $Subject $FriendlyName $AlternativeNames $IssuerName
+    }
+    "Delete-Certificate"
+    {
+        return Delete-Certificate $TargetThumbPrint
+    }
+    "Export-CertificateTo"
+    {
+        return Export-CertificateTo $TargetThumbPrint $ExportToSSLStore $PfxPassword
+    }
+    "Get-CertificateThumbPrint"
+    {
+        return Get-CertificateThumbPrint $Subject $IssuerName $TargetSSLStore
+    }
+    "Get-CertificatePublicKey"
+    {
+        return Get-CertificatePublicKey $TargetThumbPrint
+    }
+    default
+    {
+        throw "Unknown command"
+    }
+}
diff --git a/src/IISIntegration/tools/httpsys.ps1 b/src/IISIntegration/tools/httpsys.ps1
new file mode 100644
index 0000000000000000000000000000000000000000..af2254e96f73e7d5cdc2ebb28fe622e5cf1bb44a
--- /dev/null
+++ b/src/IISIntegration/tools/httpsys.ps1
@@ -0,0 +1,394 @@
+# Copyright (c) .NET Foundation. All rights reserved.
+# Licensed under the MIT License. See License.txt in the project root for license information.
+
+##############################################################################
+# Example
+# $result = .\httpsys.ps1 -Command Get-SslBinding -IpAddress "0x00" -Port 46300
+# .\httpsys.ps1 -Command Add-SslBinding -IpAddress "0x00" -Port 46300 –Thumbprint $result.CertificateHash
+# .\httpsys.ps1 -Command Delete-SslBinding -IpAddress "0x00" -Port 46300
+##############################################################################
+
+Param (
+    [parameter(Mandatory=$true , Position=0)]
+    [ValidateSet("Add-SslBinding",
+                 "Delete-SslBinding",
+                 "Get-SslBinding")]
+    [string]
+    $Command,
+    
+    [parameter()]
+    [string]
+    $IpAddress,
+    
+    [parameter()]
+    [string]
+    $Port,
+
+    [parameter()]
+    [string]
+    $Thumbprint,
+
+    [parameter()]
+    [string]
+    $TargetSSLStore,
+
+    [parameter()]
+    [string]
+    $AppId,
+
+    [parameter()] 
+    [System.Net.IPEndPoint] 
+    $IpEndPoint
+    )
+
+
+# adjust parameter variables
+if (-not $IpEndPoint)
+{
+    if ($IpAddress -and $Port)
+    {
+        $IpEndPoint = New-Object "System.Net.IPEndPoint" -ArgumentList $IpAddress,$Port
+    }
+}
+
+if (-not $TargetSSLStore)
+{
+    $TargetSSLStore = "Cert:\LocalMachine\My"
+}
+
+$StoreName = ($TargetSSLStore.Split("\") | Select-Object -Last 1).Trim()
+
+$Certificate = Get-Item "$TargetSSLStore\$Thumbprint"
+
+if (-not $AppId)
+{
+    # Assign a random GUID for $AppId
+    $AppId = [guid]::NewGuid()
+}
+
+$cs = '
+namespace Microsoft.IIS.Administration.Setup {
+using System;  
+using System.Diagnostics;  
+using System.Diagnostics.CodeAnalysis;  
+using System.Net;  
+using System.Runtime.InteropServices;  
+using System.Security.Cryptography.X509Certificates;  
+using System.Text;  
+using System.ComponentModel;  
+
+    public class Http {           
+        public const int HTTP_INITIALIZE_CONFIG = 2;  
+        public const int HTTP_SERVICE_CONFIG_SSLCERT_INFO = 1; 
+
+        [DllImport("httpapi.dll", CharSet = CharSet.Auto, PreserveSig = true)]  
+        public static extern uint HttpDeleteServiceConfiguration(IntPtr ServiceHandle, int ConfigId, ref HTTP_SERVICE_CONFIG_SSL_SET pConfigInformation, int ConfigInformationLength, IntPtr pOverlapped);  
+        
+        [DllImport("httpapi.dll", CharSet = CharSet.Auto, PreserveSig = true)]  
+        public static extern uint HttpInitialize(HTTPAPI_VERSION version, uint flags, IntPtr pReserved);   
+
+        [DllImport("httpapi.dll", EntryPoint = "HttpQueryServiceConfiguration",  
+            CharSet = CharSet.Unicode, ExactSpelling = true,  
+            CallingConvention = CallingConvention.StdCall)]  
+        public static extern uint HttpQueryServiceConfiguration(  
+            IntPtr serviceHandle,  
+            HTTP_SERVICE_CONFIG_ID configID,  
+            ref HTTP_SERVICE_CONFIG_SSL_QUERY pInputConfigInfo,  
+            UInt32 InputConfigInfoLength, 
+            IntPtr pOutputConfigInfo,
+            UInt32 OutputConfigInfoLength,  
+            [In, Out] ref UInt32 pReturnLength,  
+            IntPtr pOverlapped  
+        );  
+        
+        [DllImport("httpapi.dll", CharSet = CharSet.Auto, PreserveSig = true)]  
+        public static extern uint HttpSetServiceConfiguration(IntPtr ServiceHandle, int ConfigId, ref HTTP_SERVICE_CONFIG_SSL_SET pConfigInformation, int ConfigInformationLength, IntPtr pOverlapped);
+  
+        [DllImport("httpapi.dll", CharSet = CharSet.Auto, PreserveSig = true)]  
+        public static extern uint HttpTerminate(uint flags, IntPtr pReserved);
+
+        public static HTTP_SERVICE_CONFIG_SSL_SET MarshalConfigSslSet(IntPtr ptr) {
+            return (HTTP_SERVICE_CONFIG_SSL_SET)Marshal.PtrToStructure(ptr, typeof(HTTP_SERVICE_CONFIG_SSL_SET));
+        }
+    }   
+  
+    public enum HTTP_SERVICE_CONFIG_ID {  
+        HttpServiceConfigIPListenList,  
+        HttpServiceConfigSSLCertInfo,  
+        HttpServiceConfigUrlAclInfo,  
+        HttpServiceConfigMax  
+    }  
+  
+    public enum HTTP_SERVICE_CONFIG_QUERY_TYPE {  
+        HttpServiceConfigQueryExact,  
+        HttpServiceConfigQueryNext,  
+        HttpServiceConfigQueryMax  
+    }  
+    
+    [StructLayout(LayoutKind.Sequential)]  
+    public struct HTTPAPI_VERSION {  
+        public ushort HttpApiMajorVersion;  
+        public ushort HttpApiMinorVersion;  
+    }    
+  
+    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]  
+    public struct HTTP_SERVICE_CONFIG_SSL_KEY {  
+        public IntPtr pIpPort;  
+    }  
+  
+    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]  
+    public struct HTTP_SERVICE_CONFIG_SSL_QUERY {  
+        public HTTP_SERVICE_CONFIG_QUERY_TYPE QueryDesc; 
+        public IntPtr KeyDesc;  
+        public Int32 dwToken;  
+    }  
+        
+    [StructLayout(LayoutKind.Sequential)]  
+    public struct HTTP_SERVICE_CONFIG_SSL_SET {  
+        public IntPtr KeyDesc;  
+        public uint SslHashLength;  
+        public IntPtr pSslHash;  
+        public Guid AppId;  
+        [MarshalAs(UnmanagedType.LPWStr)]  
+        public string pSslCertStoreName;  
+        public int DefaultCertCheckMode;  
+        public int DefaultRevocationFreshnessTime;  
+        public int DefaultRecovationUrlRetrievalTimeout;  
+        [MarshalAs(UnmanagedType.LPWStr)]  
+        public string pDefaultSslCtlIdentifier;  
+        [MarshalAs(UnmanagedType.LPWStr)]  
+        public string pDefaultSslCtlStoreName;  
+        public int DefaultFlags;  
+    }      
+}
+'
+
+$SUCCESS = 0
+function InitializeInterop() {
+    try {
+        [Microsoft.IIS.Administration.Setup.Http] | Out-Null
+    }
+    catch {
+        Add-Type $cs
+    }
+}
+
+function GetIpEndpointBytes($_ipEndpoint) {
+    $socketAddress = $_ipEndpoint.Serialize()
+    $ipBytes = [System.Array]::CreateInstance([System.Byte], $socketAddress.Size)
+    for ($i = 0; $i -lt $socketAddress.Size; $i++) {
+        $ipBytes[$i] = $socketAddress[$i]
+    }
+    return $ipBytes
+}
+
+function GetBindingInfo($sslConfig) {
+    $hash = [System.Array]::CreateInstance([System.Byte], [int]($sslConfig.SslHashLength))
+    [System.Runtime.InteropServices.Marshal]::Copy($sslConfig.pSslHash, $hash, 0, $sslConfig.SslHashLength)
+
+    $socketAddressLength = 16
+    $sa = [System.Array]::CreateInstance([System.Byte], $socketAddressLength)
+    [System.Runtime.InteropServices.Marshal]::Copy($sslConfig.KeyDesc, $sa, 0, $socketAddressLength)
+    $socketAddress = New-Object "System.Net.SocketAddress" -ArgumentList ([System.Net.Sockets.AddressFamily]::InterNetwork, $socketAddressLength)
+    for ($i = 0; $i -lt $sa.Length; $i++) {
+        $socketAddress[$i] = $sa[$i]
+    }
+
+    $ep = New-Object "System.Net.IPEndPoint" -ArgumentList ([ipaddress]::Any, 0)
+    $endpoint = [System.Net.IPEndPoint]$ep.Create($socketAddress)
+
+    $ret = @{}
+    $ret.CertificateHash = [System.BitConverter]::ToString($hash).Replace("-", "")
+    $ret.AppId = $sslConfig.AppId
+    $ret.IpEndpoint = $endpoint
+    return $ret
+}
+
+function InitializeHttpSys() {
+    $v = New-Object "Microsoft.IIS.Administration.Setup.HTTPAPI_VERSION"
+    $V.HttpApiMajorVersion = 1
+    $v.HttpApiMinorVersion = 0
+
+    $result = [Microsoft.IIS.Administration.Setup.Http]::HttpInitialize($v, [Microsoft.IIS.Administration.Setup.Http]::HTTP_INITIALIZE_CONFIG, [System.IntPtr]::Zero)
+
+    if ($result -ne $SUCCESS) {
+        Write-Warning "Error initializing Http API"
+        throw [System.ComponentModel.Win32Exception] $([System.int32]$result)
+    }
+
+    return $result
+}
+
+function TerminateHttpSys() {
+    return [Microsoft.IIS.Administration.Setup.Http]::HttpTerminate([Microsoft.IIS.Administration.Setup.Http]::HTTP_INITIALIZE_CONFIG, [System.IntPtr]::Zero)
+}
+
+function Add-SslBinding($_ipEndpoint, $_certificate, $_appId) {
+    if ($_ipEndpoint -eq $null) {
+        throw "Ip Endpoint required."
+    }
+
+    if ($_certificate -eq $null) {
+        throw "Certificate required."
+    }
+
+    if ($appId -eq $null) {
+        throw "App id required."
+    }
+
+    <# FYI, [System.Guid]::Parse() is not supported in lower version of powershell
+    if (-not($_appId -is [System.Guid])) {
+        $_appId = [System.Guid]::Parse($_appId)
+    }
+    #>
+
+    setSslConfiguration $_ipEndpoint $_certificate $_appId
+}
+
+function Delete-SslBinding($_ipEndpoint) {
+
+    if ($_ipEndpoint -eq $null) {
+        throw "Ip Endpoint required."
+    }
+
+    setSslConfiguration $_ipEndpoint $null $([System.Guid]::Empty)
+}
+
+function Get-SslBinding($_ipEndpoint) {
+
+    if ($_ipEndpoint -eq $null) {
+        throw "Ip Endpoint required."
+    }
+
+    $bufferSize = 4096
+    try {
+        InitializeHttpSys| Out-Null
+
+        $ipBytes = [System.Byte[]]$(GetIpEndpointBytes($_ipEndpoint))
+        $hIp = [System.Runtime.InteropServices.GCHandle]::Alloc($ipBytes, [System.Runtime.InteropServices.GCHandleType]::Pinned)
+        $pIp = $hIp.AddrOfPinnedObject()
+
+        $queryParam = New-Object "Microsoft.IIS.Administration.Setup.HTTP_SERVICE_CONFIG_SSL_QUERY"
+        $queryParam.QueryDesc = [Microsoft.IIS.Administration.Setup.HTTP_SERVICE_CONFIG_QUERY_TYPE]::HttpServiceConfigQueryExact
+        $queryParam.dwToken = 0
+        $queryParam.KeyDesc = $pIp
+
+        $returnLen = 0
+        $pReturnSet = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($bufferSize)    
+
+        $result = [Microsoft.IIS.Administration.Setup.Http]::HttpQueryServiceConfiguration(
+                        [System.IntPtr]::Zero,
+                        [Microsoft.IIS.Administration.Setup.HTTP_SERVICE_CONFIG_ID]::HttpServiceConfigSSLCertInfo,
+                        [ref] $queryParam,
+                        [uint32]([System.Runtime.InteropServices.Marshal]::SizeOf($queryParam)),
+                        $pReturnSet,
+                        $bufferSize,
+                        [ref] $returnLen,
+                        [System.IntPtr]::Zero)
+
+        if ($result -eq 2) {
+            # File not found
+            return $null
+        }
+        if ($result -ne $SUCCESS) {
+            Write-Warning "Error reading Ssl Cert Configuration"
+            throw [System.ComponentModel.Win32Exception] $([System.int32]$result)
+        }
+        $sslConfig = [Microsoft.IIS.Administration.Setup.Http]::MarshalConfigSslSet($pReturnSet)
+        return GetBindingInfo $sslConfig
+    }
+    finally {
+        if ($hIp -ne $null) {
+            $hIp.Free()
+            $hIp = $null
+        }
+        if ($pReturnSet -ne [System.IntPtr]::Zero) {
+            [System.Runtime.InteropServices.Marshal]::FreeHGlobal($pReturnSet)
+            $pReturnSet = [System.IntPtr]::Zero
+        }
+        TerminateHttpSys | Out-Null
+    }
+}
+
+function setSslConfiguration($_ipEndpoint, $_certificate, $_appId) {
+
+    try {
+        InitializeHttpSys| Out-Null
+    
+        $sslSet = New-Object "Microsoft.IIS.Administration.Setup.HTTP_SERVICE_CONFIG_SSL_SET"
+        $sslSetSize = [System.Runtime.InteropServices.Marshal]::SizeOf($sslSet)
+
+        $ipBytes = [System.Byte[]]$(GetIpEndpointBytes($_ipEndpoint))
+        $hIp = [System.Runtime.InteropServices.GCHandle]::Alloc($ipBytes, [System.Runtime.InteropServices.GCHandleType]::Pinned)
+        $pIp = $hIp.AddrOfPinnedObject()
+
+        $sslSet.KeyDesc = $pIp # IntPtr
+        $sslSet.SslHashLength = 0
+        $sslSet.pSslHash = [System.IntPtr]::Zero
+        $sslSet.pSslCertStoreName = [System.IntPtr]::Zero
+        $sslSet.AppId = $_appId
+
+        if ($_certificate -ne $null) {
+            # Create binding
+            
+            $certBytes = $_certificate.GetCertHash()
+            $hCertBytes = [System.Runtime.InteropServices.GCHandle]::Alloc($certBytes, [System.Runtime.InteropServices.GCHandleType]::Pinned)
+            $pCertBytes = $hCertBytes.AddrOfPinnedObject()
+        
+            $sslSet.SslHashLength = 20
+            $sslSet.pSslHash = $pCertBytes
+            $sslSet.pSslCertStoreName = $StoreName
+
+            $result = [Microsoft.IIS.Administration.Setup.Http]::HttpSetServiceConfiguration([System.IntPtr]::Zero, 
+                      [Microsoft.IIS.Administration.Setup.Http]::HTTP_SERVICE_CONFIG_SSLCERT_INFO,
+                      [ref]$sslSet,
+                      $sslSetSize,
+                      [System.IntPtr]::Zero)  
+        }   
+        else {
+            #Delete binding
+            $result = [Microsoft.IIS.Administration.Setup.Http]::HttpDeleteServiceConfiguration([System.IntPtr]::Zero, 
+                      [Microsoft.IIS.Administration.Setup.Http]::HTTP_SERVICE_CONFIG_SSLCERT_INFO,
+                      [ref]$sslSet,
+                      $sslSetSize,
+                      [System.IntPtr]::Zero)  
+        }  
+
+        if ($result -ne $SUCCESS) {
+            Write-Warning "Error setting Ssl Cert Configuration"
+            throw [System.ComponentModel.Win32Exception] $([System.int32]$result)
+        }
+    }
+    finally {              
+        if ($hIp -ne $null) {
+            $hIp.Free()
+            $hIp = $null
+        }
+        if ($hCertBytes -ne $null) {
+            $hCertBytes.Free()
+            $hCertBytes = $null
+        }
+        TerminateHttpSys| Out-Null
+    }
+}
+
+InitializeInterop
+switch ($Command)
+{
+    "Add-SslBinding"
+    {
+        return Add-SslBinding $IpEndPoint $Certificate $AppId
+    }
+    "Delete-SslBinding"
+    {
+        return Delete-SslBinding $IpEndpoint
+    }
+    "Get-SslBinding"
+    {
+        return Get-SslBinding $IpEndpoint
+    }
+    default
+    {
+        throw "Unknown command"
+    }
+}
\ No newline at end of file
diff --git a/src/IISIntegration/tools/installancm.ps1 b/src/IISIntegration/tools/installancm.ps1
new file mode 100644
index 0000000000000000000000000000000000000000..b54a830d0e63c548eefd3967f85892fe8dfe1029
--- /dev/null
+++ b/src/IISIntegration/tools/installancm.ps1
@@ -0,0 +1,471 @@
+<#
+.SYNOPSIS
+    Installs asnetcore to IISExpress and IIS directory
+.DESCRIPTION
+    Installs asnetcore to IISExpress and IIS directory
+.PARAMETER Rollback
+    Default: $false
+    Rollback the updated files with the original files
+.PARAMETER ForceToBackup
+    Default: $false
+    Force to do the initial backup again (this parameter is meaningful only when you want to replace the existing backup file)
+.PARAMETER Extract
+    Default: $false
+    Search ANCM nugetfile and extract the file to the path of the ExtractFilesTo parameter value
+.PARAMETER PackagePath
+    Default: $PSScriptRoot\..\..\artifacts
+    Root path where ANCM nuget package is placed
+.PARAMETER ExtractFilesTo
+    Default: $PSScriptRoot\..\..\artifacts"
+    Output path where aspentcore.dll file is extracted
+
+Example:
+    .\installancm.ps1 "C:\Users\jhkim\AppData\Local\Temp\ihvufnf1.atw\ancm\Debug"
+
+#>
+[cmdletbinding()]
+param(
+   [Parameter(Mandatory=$false, Position = 0)]
+   [string]  $ExtractFilesTo="$PSScriptRoot\..\artifacts\build\AspNetCore\bin\Debug",
+   [Parameter(Mandatory=$false, Position = 1)]
+   [string]  $PackagePath="$PSScriptRoot\..\artifacts\build",
+   [Parameter(Mandatory=$false)]
+   [switch] $Rollback=$false,
+   [Parameter(Mandatory=$false)]
+   [switch] $ForceToBackup=$false,
+   [Parameter(Mandatory=$false)]
+   [switch] $Extract=$false
+)
+
+function Get-ANCMNugetFilePath() { 
+
+    $NugetFilePath = Get-ChildItem $PackagePath -Recurse -Filter Microsoft.AspNetCore.AspNetCoreModule*.nupkg | Select-Object -Last 1
+    return ($NugetFilePath.FullName)
+}
+
+function Check-TargetFiles() { 
+    $functionName = "Check-TargetFiles"
+    $LogHeader = "[$ScriptFileName::$functionName]"
+    $result = $true
+
+    if (-not $isIISExpressInstalled -and -not $isIISInstalled)
+    {
+        Say ("$LogHeader Both IIS and IISExpress does not have aspnetcore.dll file")
+        $result = $false
+    }
+
+    if ($isIISExpressInstalled)
+    {
+        if (-not (Test-Path $aspnetCorex64To))
+        {
+            Say ("$LogHeader Error!!! Failed to find the file $aspnetCorex64To")
+            $result = $false
+        }
+        if (-not (Test-Path $aspnetCoreSchemax64To))
+        {
+            Say ("$LogHeader Error!!! Failed to find the file $aspnetCoreSchemax64To")
+            $result = $false
+        }
+        if ($is64BitMachine)
+        {
+            if (-not (Test-Path $aspnetCoreWin32To))
+            {
+                Say ("$LogHeader Error!!! Failed to find the file $aspnetCoreWin32To")
+                $result = $false
+            }    
+            if (-not (Test-Path $aspnetCoreSchemaWin32To))
+            {
+                Say ("$LogHeader Error!!! Failed to find the file $aspnetCoreSchemaWin32To")
+                $result = $false
+            }  
+        }
+    }
+
+    if ($isIISInstalled)
+    {
+        if (-not (Test-Path $aspnetCorex64IISTo))
+        {
+            Say ("$LogHeader Error!!! Failed to find the file $aspnetCorex64IISTo")
+            $result = $false
+        }
+        if (-not (Test-Path $aspnetCoreSchemax64IISTo))
+        {
+            Say ("$LogHeader Error!!! Failed to find the file $aspnetCoreSchemax64IISTo")
+            $result = $false
+        }
+        if ($is64BitMachine)
+        {
+            if (-not (Test-Path $aspnetCoreWin32IISTo))
+            {
+                Say ("$LogHeader Error!!! Failed to find the file $aspnetCoreWin32IISTo")
+                $result = $false
+            }
+        }
+    }
+
+    return $result
+}
+
+function Check-ExtractedFiles() { 
+    $functionName = "Check-ExtractedFiles"
+    $LogHeader = "[$ScriptFileName::$functionName]"
+    $result = $true
+
+    if (-not (Test-Path $aspnetCorex64From))
+    {
+        Say ("$LogHeader Error!!! Failed to find the file $aspnetCorex64From")
+        $result = $false
+    }
+    if (-not (Test-Path $aspnetCoreWin32From))
+    {
+        Say ("$LogHeader Error!!! Failed to find the file $aspnetCoreWin32From")
+        $result = $false
+    }
+    if (-not (Test-Path $aspnetCoreSchemax64From))
+    {
+        Say ("$LogHeader Error!!! Failed to find the file $aspnetCoreSchemax64From")
+        $result = $false
+    }
+    if (-not (Test-Path $aspnetCoreSchemaWin32From))
+    {
+        Say ("$LogHeader Error!!! Failed to find the file $aspnetCoreSchemaWin32From")
+        $result = $false
+    }
+    return $result
+}
+
+function Extract-ANCMFromNugetPackage() { 
+    $result = $true
+
+    $functionName = "Extract-ANCMFromNugetPackage"
+    $LogHeader = "[$ScriptFileName::$functionName]"
+
+    $backupAncmNugetFilePath = Join-Path $TempExtractFilesTo (get-item $ancmNugetFilePath).Name
+    if (Test-Path $backupAncmNugetFilePath)
+    {
+        Say ("$LogHeader Found backup file at $backupAncmNugetFilePath")
+        if ((get-item $ancmNugetFilePath).LastWriteTime -eq (get-item $backupAncmNugetFilePath).LastWriteTime)
+        {
+            if (Check-ExtractedFiles)
+            {
+                Say ("$LogHeader Skip to extract ANCM files because $ancmNugetFilePath is matched to the backup file $backupAncmNugetFilePath.")
+                return $result
+            }
+        }
+    }
+
+    Add-Type -Assembly System.IO.Compression.FileSystem
+    if (Test-Path $TempExtractFilesTo)
+    {
+        remove-item $TempExtractFilesTo -Force -Recurse -Confirm:$false | out-null
+    }
+    if (Test-Path $TempExtractFilesTo)
+    {
+        Say ("$LogHeader Error!!! Failed to delete $TempExtractFilesTo")
+        $result = $false
+        return $result
+    }
+    else
+    {
+        new-item -Type directory $TempExtractFilesTo | out-null
+    }
+    if (-not (Test-Path $TempExtractFilesTo))
+    {
+        Say ("$LogHeader Error!!! Failed to create $TempExtractFilesTo")
+        $result = $false
+        return $result
+    }
+
+    # 
+    Say ("$LogHeader Extract the ancm nuget file $ancmNugetFilePath to $TempExtractFilesTo ...")
+    [System.IO.Compression.ZipFile]::ExtractToDirectory($ancmNugetFilePath, $TempExtractFilesTo) 
+
+    Say ("$LogHeader Create the backup file of the nuget file to $backupAncmNugetFilePath")
+    copy-item $ancmNugetFilePath $backupAncmNugetFilePath
+
+    return $result
+}
+
+function Update-ANCM() { 
+    
+    $functionName = "Update-ANCM -Rollback:$" + $Rollback.ToString()
+    $LogHeader = "[$ScriptFileName::$functionName]"
+
+    if ($isIISExpressInstalled)
+    {
+        if ($is64BitMachine)
+        {
+            Say ("$LogHeader Start updating ANCM files for IISExpress for amd64 machine...")
+            Update-File $aspnetCorex64From $aspnetCorex64To 
+            Update-File $aspnetCoreWin32From $aspnetCoreWin32To 
+            Update-File $aspnetCoreSchemax64From $aspnetCoreSchemax64To 
+            Update-File $aspnetCoreSchemaWin32From $aspnetCoreSchemaWin32To 
+        }
+        else
+        {
+            Say ("$LogHeader Start updating ANCM files for IISExpress for x86 machine...")
+            Update-File $aspnetCoreWin32From $aspnetCorex64To 
+            Update-File $aspnetCoreSchemaWin32From $aspnetCoreSchemax64To 
+        }
+    }
+    else
+    {
+        Say ("$LogHeader Can't find aspnetcore.dll for IISExpress. Skipping updating ANCM files for IISExpress")
+    }
+
+    if ($isIISInstalled)
+    {
+        if ($is64BitMachine)
+        {
+            Say ("$LogHeader Start updating ANCM files for IIS for amd64 machine...")
+            Update-File $aspnetCorex64From $aspnetCorex64IISTo 
+            Update-File $aspnetCoreWin32From $aspnetCoreWin32IISTo 
+            Update-File $aspnetCoreSchemax64From $aspnetCoreSchemax64IISTo 
+        }
+        else
+        {
+            Say ("$LogHeader Start updating ANCM files for IIS for x86 machine...")
+            Update-File $aspnetCoreWin32IISFrom $aspnetCorex64IISTo 
+            Update-File $aspnetCoreSchemaWin32From $aspnetCoreSchemax64IISTo 
+        }
+    }
+    else
+    {
+        Say ("$LogHeader Can't find aspnetcore.dll for IIS. Skipping updating ANCM files for IIS server")
+    }
+}
+
+function Update-File([string]$SourceFilePath, [string]$DestinationFilePath) { 
+
+    $Source = $SourceFilePath
+    $Destination = $DestinationFilePath
+
+    $BackupFilePath = $Destination + ".ancm_backup"
+    if ($Rollback)
+    {
+        $Source = $BackupFilePath
+    }
+        
+    $functionName = "Update-File -Rollback:$" + $Rollback.ToString()
+    $LogHeader = "[$ScriptFileName::$functionName]"
+
+    if ($ForceToBackup)
+    {
+        if (Test-Path $BackupFilePath)
+        {
+            $backupFileRemoved = $false
+            if ( ((get-item $DestinationFilePath).CreationTime -gt (get-item $BackupFilePath).CreationTime) -and ((get-item $DestinationFilePath).CreationTime -gt (get-item $SourceFilePath).CreationTime) )
+            {
+                $backupFileRemoved = $true
+                Say ('    Delete the existing "$BackupFilePath" because "$DestinationFilePath" is newer than both "$BackupFilePath" and "$SourceFilePath"')
+                Remove-Item $BackupFilePath -Force -Confirm:$false
+            }
+            else
+            {
+                Say-Verbose ('     Skipping to delete the existing backupfile because "$DestinationFilePath" is not newer than $BackupFilePath"')
+            }
+        }
+        if ($backupFileRemoved -and (Test-Path $BackupFilePath))
+        {
+            throw ("$LogHeader Can't delete $BackupFilePath")
+        }
+    }
+
+    # Do the initial back up before updating file
+    if (-Not (Test-Path $BackupFilePath))
+    {
+        Say ("    Create a backup $BackupFilePath")
+        Copy-Item $Destination $BackupFilePath  -Force
+
+        $fileMatched = $null -eq (Compare-Object -ReferenceObject $(Get-Content $Destination) -DifferenceObject $(Get-Content $BackupFilePath))
+        if (-not $fileMatched)
+        {
+            throw ("$LogHeader File not matched!!! $Destination $BackupFilePath")
+        }
+    }
+    if (-Not (Test-Path $BackupFilePath))
+    {
+        throw ("$LogHeader Can't backup $Source to $BackupFilePath")
+    }  
+
+    # Copy file from Source to Destination if those files are different each other
+    if (-Not (Test-Path $Destination))
+    {
+        throw ("$LogHeader Can't find $Destination")
+    }
+    $fileMatched = $null -eq (Compare-Object -ReferenceObject $(Get-Content $Source) -DifferenceObject $(Get-Content $Destination))
+    if (-not $fileMatched)
+    {
+        Say ("    Copying $Source to $Desting...")
+        Copy-Item $Source $Destination -Force
+
+        # check file is correctly copied
+        $fileMatched = $null -eq (Compare-Object -ReferenceObject $(Get-Content $Source) -DifferenceObject $(Get-Content $Destination))
+        if (-not $fileMatched)
+        {
+            throw ("$LogHeader File not matched!!! $Source $Destination")
+        }
+        else
+        {
+            Say-Verbose ("$LogHeader File matched!!! $Source to $Destination")
+        }
+    }
+    else
+    {
+        Say ("    Skipping $Destination that is already identical to $Source ")
+    }
+}
+
+function Say($str) {
+    Write-Host $str
+}
+
+function Say-Verbose($str) {
+    Write-Verbose $str
+}
+
+#######################################################
+# Start execution point
+#######################################################
+
+$EXIT_FAIL = 1
+$EXIT_SUCCESS = 0
+
+$ScriptFileName = "installancm.ps1"
+$LogHeader = "[$ScriptFileName]"
+
+if ($Extract -and (-Not $Rollback))
+{
+    if (-not (Test-Path $PackagePath))
+    {
+        Say ("$LogHeader Error!!! Failed to find the directory $PackagePath")
+        exit $EXIT_FAIL
+    }
+
+    $ancmNugetFilePath = Get-ANCMNugetFilePath
+    if (-not (Test-Path $ancmNugetFilePath))
+    {
+        Say ("$LogHeader Error!!! Failed to find AspNetCoreModule nupkg file under $PackagePath nor its child directories")
+        exit $EXIT_FAIL
+    }
+}
+
+if (-Not $Rollback)
+{
+    if (-not (Test-Path $ExtractFilesTo))
+    {
+        Say ("$LogHeader Error!!! Failed to find the directory $ExtractFilesTo")
+        exit $EXIT_FAIL
+    }
+}
+
+$TempExtractFilesTo = $ExtractFilesTo + "\.ancm"
+$ExtractFilesRootPath = ""
+if ($Extract)
+{
+    $ExtractFilesRootPath = $TempExtractFilesTo + "\ancm\Debug"
+}
+else
+{
+    $ExtractFilesRootPath = $ExtractFilesTo
+}
+
+# Try with solution output path
+$aspnetCorex64From = $ExtractFilesRootPath + "\x64\aspnetcore.dll"
+$aspnetCoreWin32From = $ExtractFilesRootPath + "\Win32\aspnetcore.dll"
+$aspnetCoreSchemax64From = $ExtractFilesRootPath + "\x64\aspnetcore_schema.xml"
+$aspnetCoreSchemaWin32From = $ExtractFilesRootPath + "\Win32\aspnetcore_schema.xml"
+
+$aspnetCorex64To = "$env:ProgramFiles\IIS Express\aspnetcore.dll"
+$aspnetCoreWin32To = "${env:ProgramFiles(x86)}\IIS Express\aspnetcore.dll"
+$aspnetCoreSchemax64To = "$env:ProgramFiles\IIS Express\config\schema\aspnetcore_schema.xml"
+$aspnetCoreSchemaWin32To = "${env:ProgramFiles(x86)}\IIS Express\config\schema\aspnetcore_schema.xml"
+
+$aspnetCorex64IISTo = "$env:windir\system32\inetsrv\aspnetcore.dll"
+$aspnetCoreWin32IISTo = "$env:windir\syswow64\inetsrv\aspnetcore.dll"
+$aspnetCoreSchemax64IISTo = "$env:windir\system32\inetsrv\config\schema\aspnetcore_schema.xml"
+
+# if this is not solution output path, use nuget package directory structure
+if (-not (Test-Path $aspnetCorex64From))
+{
+    $aspnetCorex64From = $ExtractFilesRootPath + "\runtimes\win7-x64\native\aspnetcore.dll"
+    $aspnetCoreWin32From = $ExtractFilesRootPath + "\runtimes\win7-x86\native\aspnetcore.dll"
+    $aspnetCoreSchemax64From = $ExtractFilesRootPath + "\aspnetcore_schema.xml"
+    $aspnetCoreSchemaWin32From = $ExtractFilesRootPath + "\aspnetcore_schema.xml"
+
+    $aspnetCorex64To = "$env:ProgramFiles\IIS Express\aspnetcore.dll"
+    $aspnetCoreWin32To = "${env:ProgramFiles(x86)}\IIS Express\aspnetcore.dll"
+    $aspnetCoreSchemax64To = "$env:ProgramFiles\IIS Express\config\schema\aspnetcore_schema.xml"
+    $aspnetCoreSchemaWin32To = "${env:ProgramFiles(x86)}\IIS Express\config\schema\aspnetcore_schema.xml"
+
+    $aspnetCorex64IISTo = "$env:windir\system32\inetsrv\aspnetcore.dll"
+    $aspnetCoreWin32IISTo = "$env:windir\syswow64\inetsrv\aspnetcore.dll"
+    $aspnetCoreSchemax64IISTo = "$env:windir\system32\inetsrv\config\schema\aspnetcore_schema.xml"
+}
+
+$is64BitMachine = $env:PROCESSOR_ARCHITECTURE.ToLower() -eq "amd64"
+$isIISExpressInstalled = Test-Path $aspnetCorex64To
+$isIISInstalled = Test-Path $aspnetCorex64IISTo
+
+# Check expected files are available on IIS/IISExpress directory
+if (-not (Check-TargetFiles))
+{
+    Say ("$LogHeader Error!!! Failed to update ANCM files because AspnetCore.dll is not installed on IIS/IISExpress directory.")
+    exit $EXIT_FAIL
+}
+
+if ($Extract)
+{
+    # Extrack nuget package when $DoExtract is true
+    if (-not (Extract-ANCMFromNugetPackage))
+    {
+        Say ("$LogHeader Error!!! Failed to extract ANCM file")
+        exit $EXIT_FAIL
+    }
+}
+
+# clean up IIS and IISExpress worker processes and IIS services
+Say ("$LogHeader Stopping w3wp.exe process")
+Stop-Process -Name w3wp -ErrorAction Ignore -Force -Confirm:$false
+
+Say ("$LogHeader Stopping iisexpress.exe process")
+Stop-Process -Name iisexpress -ErrorAction Ignore -Force -Confirm:$false
+
+$w3svcGotStopped = $false
+$w3svcWindowsServce = Get-Service W3SVC -ErrorAction Ignore
+if ($w3svcWindowsServce -and $w3svcWindowsServce.Status -eq "Running")
+{
+    Say ("$LogHeader Stopping w3svc service")
+    $w3svcGotStopped = $true
+    Stop-Service W3SVC -Force -ErrorAction Ignore
+    Say ("$LogHeader Stopping w3logsvc service")
+    Stop-Service W3LOGSVC -Force -ErrorAction Ignore
+}
+
+if ($Rollback)
+{
+    Say ("$LogHeader Rolling back ANCM files...")
+}
+else
+{
+    Say  ("Updating ANCM files...")
+}
+Update-ANCM
+
+# Recover w3svc service 
+if ($w3svcGotStopped)
+{
+    Say ("$LogHeader Starting w3svc service")
+    Start-Service W3SVC -ErrorAction Ignore
+    $w3svcServiceStopped = $false
+
+    $w3svcWindowsServce = Get-Service W3SVC -ErrorAction Ignore
+    if ($w3svcWindowsServce.Status -ne "Running")
+    {
+        Say  ("$LogHeader Error!!! Failed to start w3svc service.")
+        exit $EXIT_FAIL
+    }
+}
+
+Say ("$LogHeader Finished!!!")
+exit $EXIT_SUCCESS
diff --git a/src/IISIntegration/tools/stresstest.ps1 b/src/IISIntegration/tools/stresstest.ps1
new file mode 100644
index 0000000000000000000000000000000000000000..981c6fcf44dc639c8d5ec1e75e064c40199821b0
--- /dev/null
+++ b/src/IISIntegration/tools/stresstest.ps1
@@ -0,0 +1,96 @@
+##########################################################
+# NOTE: 
+# For running test automation, following prerequisite required:
+#
+# 1. On Win7, powershell should be upgraded to 4.0
+#    https://social.technet.microsoft.com/wiki/contents/articles/21016.how-to-install-windows-powershell-4-0.aspx
+# 2. url-rewrite should be installed 
+# 3. makecert.exe tools should be available
+##########################################################
+
+# Replace aspnetcore.dll with the latest version
+copy C:\gitroot\AspNetCoreModule\artifacts\build\AspNetCore\bin\Release\x64\aspnetcore.dll "C:\Program Files\IIS Express"
+copy C:\gitroot\AspNetCoreModule\artifacts\build\AspNetCore\bin\Release\x64\aspnetcore.pdb "C:\Program Files\IIS Express"
+
+
+# Enable appverif for IISExpress.exe
+appverif /verify iisexpress.exe
+
+# Set the AspNetCoreModuleTest environment variable with the following command 
+cd C:\gitroot\AspNetCoreModule\test\AspNetCoreModule.Test
+dotnet restore
+dotnet build
+$aspNetCoreModuleTest="C:\gitroot\AspNetCoreModule\test\AspNetCoreModule.Test\bin\Debug\net46"
+
+if (Test-Path (Join-Path $aspNetCoreModuleTest aspnetcoremodule.test.dll))
+{
+    # Clean up applicationhost.config of IISExpress
+    del $env:userprofile\documents\iisexpress\config\applicationhost.config -Confirm:$false -Force
+    Start-Process "C:\Program Files\IIS Express\iisexpress.exe"
+    Sleep 3
+    Stop-Process -Name iisexpress
+
+    # Create sites
+    (1..50) | foreach { md ("C:\inetpub\wwwroot\AspnetCoreHandler_HelloWeb\foo" + $_ ) 2> out-null } 
+    (1..50) | foreach { copy C:\gitroot\AspNetCoreModule\test\StressTestWebRoot\web.config ("C:\inetpub\wwwroot\AspnetCoreHandler_HelloWeb\foo" + $_ ) } 
+    (1..50) | foreach { 
+        $path = ("C:\inetpub\wwwroot\AspnetCoreHandler_HelloWeb\foo" + $_ ) 
+        $appPath = "/foo"+$_
+         & "C:\Program Files\IIS Express\appcmd.exe" add app /site.name:"WebSite1" /path:$appPath /physicalPath:$path
+    }
+
+    <#(1..50) | foreach { 
+        $configpath = ("WebSite1/foo" + $_)
+        $value = "C:\inetpub\wwwroot\AspnetCoreHandler_HelloWeb\foo" + $_ + ".exe"
+        & "C:\Program Files\IIS Express\appcmd.exe" set config $configpath -section:system.webServer/aspNetCore /processPath:$value
+    }
+    (1..50) | foreach { copy C:\inetpub\wwwroot\AspnetCoreHandler_HelloWeb\foo.exe ("C:\inetpub\wwwroot\AspnetCoreHandler_HelloWeb\foo" + $_ +".exe") } 
+    (1..50) | foreach { 
+        $configpath = ("WebSite1/foo" + $_)
+        $value = "%AspNetCoreModuleTest%\AspnetCoreApp_HelloWeb\foo" + $_ + ".exe"
+        & "C:\Program Files\IIS Express\appcmd.exe" set config $configpath -section:system.webServer/aspNetCore /processPath:$value /apphostconfig:%AspNetCoreModuleTest%\config\applicationhost.config
+
+        $value = "%AspNetCoreModuleTest%\AspnetCoreApp_HelloWeb\AutobahnTestServer.dll"
+        & "C:\Program Files\IIS Express\appcmd.exe" set config $configpath -section:system.webServer/aspNetCore /arguments:$value /apphostconfig:%AspNetCoreModuleTest%\config\applicationhost.config
+    } 
+    #>
+    
+    # Start IISExpress with running the below command
+    &"C:\Program Files\Debugging Tools for Windows (x64)\windbg.exe" /g /G "C:\Program Files\IIS Express\iisexpress.exe"
+
+
+    # 6. Start stress testing
+    (1..10000) | foreach {
+        if ($_ % 2 -eq 0)
+        {
+            ("Recycling backend only")
+            stop-process -name dotnet 
+            (1..50) | foreach { del ("C:\inetpub\wwwroot\AspnetCoreHandler_HelloWeb\foo" + $_  + "\app_offline.htm") -confirm:$false -Force 2> out-null } 
+            stop-process -name dotnet 
+        }
+        else
+        {
+            ("Recycling backedn + enabling appoffline ....")          
+            stop-process -name dotnet
+            (1..50) | foreach { copy C:\gitroot\AspNetCoreModule\test\StressTestWebRoot\app_offline.htm ("C:\inetpub\wwwroot\AspnetCoreHandler_HelloWeb\foo" + $_ ) } 
+        }
+        Sleep 1
+
+        (1..10) | foreach {
+            (1..50) | foreach { 
+                invoke-webrequest ("http://localhost:8080/foo"+$_) > $null
+            }
+        }
+    }
+
+
+    # Stress test idea
+    # 1. Use Web Stress Tester
+    # 2. Run stop-process -name dotnet
+    # 3. Hit Q command to IISExpress console window
+    # 4. Use app_offline.htm
+    # 5. Save dummy web.config 
+}
+
+// bp aspnetcore!FORWARDING_HANDLER::FORWARDING_HANDLER
+// bp aspnetcore!FORWARDING_HANDLER::~FORWARDING_HANDLER
\ No newline at end of file
diff --git a/src/IISIntegration/tools/update_schema.ps1 b/src/IISIntegration/tools/update_schema.ps1
new file mode 100644
index 0000000000000000000000000000000000000000..b299c91e6aba5fff56c0900b05ef89cfebadb678
--- /dev/null
+++ b/src/IISIntegration/tools/update_schema.ps1
@@ -0,0 +1,55 @@
+<#
+.DESCRIPTION
+Updates aspnetcore_schema.xml to the latest version.
+Requires admin privileges.
+#>
+[cmdletbinding(SupportsShouldProcess = $true)]
+param()
+
+$ErrorActionPreference = 'Stop'
+Set-StrictMode -Version 1
+
+$schemaSource = Resolve-Path "$PSScriptRoot\..\src\AspNetCoreModuleV2\AspNetCore\aspnetcore_schema.xml"
+[bool]$isAdmin = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")
+
+if (-not $isAdmin -and -not $WhatIfPreference) {
+    if ($PSCmdlet.ShouldContinue("Continue as an admin?", "This script needs admin privileges to update IIS Express and IIS.")) {
+        $thisFile = Join-Path $PSScriptRoot $MyInvocation.MyCommand.Name
+
+        Start-Process `
+            -Verb runas `
+            -FilePath "powershell.exe" `
+            -ArgumentList $thisFile `
+            -Wait `
+            | Out-Null
+
+        if (-not $?) {
+            throw 'Update failed'
+        }
+        exit
+    }
+    else {
+        throw 'Requires admin privileges'
+    }
+}
+
+$destinations = @(
+    "${env:ProgramFiles(x86)}\IIS Express\config\schema\aspnetcore_schema.xml",
+    "${env:ProgramFiles}\IIS Express\config\schema\aspnetcore_schema.xml",
+    "${env:windir}\system32\inetsrv\config\schema\aspnetcore_schema.xml"
+) | Get-Unique
+
+
+foreach ($dest in $destinations) {
+    if (-not (Test-Path $dest)) {
+        Write-Host -ForegroundColor Yellow "Skipping $dest. File does not already exist."
+        continue
+    }
+
+    if ($PSCmdlet.ShouldProcess($dest, "Replace file")) {
+        Write-Host "Updated $dest"
+        Move-Item $dest "${dest}.bak" -ErrorAction Ignore
+        Copy-Item $schemaSource $dest
+    }
+}
+
diff --git a/src/IISIntegration/version.props b/src/IISIntegration/version.props
new file mode 100644
index 0000000000000000000000000000000000000000..e897351a24cc220825771d30fac84356cdd42b12
--- /dev/null
+++ b/src/IISIntegration/version.props
@@ -0,0 +1,18 @@
+<Project>
+  <PropertyGroup>
+    <DotNetMajorVersion>2</DotNetMajorVersion>
+    <DotNetMinorVersion>1</DotNetMinorVersion>
+    <DotNetPatchVersion>2</DotNetPatchVersion>
+    <VersionPrefix>$(DotNetMajorVersion).$(DotNetMinorVersion).$(DotNetPatchVersion)</VersionPrefix>
+    <AspNetCoreModuleVersionMajor>12</AspNetCoreModuleVersionMajor>
+    <AspNetCoreModuleVersionMinor>$(DotNetMinorVersion)</AspNetCoreModuleVersionMinor>
+    <AspNetCoreModuleVersionRevision>$(DotNetPatchVersion)</AspNetCoreModuleVersionRevision>
+    <VersionSuffix>rtm</VersionSuffix>
+    <PackageVersion Condition="'$(IsFinalBuild)' == 'true' AND '$(VersionSuffix)' == 'rtm' ">$(VersionPrefix)</PackageVersion>
+    <PackageVersion Condition="'$(IsFinalBuild)' == 'true' AND '$(VersionSuffix)' != 'rtm' ">$(VersionPrefix)-$(VersionSuffix)-final</PackageVersion>
+    <BuildNumber Condition="'$(BuildNumber)' == ''">t000</BuildNumber>
+    <FeatureBranchVersionPrefix Condition="'$(FeatureBranchVersionPrefix)' == ''">a-</FeatureBranchVersionPrefix>
+    <VersionSuffix Condition="'$(VersionSuffix)' != '' And '$(FeatureBranchVersionSuffix)' != ''">$(FeatureBranchVersionPrefix)$(VersionSuffix)-$([System.Text.RegularExpressions.Regex]::Replace('$(FeatureBranchVersionSuffix)', '[^\w-]', '-'))</VersionSuffix>
+    <VersionSuffix Condition="'$(VersionSuffix)' != '' And '$(BuildNumber)' != ''">$(VersionSuffix)-$(BuildNumber)</VersionSuffix>
+  </PropertyGroup>
+</Project>