diff --git a/.gitignore b/.gitignore index ddefb684fa..5004d81d9d 100644 --- a/.gitignore +++ b/.gitignore @@ -25,15 +25,9 @@ project.lock.json *.ncrunchsolution *.*sdf *.ipch -<<<<<<< HEAD -*.vs/ .vscode/ -.testPublish/ -.build/ *.nuget.props *.nuget.targets -global.json -======= *.bin *.vs/ .testPublish/ @@ -41,12 +35,15 @@ global.json *.obj *.tlog *.CppClean.log +*msbuild.log src/*/Debug/ src/*/x64/Debug/ src/*/Release/ src/*/x64/Release/ +x64/ +*vcxproj.filters *.aps *.pdb *.lib @@ -59,5 +56,3 @@ src/AspNetCore/version.h *.VC.*db global.json - ->>>>>>> ANCM/dev diff --git a/AspNetCoreModule.sln b/AspNetCoreModule.sln deleted file mode 100644 index a6d854e59b..0000000000 --- a/AspNetCoreModule.sln +++ /dev/null @@ -1,93 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.27110.0 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AspNetCore", "src\AspNetCore\AspNetCore.vcxproj", "{439824F9-1455-4CC4-BD79-B44FA0A16552}" - ProjectSection(ProjectDependencies) = postProject - {4787A64F-9A3E-4867-A55A-70CB4B2B2FFE} = {4787A64F-9A3E-4867-A55A-70CB4B2B2FFE} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "IISLib", "src\IISLib\IISLib.vcxproj", "{4787A64F-9A3E-4867-A55A-70CB4B2B2FFE}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{02F461DC-5166-4E88-AAD5-CF110016A647}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{FDD2EDF8-1B62-4978-9815-9D95260B8B91}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AspNetCoreModule.Test", "test\AspNetCoreModule.Test\AspNetCoreModule.Test.csproj", "{4DDA7560-AA29-4161-A5EA-A7E8F3997321}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AspNetCoreModule.TestSites.Standard", "test\AspNetCoreModule.TestSites.Standard\AspNetCoreModule.TestSites.Standard.csproj", "{030225D8-4EE8-47E5-B692-2A96B3B51A38}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{0EF45656-B25D-40D8-959C-726EAF185E60}" - ProjectSection(SolutionItems) = preProject - NuGet.Config = NuGet.Config - EndProjectSection -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Debug|Win32 = Debug|Win32 - Debug|x64 = Debug|x64 - Release|Any CPU = Release|Any CPU - Release|Win32 = Release|Win32 - Release|x64 = Release|x64 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {439824F9-1455-4CC4-BD79-B44FA0A16552}.Debug|Any CPU.ActiveCfg = Debug|Win32 - {439824F9-1455-4CC4-BD79-B44FA0A16552}.Debug|Win32.ActiveCfg = Release|x64 - {439824F9-1455-4CC4-BD79-B44FA0A16552}.Debug|Win32.Build.0 = Release|x64 - {439824F9-1455-4CC4-BD79-B44FA0A16552}.Debug|x64.ActiveCfg = Debug|x64 - {439824F9-1455-4CC4-BD79-B44FA0A16552}.Debug|x64.Build.0 = Debug|x64 - {439824F9-1455-4CC4-BD79-B44FA0A16552}.Release|Any CPU.ActiveCfg = Release|Win32 - {439824F9-1455-4CC4-BD79-B44FA0A16552}.Release|Win32.ActiveCfg = Release|Win32 - {439824F9-1455-4CC4-BD79-B44FA0A16552}.Release|Win32.Build.0 = Release|Win32 - {439824F9-1455-4CC4-BD79-B44FA0A16552}.Release|x64.ActiveCfg = Release|x64 - {439824F9-1455-4CC4-BD79-B44FA0A16552}.Release|x64.Build.0 = Release|x64 - {4787A64F-9A3E-4867-A55A-70CB4B2B2FFE}.Debug|Any CPU.ActiveCfg = Debug|Win32 - {4787A64F-9A3E-4867-A55A-70CB4B2B2FFE}.Debug|Win32.ActiveCfg = Release|x64 - {4787A64F-9A3E-4867-A55A-70CB4B2B2FFE}.Debug|Win32.Build.0 = Release|x64 - {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}.Release|Any CPU.ActiveCfg = Release|Win32 - {4787A64F-9A3E-4867-A55A-70CB4B2B2FFE}.Release|Win32.ActiveCfg = Release|Win32 - {4787A64F-9A3E-4867-A55A-70CB4B2B2FFE}.Release|Win32.Build.0 = Release|Win32 - {4787A64F-9A3E-4867-A55A-70CB4B2B2FFE}.Release|x64.ActiveCfg = Release|x64 - {4787A64F-9A3E-4867-A55A-70CB4B2B2FFE}.Release|x64.Build.0 = Release|x64 - {4DDA7560-AA29-4161-A5EA-A7E8F3997321}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {4DDA7560-AA29-4161-A5EA-A7E8F3997321}.Debug|Any CPU.Build.0 = Debug|Any CPU - {4DDA7560-AA29-4161-A5EA-A7E8F3997321}.Debug|Win32.ActiveCfg = Debug|Any CPU - {4DDA7560-AA29-4161-A5EA-A7E8F3997321}.Debug|Win32.Build.0 = Debug|Any CPU - {4DDA7560-AA29-4161-A5EA-A7E8F3997321}.Debug|x64.ActiveCfg = Debug|Any CPU - {4DDA7560-AA29-4161-A5EA-A7E8F3997321}.Debug|x64.Build.0 = Debug|Any CPU - {4DDA7560-AA29-4161-A5EA-A7E8F3997321}.Release|Any CPU.ActiveCfg = Release|Any CPU - {4DDA7560-AA29-4161-A5EA-A7E8F3997321}.Release|Any CPU.Build.0 = Release|Any CPU - {4DDA7560-AA29-4161-A5EA-A7E8F3997321}.Release|Win32.ActiveCfg = Release|Any CPU - {4DDA7560-AA29-4161-A5EA-A7E8F3997321}.Release|Win32.Build.0 = Release|Any CPU - {4DDA7560-AA29-4161-A5EA-A7E8F3997321}.Release|x64.ActiveCfg = Release|Any CPU - {4DDA7560-AA29-4161-A5EA-A7E8F3997321}.Release|x64.Build.0 = Release|Any CPU - {030225D8-4EE8-47E5-B692-2A96B3B51A38}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {030225D8-4EE8-47E5-B692-2A96B3B51A38}.Debug|Any CPU.Build.0 = Debug|Any CPU - {030225D8-4EE8-47E5-B692-2A96B3B51A38}.Debug|Win32.ActiveCfg = Debug|Any CPU - {030225D8-4EE8-47E5-B692-2A96B3B51A38}.Debug|Win32.Build.0 = Debug|Any CPU - {030225D8-4EE8-47E5-B692-2A96B3B51A38}.Debug|x64.ActiveCfg = Debug|Any CPU - {030225D8-4EE8-47E5-B692-2A96B3B51A38}.Debug|x64.Build.0 = Debug|Any CPU - {030225D8-4EE8-47E5-B692-2A96B3B51A38}.Release|Any CPU.ActiveCfg = Release|Any CPU - {030225D8-4EE8-47E5-B692-2A96B3B51A38}.Release|Any CPU.Build.0 = Release|Any CPU - {030225D8-4EE8-47E5-B692-2A96B3B51A38}.Release|Win32.ActiveCfg = Release|Any CPU - {030225D8-4EE8-47E5-B692-2A96B3B51A38}.Release|Win32.Build.0 = Release|Any CPU - {030225D8-4EE8-47E5-B692-2A96B3B51A38}.Release|x64.ActiveCfg = Release|Any CPU - {030225D8-4EE8-47E5-B692-2A96B3B51A38}.Release|x64.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(NestedProjects) = preSolution - {439824F9-1455-4CC4-BD79-B44FA0A16552} = {FDD2EDF8-1B62-4978-9815-9D95260B8B91} - {4787A64F-9A3E-4867-A55A-70CB4B2B2FFE} = {FDD2EDF8-1B62-4978-9815-9D95260B8B91} - {4DDA7560-AA29-4161-A5EA-A7E8F3997321} = {02F461DC-5166-4E88-AAD5-CF110016A647} - {030225D8-4EE8-47E5-B692-2A96B3B51A38} = {02F461DC-5166-4E88-AAD5-CF110016A647} - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {0967E9B4-FEE7-40D7-860A-23E340E65840} - EndGlobalSection -EndGlobal diff --git a/Directory.Build.props b/Directory.Build.props index 2a4a55f689..a03bf421cb 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,17 +1,12 @@ -<<<<<<< HEAD - + -======= - ->>>>>>> ANCM/dev -<<<<<<< HEAD Microsoft ASP.NET Core https://github.com/aspnet/IISIntegration @@ -28,14 +23,4 @@ -======= - - Microsoft ASP.NET Core - https://github.com/aspnet/AspNetCoreModule - git - $(MSBuildThisFileDirectory)build\Key.snk - true - true - ->>>>>>> ANCM/dev diff --git a/IISIntegration.sln b/IISIntegration.sln index 75d59c5d46..12bb8b1bc8 100644 --- a/IISIntegration.sln +++ b/IISIntegration.sln @@ -45,6 +45,14 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IISTestSite", "test\IISTest EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IISIntegration.IISServerFunctionalTests", "test\IISIntegration.IISServerFunctionalTests\IISIntegration.IISServerFunctionalTests.csproj", "{C745BBFD-7888-4038-B41B-6D1832D13878}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AspNetCore", "src\AspNetCore\AspNetCore.vcxproj", "{439824F9-1455-4CC4-BD79-B44FA0A16552}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "IISLib", "src\IISLib\IISLib.vcxproj", "{4787A64F-9A3E-4867-A55A-70CB4B2B2FFE}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RequestHandler", "src\RequestHandler\RequestHandler.vcxproj", "{D57EA297-6DC2-4BC0-8C91-334863327863}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CommonLib", "src\CommonLib\CommonLib.vcxproj", "{55494E58-E061-4C4C-A0A8-837008E72F85}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -150,6 +158,50 @@ Global {C745BBFD-7888-4038-B41B-6D1832D13878}.Release|x64.ActiveCfg = Release|Any CPU {C745BBFD-7888-4038-B41B-6D1832D13878}.Release|x64.Build.0 = Release|Any CPU {C745BBFD-7888-4038-B41B-6D1832D13878}.Release|x86.ActiveCfg = Release|Any CPU + {439824F9-1455-4CC4-BD79-B44FA0A16552}.Debug|Any CPU.ActiveCfg = Debug|Win32 + {439824F9-1455-4CC4-BD79-B44FA0A16552}.Debug|x64.ActiveCfg = Debug|x64 + {439824F9-1455-4CC4-BD79-B44FA0A16552}.Debug|x64.Build.0 = Debug|x64 + {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 + {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 + {D57EA297-6DC2-4BC0-8C91-334863327863}.Debug|Any CPU.ActiveCfg = Debug|Win32 + {D57EA297-6DC2-4BC0-8C91-334863327863}.Debug|Win32.ActiveCfg = Debug|x64 + {D57EA297-6DC2-4BC0-8C91-334863327863}.Debug|Win32.Build.0 = Debug|x64 + {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}.Release|Any CPU.ActiveCfg = Release|Win32 + {D57EA297-6DC2-4BC0-8C91-334863327863}.Release|Win32.ActiveCfg = Release|Win32 + {D57EA297-6DC2-4BC0-8C91-334863327863}.Release|Win32.Build.0 = Release|Win32 + {D57EA297-6DC2-4BC0-8C91-334863327863}.Release|x64.ActiveCfg = Release|x64 + {D57EA297-6DC2-4BC0-8C91-334863327863}.Release|x64.Build.0 = Release|x64 + {55494E58-E061-4C4C-A0A8-837008E72F85}.Debug|Any CPU.ActiveCfg = Debug|Win32 + {55494E58-E061-4C4C-A0A8-837008E72F85}.Debug|Win32.ActiveCfg = Debug|x64 + {55494E58-E061-4C4C-A0A8-837008E72F85}.Debug|Win32.Build.0 = Debug|x64 + {55494E58-E061-4C4C-A0A8-837008E72F85}.Debug|Win32.Deploy.0 = Debug|x64 + {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|x64.Deploy.0 = Debug|x64 + {55494E58-E061-4C4C-A0A8-837008E72F85}.Release|Any CPU.ActiveCfg = Release|Win32 + {55494E58-E061-4C4C-A0A8-837008E72F85}.Release|Win32.ActiveCfg = Release|Win32 + {55494E58-E061-4C4C-A0A8-837008E72F85}.Release|Win32.Build.0 = Release|Win32 + {55494E58-E061-4C4C-A0A8-837008E72F85}.Release|Win32.Deploy.0 = 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|x64.Deploy.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -163,6 +215,10 @@ Global {9BC4AFCB-325D-4C81-8228-8CF301CE2F97} = {C74B8F36-FD2F-45C9-9B8A-00E7CF0126A9} {679FA2A2-898B-4320-884E-C2D294A97CE1} = {EF30B533-D715-421A-92B7-92FEF460AC9C} {C745BBFD-7888-4038-B41B-6D1832D13878} = {EF30B533-D715-421A-92B7-92FEF460AC9C} + {439824F9-1455-4CC4-BD79-B44FA0A16552} = {04B1EDB6-E967-4D25-89B9-E6F8304038CD} + {4787A64F-9A3E-4867-A55A-70CB4B2B2FFE} = {04B1EDB6-E967-4D25-89B9-E6F8304038CD} + {D57EA297-6DC2-4BC0-8C91-334863327863} = {FDD2EDF8-1B62-4978-9815-9D95260B8B91} + {55494E58-E061-4C4C-A0A8-837008E72F85} = {FDD2EDF8-1B62-4978-9815-9D95260B8B91} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {DB4F868D-E1AE-4FD7-9333-69FA15B268C5} diff --git a/LICENSE.txt b/LICENSE.txt index 64abc3099c..d50cef4a3f 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,4 +1,3 @@ -<<<<<<< HEAD Copyright (c) .NET Foundation and Contributors All rights reserved. @@ -13,7 +12,7 @@ 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 @@ -36,5 +35,4 @@ 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. ->>>>>>> ANCM/dev +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md index 683efab329..94f5fa5df9 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,7 @@ -<<<<<<< HEAD -ASP.NET Core IIS Integration -======== - This repo hosts the ASP.NET Core middleware for IIS integration. 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. + ======= # ASP.NET Core Module diff --git a/build.cmd b/build.cmd index d3bb975df1..c0050bda12 100644 --- a/build.cmd +++ b/build.cmd @@ -1,6 +1,2 @@ @ECHO OFF -<<<<<<< HEAD PowerShell -NoProfile -NoLogo -ExecutionPolicy unrestricted -Command "[System.Threading.Thread]::CurrentThread.CurrentCulture = ''; [System.Threading.Thread]::CurrentThread.CurrentUICulture = '';& '%~dp0run.ps1' default-build %*; exit $LASTEXITCODE" -======= -PowerShell -NoProfile -NoLogo -ExecutionPolicy unrestricted -Command "[System.Threading.Thread]::CurrentThread.CurrentCulture = ''; [System.Threading.Thread]::CurrentThread.CurrentUICulture = '';& '%~dp0run.ps1' default-build %*; exit $LASTEXITCODE" ->>>>>>> ANCM/dev diff --git a/build/build.msbuild b/build/build.msbuild index 59c022e99c..c731cd9ff8 100644 --- a/build/build.msbuild +++ b/build/build.msbuild @@ -3,6 +3,7 @@ + diff --git a/build/repo.props b/build/repo.props index 4d9fa51c7f..810db16cd7 100644 --- a/build/repo.props +++ b/build/repo.props @@ -1,5 +1,4 @@ -<<<<<<< HEAD - + diff --git a/build/repo.targets b/build/repo.targets index 43afd316c8..97c447ab01 100644 --- a/build/repo.targets +++ b/build/repo.targets @@ -16,6 +16,8 @@ + diff --git a/build/sources.props b/build/sources.props index c91e42df09..05a4b7dc2e 100644 --- a/build/sources.props +++ b/build/sources.props @@ -1,8 +1,4 @@ -<<<<<<< HEAD - -======= ->>>>>>> ANCM/dev diff --git a/korebuild-lock.txt b/korebuild-lock.txt index a1256be6f8..fe4a961da3 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,7 +1,2 @@ -<<<<<<< HEAD -version:2.1.0-preview1-15576 -commithash:2f3856d2ba4f659fcb9253215b83946a06794a27 -======= version:2.1.0-preview1-15620 commithash:6432b49a2c00310416df39b6fe548ef4af9c6011 ->>>>>>> ANCM/dev diff --git a/korebuild.json b/korebuild.json index 79c0242c7a..80e6e41c09 100644 --- a/korebuild.json +++ b/korebuild.json @@ -1,9 +1,4 @@ { -<<<<<<< HEAD - "$schema": "https://raw.githubusercontent.com/aspnet/BuildTools/dev/tools/korebuild.schema.json", - "channel": "dev" -} -======= "$schema": "https://raw.githubusercontent.com/aspnet/BuildTools/dev/tools/korebuild.schema.json", "channel": "dev", "toolsets": { @@ -16,5 +11,4 @@ ] } } - } ->>>>>>> ANCM/dev + } \ No newline at end of file diff --git a/nuget/AspNetCore.nuspec b/nuget/AspNetCore.nuspec index a91aeee733..bb3c627b3e 100644 --- a/nuget/AspNetCore.nuspec +++ b/nuget/AspNetCore.nuspec @@ -20,6 +20,8 @@ + + diff --git a/nuget/Microsoft.AspNetCore.AspNetCoreModule.props b/nuget/Microsoft.AspNetCore.AspNetCoreModule.props index 7a761813b4..5b01ee63a4 100644 --- a/nuget/Microsoft.AspNetCore.AspNetCoreModule.props +++ b/nuget/Microsoft.AspNetCore.AspNetCoreModule.props @@ -3,6 +3,8 @@ $(MSBuildThisFileDirectory)..\contentFiles\any\any\x64\aspnetcore.dll $(MSBuildThisFileDirectory)..\contentFiles\any\any\x86\aspnetcore.dll + $(MSBuildThisFileDirectory)..\contentFiles\any\any\x64\aspnetcorerh.dll + $(MSBuildThisFileDirectory)..\contentFiles\any\any\x86\aspnetcorerh.dll diff --git a/run.cmd b/run.cmd index 47b40d746e..d52d5c7e68 100644 --- a/run.cmd +++ b/run.cmd @@ -1,6 +1,2 @@ @ECHO OFF -<<<<<<< HEAD PowerShell -NoProfile -NoLogo -ExecutionPolicy unrestricted -Command "[System.Threading.Thread]::CurrentThread.CurrentCulture = ''; [System.Threading.Thread]::CurrentThread.CurrentUICulture = '';& '%~dp0run.ps1' %*; exit $LASTEXITCODE" -======= -PowerShell -NoProfile -NoLogo -ExecutionPolicy unrestricted -Command "[System.Threading.Thread]::CurrentThread.CurrentCulture = ''; [System.Threading.Thread]::CurrentThread.CurrentUICulture = '';& '%~dp0run.ps1' %*; exit $LASTEXITCODE" ->>>>>>> ANCM/dev diff --git a/run.ps1 b/run.ps1 index 4b3425ac8a..b7de403018 100644 --- a/run.ps1 +++ b/run.ps1 @@ -29,12 +29,9 @@ Updates KoreBuild to the latest version even if a lock file is present. .PARAMETER ConfigFile The path to the configuration file that stores values. Defaults to korebuild.json. -<<<<<<< HEAD .PARAMETER ToolsSourceSuffix The Suffix to append to the end of the ToolsSource. Useful for query strings in blob stores. -======= ->>>>>>> ANCM/dev .PARAMETER Arguments Arguments to be passed to the command @@ -57,11 +54,7 @@ Example config file: #> [CmdletBinding(PositionalBinding = $false)] param( -<<<<<<< HEAD [Parameter(Mandatory = $true, Position = 0)] -======= - [Parameter(Mandatory=$true, Position = 0)] ->>>>>>> ANCM/dev [string]$Command, [string]$Path = $PSScriptRoot, [Alias('c')] @@ -73,10 +66,7 @@ param( [Alias('u')] [switch]$Update, [string]$ConfigFile, -<<<<<<< HEAD [string]$ToolsSourceSuffix, -======= ->>>>>>> ANCM/dev [Parameter(ValueFromRemainingArguments = $true)] [string[]]$Arguments ) @@ -93,11 +83,7 @@ function Get-KoreBuild { $lockFile = Join-Path $Path 'korebuild-lock.txt' if (!(Test-Path $lockFile) -or $Update) { -<<<<<<< HEAD Get-RemoteFile "$ToolsSource/korebuild/channels/$Channel/latest.txt" $lockFile $ToolsSourceSuffix -======= - Get-RemoteFile "$ToolsSource/korebuild/channels/$Channel/latest.txt" $lockFile ->>>>>>> ANCM/dev } $version = Get-Content $lockFile | Where-Object { $_ -like 'version:*' } | Select-Object -first 1 @@ -114,11 +100,7 @@ function Get-KoreBuild { try { $tmpfile = Join-Path ([IO.Path]::GetTempPath()) "KoreBuild-$([guid]::NewGuid()).zip" -<<<<<<< HEAD Get-RemoteFile $remotePath $tmpfile $ToolsSourceSuffix -======= - Get-RemoteFile $remotePath $tmpfile ->>>>>>> ANCM/dev if (Get-Command -Name 'Expand-Archive' -ErrorAction Ignore) { # Use built-in commands where possible as they are cross-plat compatible Expand-Archive -Path $tmpfile -DestinationPath $korebuildPath @@ -146,11 +128,7 @@ function Join-Paths([string]$path, [string[]]$childPaths) { return $path } -<<<<<<< HEAD function Get-RemoteFile([string]$RemotePath, [string]$LocalPath, [string]$RemoteSuffix) { -======= -function Get-RemoteFile([string]$RemotePath, [string]$LocalPath) { ->>>>>>> ANCM/dev if ($RemotePath -notlike 'http*') { Copy-Item $RemotePath $LocalPath return @@ -160,11 +138,7 @@ function Get-RemoteFile([string]$RemotePath, [string]$LocalPath) { while ($retries -gt 0) { $retries -= 1 try { -<<<<<<< HEAD Invoke-WebRequest -UseBasicParsing -Uri $($RemotePath + $RemoteSuffix) -OutFile $LocalPath -======= - Invoke-WebRequest -UseBasicParsing -Uri $RemotePath -OutFile $LocalPath ->>>>>>> ANCM/dev return } catch { @@ -191,12 +165,8 @@ if (Test-Path $ConfigFile) { if (!($Channel) -and (Get-Member -Name 'channel' -InputObject $config)) { [string] $Channel = $config.channel } if (!($ToolsSource) -and (Get-Member -Name 'toolsSource' -InputObject $config)) { [string] $ToolsSource = $config.toolsSource} } -<<<<<<< HEAD } catch { -======= - } catch { ->>>>>>> ANCM/dev Write-Warning "$ConfigFile could not be read. Its settings will be ignored." Write-Warning $Error[0] } @@ -223,8 +193,4 @@ try { } finally { Remove-Module 'KoreBuild' -ErrorAction Ignore -<<<<<<< HEAD -} -======= -} ->>>>>>> ANCM/dev +} \ No newline at end of file diff --git a/src/AspNetCore/AspNetCore.vcxproj b/src/AspNetCore/AspNetCore.vcxproj index 005f0c5d5a..1237d765a8 100644 --- a/src/AspNetCore/AspNetCore.vcxproj +++ b/src/AspNetCore/AspNetCore.vcxproj @@ -40,7 +40,6 @@ true v141 Unicode - false DynamicLibrary @@ -75,16 +74,34 @@ $(SolutionDir)artifacts\build\$(ProjectName)\bin\$(Configuration)\$(Platform) + + $(SolutionDir)artifacts\build\$(ProjectName)\bin\$(Configuration)\$(Platform) + + + $(SolutionDir)artifacts\build\$(ProjectName)\bin\$(Configuration)\$(Platform) + NotUsing - Level3 + Level4 Disabled WIN32;_DEBUG;_WINDOWS;_USRDLL;ASPNETCOREMODULE_EXPORTS;%(PreprocessorDefinitions) precomp.hxx $(IntDir)$(TargetName).pch ..\IISLib;.\Inc ProgramDatabase + MultiThreadedDebug + true + true + true + false + SyncCThrow + 8Bytes + true + false + true + CompileAsCpp + true Windows @@ -104,6 +121,17 @@ ..\IISLib;.\Inc ProgramDatabase MultiThreadedDebug + true + true + true + false + SyncCThrow + 8Bytes + true + false + true + CompileAsCpp + true Windows @@ -123,6 +151,17 @@ ..\IISLib;inc precomp.hxx MultiThreaded + true + true + true + false + SyncCThrow + 8Bytes + true + false + true + CompileAsCpp + true Windows @@ -144,6 +183,17 @@ precomp.hxx ..\IISLib;inc MultiThreaded + true + true + true + false + SyncCThrow + 8Bytes + true + false + true + CompileAsCpp + true Windows @@ -155,52 +205,22 @@ - + + + - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - + - - - - @@ -221,29 +241,16 @@ - - - Document - mc %(FullPath) - Compiling Event Messages ... - %(Filename).rc;%(Filename).h;MSG0409.bin - mc %(FullPath) - Compiling Event Messages ... - %(Filename).rc;%(Filename).h;MSG0409.bin - mc %(FullPath) - Compiling Event Messages ... - %(Filename).rc;%(Filename).h;MSG0409.bin - mc %(FullPath) - Compiling Event Messages ... - %(Filename).rc;%(Filename).h;MSG0409.bin - - + + {55494e58-e061-4c4c-a0a8-837008e72f85} + {4787a64f-9a3e-4867-a55a-70cb4b2b2ffe} + false @@ -254,6 +261,9 @@ PreserveNewest + + + diff --git a/src/AspNetCore/Inc/application.h b/src/AspNetCore/Inc/application.h deleted file mode 100644 index 3bed6712b8..0000000000 --- a/src/AspNetCore/Inc/application.h +++ /dev/null @@ -1,286 +0,0 @@ -// 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 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_pApplicationManager(NULL), m_cRefs(1), - m_fAppOfflineFound(FALSE), m_pAppOfflineHtm(NULL), - m_pFileWatcherEntry(NULL), m_pConfiguration(NULL) - { - InitializeSRWLock(&m_srwLock); - } - - APPLICATION_KEY * - QueryApplicationKey() - { - return &m_applicationKey; - } - - virtual - ~APPLICATION(); - - virtual - HRESULT - Initialize( - _In_ APPLICATION_MANAGER *pApplicationManager, - _In_ ASPNETCORE_CONFIG *pConfiguration) = 0; - - VOID - ReferenceApplication() const - { - InterlockedIncrement(&m_cRefs); - } - - VOID - DereferenceApplication() const - { - if (InterlockedDecrement(&m_cRefs) == 0) - { - delete this; - } - } - - APP_OFFLINE_HTM* QueryAppOfflineHtm() - { - return m_pAppOfflineHtm; - } - - BOOL - AppOfflineFound() - { - return m_fAppOfflineFound; - } - - virtual - VOID - OnAppOfflineHandleChange() = 0; - - VOID - UpdateAppOfflineFileHandle(); - - HRESULT - StartMonitoringAppOffline(); - - ASPNETCORE_CONFIG* - QueryConfig() - { - return m_pConfiguration; - } - - virtual - REQUEST_NOTIFICATION_STATUS - ExecuteRequest( - _In_ IHttpContext* pHttpContext - ) = 0; - -protected: - - mutable LONG m_cRefs; - APPLICATION_KEY m_applicationKey; - APPLICATION_MANAGER *m_pApplicationManager; - BOOL m_fAppOfflineFound; - APP_OFFLINE_HTM *m_pAppOfflineHtm; - FILE_WATCHER_ENTRY *m_pFileWatcherEntry; - ASPNETCORE_CONFIG *m_pConfiguration; - SRWLOCK m_srwLock; - -}; - -class APPLICATION_HASH : - public HASH_TABLE -{ - -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/AspNetCore/Inc/applicationinfo.h b/src/AspNetCore/Inc/applicationinfo.h new file mode 100644 index 0000000000..47519adb6d --- /dev/null +++ b/src/AspNetCore/Inc/applicationinfo.h @@ -0,0 +1,218 @@ +// 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 +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; + } + + APPLICATION* + QueryApplication() + { + return m_pApplication; + } + + HRESULT + EnsureApplicationCreated(); + + PFN_ASPNETCORE_CREATE_REQUEST_HANDLER + QueryCreateRequestHandler() + { + return m_pfnAspNetCoreCreateRequestHandler; + } + +private: + HRESULT FindRequestHandlerAssembly(); + HRESULT FindNativeAssemblyFromGlobalLocation(STRU* struFilename); + HRESULT FindNativeAssemblyFromLocalBin(STRU* struFilename); + HRESULT GetRequestHandlerFromRuntimeStore(STRU* struFilename); + + 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 +{ + +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(); + } + +private: + + APPLICATION_INFO_HASH(const APPLICATION_INFO_HASH &); + void operator=(const APPLICATION_INFO_HASH &); +}; diff --git a/src/AspNetCore/Inc/applicationmanager.h b/src/AspNetCore/Inc/applicationmanager.h index 9b413341bd..9e9b062ba2 100644 --- a/src/AspNetCore/Inc/applicationmanager.h +++ b/src/AspNetCore/Inc/applicationmanager.h @@ -5,6 +5,11 @@ #define DEFAULT_HASH_BUCKETS 293 +// +// 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 +// class APPLICATION_MANAGER { public: @@ -15,12 +20,12 @@ public: VOID ) { - if( sm_pApplicationManager == NULL ) + if ( sm_pApplicationManager == NULL ) { sm_pApplicationManager = new APPLICATION_MANAGER(); } - return sm_pApplicationManager; + return sm_pApplicationManager; } static @@ -37,29 +42,27 @@ public: } HRESULT - GetApplication( - _In_ IHttpContext* pContext, + GetApplicationInfo( + _In_ IHttpServer* pServer, _In_ ASPNETCORE_CONFIG* pConfig, - _Out_ APPLICATION ** ppApplication + _Out_ APPLICATION_INFO ** ppApplicationInfo ); HRESULT - RecycleApplication( - _In_ LPCWSTR pszApplication + RecycleApplication( + _In_ LPCWSTR pszApplicationId ); - HRESULT - Get502ErrorPage( - _Out_ HTTP_DATA_CHUNK** ppErrorPage - ); + VOID + ShutDown(); ~APPLICATION_MANAGER() { - if(m_pApplicationHash != NULL) + if(m_pApplicationInfoHash != NULL) { - m_pApplicationHash->Clear(); - delete m_pApplicationHash; - m_pApplicationHash = NULL; + m_pApplicationInfoHash->Clear(); + delete m_pApplicationInfoHash; + m_pApplicationInfoHash = NULL; } if( m_pFileWatcher!= NULL ) @@ -67,13 +70,6 @@ public: delete m_pFileWatcher; m_pFileWatcher = NULL; } - - if(m_pHttp502ErrorPage != NULL) - { - delete m_pHttp502ErrorPage; - m_pHttp502ErrorPage = NULL; - } - } FILE_WATCHER* @@ -86,16 +82,16 @@ public: { HRESULT hr = S_OK; - if(m_pApplicationHash == NULL) + if(m_pApplicationInfoHash == NULL) { - m_pApplicationHash = new APPLICATION_HASH(); - if(m_pApplicationHash == NULL) + m_pApplicationInfoHash = new APPLICATION_INFO_HASH(); + if(m_pApplicationInfoHash == NULL) { hr = E_OUTOFMEMORY; goto Finished; } - hr = m_pApplicationHash->Initialize(DEFAULT_HASH_BUCKETS); + hr = m_pApplicationInfoHash->Initialize(DEFAULT_HASH_BUCKETS); if(FAILED(hr)) { goto Finished; @@ -122,41 +118,18 @@ 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_hostingModel(HOSTING_UNKNOWN), - m_pstrErrorInfo( - " \ - \ - \ - \ - IIS 502.5 Error \ -
\ -

HTTP Error 502.5 - Process Failure

\ -
\ -

Common causes of this issue:

\ -
  • The application process failed to start
  • \ -
  • The application process started but then stopped
  • \ -
  • The application process started but failed to listen on the configured port
\ -
\ -
\ -

Troubleshooting steps:

\ -
  • Check the system event log for error messages
  • \ -
  • Enable logging the application process' stdout messages
  • \ -
  • Attach a debugger to the application process and inspect
\ -

For more information visit: \ - https://go.microsoft.com/fwlink/?LinkID=808681

\ -
\ -
\ -
") + APPLICATION_MANAGER() : m_pApplicationInfoHash(NULL), + m_pFileWatcher(NULL), + m_hostingModel(HOSTING_UNKNOWN), + m_fInShutdown(FALSE) { InitializeSRWLock(&m_srwLock); } FILE_WATCHER *m_pFileWatcher; - APPLICATION_HASH *m_pApplicationHash; + APPLICATION_INFO_HASH *m_pApplicationInfoHash; static APPLICATION_MANAGER *sm_pApplicationManager; SRWLOCK m_srwLock; - HTTP_DATA_CHUNK *m_pHttp502ErrorPage; - LPSTR m_pstrErrorInfo; APP_HOSTING_MODEL m_hostingModel; + bool m_fInShutdown; }; \ No newline at end of file diff --git a/src/AspNetCore/Inc/appoffline.h b/src/AspNetCore/Inc/appoffline.h new file mode 100644 index 0000000000..53c758f36a --- /dev/null +++ b/src/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 (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/AspNetCore/Inc/filewatcher.h b/src/AspNetCore/Inc/filewatcher.h index 6ae853708e..c5bff0df0d 100644 --- a/src/AspNetCore/Inc/filewatcher.h +++ b/src/AspNetCore/Inc/filewatcher.h @@ -19,7 +19,7 @@ #define FILE_WATCHER_ENTRY_SIGNATURE ((DWORD) 'FWES') #define FILE_WATCHER_ENTRY_SIGNATURE_FREE ((DWORD) 'sewf') -class APPLICATION; +class APPLICATION_INFO; class FILE_WATCHER{ public: @@ -67,7 +67,7 @@ public: Create( _In_ PCWSTR pszDirectoryToMonitor, _In_ PCWSTR pszFileNameToMonitor, - _In_ APPLICATION* pApplication, + _In_ APPLICATION_INFO* pApplicationInfo, _In_ HANDLE hImpersonationToken ); @@ -116,7 +116,7 @@ private: HANDLE _hImpersonationToken; HANDLE _hDirectory; FILE_WATCHER* _pFileMonitor; - APPLICATION* _pApplication; + APPLICATION_INFO* _pApplicationInfo; STRU _strFileName; STRU _strDirectoryName; LONG _lStopMonitorCalled; diff --git a/src/AspNetCore/Inc/forwardinghandler.h b/src/AspNetCore/Inc/forwardinghandler.h deleted file mode 100644 index 4a6ecbe451..0000000000 --- a/src/AspNetCore/Inc/forwardinghandler.h +++ /dev/null @@ -1,446 +0,0 @@ -// 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 "forwarderconnection.h" -#include "protocolconfig.h" -#include "serverprocess.h" -#include "application.h" -#include "tracelog.h" -#include "websockethandler.h" - -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; - -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, - __in APPLICATION * pApplication - ); - - 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(reinterpret_cast(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; - } - -private: - - virtual - ~FORWARDING_HANDLER( - VOID - ); - - // - // 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 - ); - - HRESULT - SetHttpSysDisconnectCallback( - VOID - ); - - DWORD m_Signature; - mutable LONG m_cRefs; - - IHttpContext * m_pW3Context; - IHttpContext * m_pChildRequestContext; - - // - // 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_fWebSocketEnabled; - bool m_fHandleClosedDueToClient; - bool m_fResponseHeadersReceivedAndSet; - BOOL m_fDoReverseRewriteHeaders; - BOOL m_fErrorHandled; - BOOL m_fWebSocketUpgrade; - BOOL m_fFinishRequest; - BOOL m_fClientDisconnected; - BOOL m_fHasError; - DWORD m_msStartTime; - DWORD m_BytesToReceive; - DWORD m_BytesToSend; - DWORD m_cchLastSend; - DWORD m_cEntityBuffers; - DWORD m_cBytesBuffered; - DWORD m_cMinBufferLimit; - - BYTE * m_pEntityBuffer; - static const SIZE_T INLINE_ENTITY_BUFFERS = 8; - BUFFER_T m_buffEntityBuffers; - - PCSTR m_pszOriginalHostHeader; - - FORWARDING_REQUEST_STATUS m_RequestStatus; - - ASYNC_DISCONNECT_CONTEXT * m_pDisconnect; - - PCWSTR m_pszHeaders; - DWORD m_cchHeaders; - - 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/AspNetCore/Inc/globalmodule.h b/src/AspNetCore/Inc/globalmodule.h new file mode 100644 index 0000000000..aca1857051 --- /dev/null +++ b/src/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/AspNetCore/Inc/inprocessstoredcontext.h b/src/AspNetCore/Inc/inprocessstoredcontext.h deleted file mode 100644 index 64244692d4..0000000000 --- a/src/AspNetCore/Inc/inprocessstoredcontext.h +++ /dev/null @@ -1,90 +0,0 @@ -// 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 IN_PROCESS_STORED_CONTEXT : public IHttpStoredContext -{ -public: - IN_PROCESS_STORED_CONTEXT( - IHttpContext* pHttpContext, - PVOID pvManagedContext - ); - - ~IN_PROCESS_STORED_CONTEXT(); - - virtual - VOID - CleanupStoredContext( - VOID - ) - { - delete this; - } - - virtual - VOID - OnClientDisconnected( - VOID - ) - { - } - - virtual - VOID - OnListenerEvicted( - VOID - ) - { - } - - PVOID - QueryManagedHttpContext( - VOID - ); - - IHttpContext* - QueryHttpContext( - VOID - ); - - BOOL - QueryIsManagedRequestComplete( - VOID - ); - - VOID - IndicateManagedRequestComplete( - VOID - ); - - REQUEST_NOTIFICATION_STATUS - QueryAsyncCompletionStatus( - VOID - ); - - VOID - SetAsyncCompletionStatus( - REQUEST_NOTIFICATION_STATUS requestNotificationStatus - ); - - static - HRESULT - GetInProcessStoredContext( - IHttpContext* pHttpContext, - IN_PROCESS_STORED_CONTEXT** ppInProcessStoredContext - ); - - static - HRESULT - SetInProcessStoredContext( - IHttpContext* pHttpContext, - IN_PROCESS_STORED_CONTEXT* pInProcessStoredContext - ); - -private: - PVOID m_pManagedHttpContext; - IHttpContext* m_pHttpContext; - BOOL m_fManagedRequestComplete; - REQUEST_NOTIFICATION_STATUS m_requestNotificationStatus; -}; - diff --git a/src/AspNetCore/Inc/outprocessapplication.h b/src/AspNetCore/Inc/outprocessapplication.h deleted file mode 100644 index 57e6022c0c..0000000000 --- a/src/AspNetCore/Inc/outprocessapplication.h +++ /dev/null @@ -1,40 +0,0 @@ -// 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 "application.h" - -class OUT_OF_PROCESS_APPLICATION : public APPLICATION -{ -public: - OUT_OF_PROCESS_APPLICATION(); - - ~OUT_OF_PROCESS_APPLICATION(); - - __override - HRESULT Initialize(_In_ APPLICATION_MANAGER* pApplicationManager, - _In_ ASPNETCORE_CONFIG* pConfiguration); - - __override - VOID OnAppOfflineHandleChange(); - - __override - REQUEST_NOTIFICATION_STATUS - ExecuteRequest( - _In_ IHttpContext* pHttpContext - ); - - HRESULT - GetProcess( - _In_ IHttpContext *context, - _Out_ SERVER_PROCESS **ppServerProcess - ) - { - return m_pProcessManager->GetProcess(context, m_pConfiguration, ppServerProcess); - } - -private: - - PROCESS_MANAGER* m_pProcessManager; -}; diff --git a/src/AspNetCore/Inc/proxymodule.h b/src/AspNetCore/Inc/proxymodule.h index f05438c5c1..7e5f30a8eb 100644 --- a/src/AspNetCore/Inc/proxymodule.h +++ b/src/AspNetCore/Inc/proxymodule.h @@ -1,18 +1,19 @@ - // 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 "forwardinghandler.h" +extern HTTP_MODULE_ID g_pModuleId; +extern IHttpServer *g_pHttpServer; +extern HMODULE g_hAspnetCoreRH; -class CProxyModule : public CHttpModule +class ASPNET_CORE_PROXY_MODULE : public CHttpModule { public: - CProxyModule(); + ASPNET_CORE_PROXY_MODULE(); - ~CProxyModule(); + ~ASPNET_CORE_PROXY_MODULE(); void * operator new(size_t size, IModuleAllocator * pPlacement) { @@ -44,10 +45,12 @@ class CProxyModule : public CHttpModule private: - FORWARDING_HANDLER * m_pHandler; + APPLICATION_INFO *m_pApplicationInfo; + APPLICATION *m_pApplication; + REQUEST_HANDLER *m_pHandler; }; -class CProxyModuleFactory : public IHttpModuleFactory +class ASPNET_CORE_PROXY_MODULE_FACTORY : public IHttpModuleFactory { public: HRESULT diff --git a/src/AspNetCore/Inc/resource.h b/src/AspNetCore/Inc/resource.h index be91685c10..45cd8f1ef5 100644 --- a/src/AspNetCore/Inc/resource.h +++ b/src/AspNetCore/Inc/resource.h @@ -6,6 +6,7 @@ #define IDS_INVALID_PROPERTY 1000 #define IDS_SERVER_ERROR 1001 +// TODO remove this file? #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." diff --git a/src/AspNetCore/Src/application.cxx b/src/AspNetCore/Src/application.cxx deleted file mode 100644 index 2bd5b688b8..0000000000 --- a/src/AspNetCore/Src/application.cxx +++ /dev/null @@ -1,78 +0,0 @@ -// 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::~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; - } -} - -HRESULT -APPLICATION::StartMonitoringAppOffline() -{ - HRESULT hr = S_OK; - if (m_pFileWatcherEntry != NULL) - { - hr = m_pFileWatcherEntry->Create(m_pConfiguration->QueryApplicationFullPath()->QueryStr(), L"app_offline.htm", this, NULL); - } - return hr; -} - -VOID -APPLICATION::UpdateAppOfflineFileHandle() -{ - STRU strFilePath; - PATH::ConvertPathToFullPath(L".\\app_offline.htm", m_pConfiguration->QueryApplicationFullPath()->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; - 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; - } - } - - OnAppOfflineHandleChange(); - } -} \ No newline at end of file diff --git a/src/AspNetCore/Src/applicationinfo.cpp b/src/AspNetCore/Src/applicationinfo.cpp new file mode 100644 index 0000000000..e63e633a93 --- /dev/null +++ b/src/AspNetCore/Src/applicationinfo.cpp @@ -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. + +#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 = 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; +} + +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; + + if (INVALID_FILE_ATTRIBUTES == GetFileAttributes(strFilePath.QueryStr()) && + GetLastError() == ERROR_FILE_NOT_FOUND) + { + m_fAppOfflineFound = FALSE; + } + else + { + m_fAppOfflineFound = TRUE; + 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; + } + } + + // recycle the application + if (m_pApplication != NULL) + { + m_pApplication->ShutDown(); + m_pApplication->DereferenceApplication(); + m_pApplication = NULL; + } + } +} + +HRESULT +APPLICATION_INFO::EnsureApplicationCreated() +{ + HRESULT hr = S_OK; + BOOL fLocked = FALSE; + APPLICATION* pApplication = NULL; + STACK_STRU(struFileName, 300); // >MAX_PATH + STRU hostFxrDllLocation; + + if (m_pApplication != NULL) + { + goto Finished; + } + + hr = FindRequestHandlerAssembly(); + if (FAILED(hr)) + { + goto Finished; + } + + if (m_pApplication == NULL) + { + AcquireSRWLockExclusive(&m_srwLock); + fLocked = TRUE; + if (m_pApplication != NULL) + { + 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; + } + + // load assembly and create the application + if (m_pConfiguration->QueryHostingModel() == APP_HOSTING_MODEL::HOSTING_IN_PROCESS) + { + // Look at inetsvr only for now. TODO add in functionality + hr = FindNativeAssemblyFromGlobalLocation(&struFileName); + + if (FAILED(hr)) + { + goto Finished; + } + } + else + { + hr = FindNativeAssemblyFromGlobalLocation(&struFileName); + if (FAILED(hr)) + { + 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 + while (!fDone) + { + DWORD dwReturnedSize = GetModuleFileName(NULL, 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 + struFilename->Resize(dwSize + 20); // aspnetcorerh.dll + } + 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(g_pwzAspnetcoreRequestHandlerName))) + { + goto Finished; + } + +Finished: + return hr; +} diff --git a/src/AspNetCore/Src/applicationmanager.cxx b/src/AspNetCore/Src/applicationmanager.cxx index f2640a55a5..094f1d5e1c 100644 --- a/src/AspNetCore/Src/applicationmanager.cxx +++ b/src/AspNetCore/Src/applicationmanager.cxx @@ -6,28 +6,28 @@ APPLICATION_MANAGER* APPLICATION_MANAGER::sm_pApplicationManager = NULL; HRESULT -APPLICATION_MANAGER::GetApplication( - _In_ IHttpContext* pContext, +APPLICATION_MANAGER::GetApplicationInfo( + _In_ IHttpServer* pServer, _In_ ASPNETCORE_CONFIG* pConfig, - _Out_ APPLICATION ** ppApplication + _Out_ APPLICATION_INFO ** ppApplicationInfo ) { - HRESULT hr = S_OK; - APPLICATION *pApplication = NULL; - APPLICATION_KEY key; - BOOL fExclusiveLock = FALSE; - BOOL fMixedHostingModelError = FALSE; - BOOL fDuplicatedInProcessApp = FALSE; - PCWSTR pszApplicationId = NULL; - LPCWSTR apsz[1]; + HRESULT hr = S_OK; + APPLICATION_INFO *pApplicationInfo = NULL; + APPLICATION_INFO_KEY key; + BOOL fExclusiveLock = FALSE; + BOOL fMixedHostingModelError = FALSE; + BOOL fDuplicatedInProcessApp = FALSE; + PCWSTR pszApplicationId = NULL; + LPCWSTR apsz[1]; STACK_STRU ( strEventMsg, 256 ); - *ppApplication = NULL; - - DBG_ASSERT(pContext != NULL); - DBG_ASSERT(pContext->GetApplication() != NULL); + *ppApplicationInfo = NULL; - pszApplicationId = pContext->GetApplication()->GetApplicationId(); + DBG_ASSERT(pServer != NULL); + DBG_ASSERT(pConfig != NULL); + + pszApplicationId = pConfig->QueryConfigPath()->QueryStr(); hr = key.Initialize(pszApplicationId); if (FAILED(hr)) @@ -35,33 +35,39 @@ APPLICATION_MANAGER::GetApplication( goto Finished; } - m_pApplicationHash->FindKey(&key, ppApplication); + AcquireSRWLockShared(&m_srwLock); + if (m_fInShutdown) + { + ReleaseSRWLockShared(&m_srwLock); + hr = HRESULT_FROM_WIN32(ERROR_SERVER_SHUTDOWN_IN_PROGRESS); + goto Finished; + } + m_pApplicationInfoHash->FindKey(&key, ppApplicationInfo); + ReleaseSRWLockShared(&m_srwLock); - if (*ppApplication == NULL) + if (*ppApplicationInfo == NULL) { switch (pConfig->QueryHostingModel()) { case HOSTING_IN_PROCESS: - if (m_pApplicationHash->Count() > 0) + 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; } - pApplication = new IN_PROCESS_APPLICATION(); break; case HOSTING_OUT_PROCESS: - pApplication = new OUT_OF_PROCESS_APPLICATION(); break; default: hr = E_UNEXPECTED; goto Finished; } - - if (pApplication == NULL) + pApplicationInfo = new APPLICATION_INFO(pServer); + if (pApplicationInfo == NULL) { hr = E_OUTOFMEMORY; goto Finished; @@ -69,13 +75,19 @@ APPLICATION_MANAGER::GetApplication( AcquireSRWLockExclusive(&m_srwLock); fExclusiveLock = TRUE; - m_pApplicationHash->FindKey(&key, ppApplication); + if (m_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 (*ppApplication != NULL) + if (*ppApplicationInfo != NULL) { // someone else created the application - delete pApplication; - pApplication = NULL; + delete pApplicationInfo; + pApplicationInfo = NULL; goto Finished; } @@ -92,13 +104,13 @@ APPLICATION_MANAGER::GetApplication( } } - hr = pApplication->Initialize(this, pConfig); + hr = pApplicationInfo->Initialize(pConfig, m_pFileWatcher); if (FAILED(hr)) { goto Finished; } - hr = m_pApplicationHash->InsertRecord( pApplication ); + hr = m_pApplicationInfoHash->InsertRecord( pApplicationInfo ); if (FAILED(hr)) { goto Finished; @@ -112,13 +124,12 @@ APPLICATION_MANAGER::GetApplication( m_hostingModel = pConfig->QueryHostingModel(); } + *ppApplicationInfo = pApplicationInfo; ReleaseSRWLockExclusive(&m_srwLock); fExclusiveLock = FALSE; - pApplication->StartMonitoringAppOffline(); - - *ppApplication = pApplication; - pApplication = NULL; + pApplicationInfo->StartMonitoringAppOffline(); + pApplicationInfo = NULL; } Finished: @@ -128,21 +139,21 @@ Finished: ReleaseSRWLockExclusive(&m_srwLock); } + if (pApplicationInfo != NULL) + { + pApplicationInfo->DereferenceApplicationInfo(); + pApplicationInfo = NULL; + } + if (FAILED(hr)) { - if (pApplication != NULL) - { - pApplication->DereferenceApplication(); - pApplication = NULL; - } - if (fDuplicatedInProcessApp) { if (SUCCEEDED(strEventMsg.SafeSnwprintf( ASPNETCORE_EVENT_DUPLICATED_INPROCESS_APP_MSG, pszApplicationId))) { - apsz[0] = strEventMsg.QueryStr(); + /*apsz[0] = strEventMsg.QueryStr(); if (FORWARDING_HANDLER::QueryEventLog() != NULL) { ReportEventW(FORWARDING_HANDLER::QueryEventLog(), @@ -154,30 +165,30 @@ Finished: 0, apsz, NULL); - } + }*/ } } else if (fMixedHostingModelError) { - if (SUCCEEDED(strEventMsg.SafeSnwprintf( - ASPNETCORE_EVENT_MIXED_HOSTING_MODEL_ERROR_MSG, - pszApplicationId, - pConfig->QueryHostingModelStr()))) - { - apsz[0] = strEventMsg.QueryStr(); - if (FORWARDING_HANDLER::QueryEventLog() != NULL) - { - ReportEventW(FORWARDING_HANDLER::QueryEventLog(), - EVENTLOG_ERROR_TYPE, - 0, - ASPNETCORE_EVENT_MIXED_HOSTING_MODEL_ERROR, - NULL, - 1, - 0, - apsz, - NULL); - } - } + //if (SUCCEEDED(strEventMsg.SafeSnwprintf( + // ASPNETCORE_EVENT_MIXED_HOSTING_MODEL_ERROR_MSG, + // pszApplicationId, + // pConfig->QueryHostingModelStr()))) + //{ + // apsz[0] = strEventMsg.QueryStr(); + // /*if (FORWARDING_HANDLER::QueryEventLog() != NULL) + // { + // ReportEventW(FORWARDING_HANDLER::QueryEventLog(), + // EVENTLOG_ERROR_TYPE, + // 0, + // ASPNETCORE_EVENT_MIXED_HOSTING_MODEL_ERROR, + // NULL, + // 1, + // 0, + // apsz, + // NULL); + // }*/ + //} } else { @@ -187,7 +198,7 @@ Finished: hr))) { apsz[0] = strEventMsg.QueryStr(); - if (FORWARDING_HANDLER::QueryEventLog() != NULL) + /*if (FORWARDING_HANDLER::QueryEventLog() != NULL) { ReportEventW(FORWARDING_HANDLER::QueryEventLog(), EVENTLOG_ERROR_TYPE, @@ -198,7 +209,7 @@ Finished: 0, apsz, NULL); - } + }*/ } } } @@ -208,23 +219,33 @@ Finished: HRESULT APPLICATION_MANAGER::RecycleApplication( - _In_ LPCWSTR pszApplication + _In_ LPCWSTR pszApplicationId ) { HRESULT hr = S_OK; - APPLICATION_KEY key; + APPLICATION_INFO_KEY key; - hr = key.Initialize(pszApplication); + hr = key.Initialize(pszApplicationId); if (FAILED(hr)) { goto Finished; } AcquireSRWLockExclusive(&m_srwLock); - m_pApplicationHash->DeleteKey(&key); - if (m_pApplicationHash->Count() == 0) + m_pApplicationInfoHash->DeleteKey(&key); + + if (m_pApplicationInfoHash->Count() == 0) { m_hostingModel = HOSTING_UNKNOWN; } + + if (g_fAspnetcoreRHLoadedError) + { + // We had assembly loading failure + // this error blocked the start of all applications + // Let's recycle the worker process if user redeployed any application + g_pHttpServer->RecycleProcess(L"AspNetCore Recycle Process on Demand due to assembly loading failure"); + } + ReleaseSRWLockExclusive(&m_srwLock); Finished: @@ -232,65 +253,17 @@ Finished: return hr; } -HRESULT -APPLICATION_MANAGER::Get502ErrorPage( - _Out_ HTTP_DATA_CHUNK** ppErrorPage -) +VOID +APPLICATION_MANAGER::ShutDown() { - 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 + m_fInShutdown = TRUE; + if (m_pApplicationInfoHash != NULL) { 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) - { + // clean up the hash table so that the application will be informed on shutdown + m_pApplicationInfoHash->Clear(); ReleaseSRWLockExclusive(&m_srwLock); } - if (FAILED(hr)) - { - if (pHttp502ErrorPage != NULL) - { - delete pHttp502ErrorPage; - } - } - - return hr; -} \ No newline at end of file +} diff --git a/src/AspNetCore/Src/dllmain.cpp b/src/AspNetCore/Src/dllmain.cpp index e25cc49623..d61a729361 100644 --- a/src/AspNetCore/Src/dllmain.cpp +++ b/src/AspNetCore/Src/dllmain.cpp @@ -6,35 +6,42 @@ HTTP_MODULE_ID g_pModuleId = NULL; IHttpServer * g_pHttpServer = NULL; -BOOL g_fAsyncDisconnectAvailable = FALSE; -BOOL g_fWinHttpNonBlockingCallbackAvailable = FALSE; BOOL g_fRecycleProcessCalled = 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; +HMODULE g_hAspnetCoreRH = NULL; +BOOL g_fAspnetcoreRHAssemblyLoaded = FALSE; +BOOL g_fAspnetcoreRHLoadedError = 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. - +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(); +} 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: + StaticCleanup(); default: break; } @@ -42,75 +49,6 @@ BOOL WINAPI DllMain(HMODULE hModule, 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( @@ -138,8 +76,14 @@ HRESULT --*/ { - HRESULT hr = S_OK; - CProxyModuleFactory * pFactory = NULL; + 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"); @@ -148,63 +92,50 @@ HRESULT CREATE_DEBUG_PRINT_OBJECT; - LoadGlobalConfiguration(); + //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; - } - } + InitializeSRWLock(&g_srwLock); g_pModuleId = pModuleInfo->GetId(); g_pszModuleName = pModuleInfo->GetName(); g_pHttpServer = pHttpServer; - g_hWinHttpModule = GetModuleHandle(TEXT("winhttp.dll")); - // - // 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)); + // 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); + } + } + + if (fDisableANCM) + { + // Logging + goto Finished; + } // // Create the factory before any static initialization. - // The CProxyModuleFactory::Terminate method will clean any + // The ASPNET_CORE_PROXY_MODULE_FACTORY::Terminate method will clean any // static object initialized. // - pFactory = new CProxyModuleFactory; + pFactory = new ASPNET_CORE_PROXY_MODULE_FACTORY; if (pFactory == NULL) { @@ -213,28 +144,45 @@ HRESULT } hr = pModuleInfo->SetRequestNotifications( - pFactory, - RQ_EXECUTE_REQUEST_HANDLER, - 0); + 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; - g_pResponseHeaderHash = new RESPONSE_HEADER_HASH; - if (g_pResponseHeaderHash == NULL) + pGlobalModule = new ASPNET_CORE_GLOBAL_MODULE(pApplicationManager); + if (pGlobalModule == NULL) { hr = E_OUTOFMEMORY; goto Finished; } - hr = g_pResponseHeaderHash->Initialize(); + hr = pModuleInfo->SetGlobalNotifications( + pGlobalModule, + GL_CONFIGURATION_CHANGE | GL_STOP_LISTENING); + if (FAILED(hr)) { goto Finished; } + pGlobalModule = NULL; hr = ALLOC_CACHE_HANDLER::StaticInitialize(); if (FAILED(hr)) @@ -242,19 +190,12 @@ HRESULT 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 (pGlobalModule != NULL) + { + delete pGlobalModule; + pGlobalModule = NULL; + } if (pFactory != NULL) { diff --git a/src/AspNetCore/Src/filewatcher.cxx b/src/AspNetCore/Src/filewatcher.cxx index 9bd5d6c2da..0765b1c39e 100644 --- a/src/AspNetCore/Src/filewatcher.cxx +++ b/src/AspNetCore/Src/filewatcher.cxx @@ -13,9 +13,17 @@ FILE_WATCHER::~FILE_WATCHER() { if (m_hChangeNotificationThread != NULL) { + PostQueuedCompletionStatus(m_hCompletionPort, 0, FILE_WATCHER_SHUTDOWN_KEY, NULL); + WaitForSingleObject(m_hChangeNotificationThread, INFINITE); CloseHandle(m_hChangeNotificationThread); m_hChangeNotificationThread = NULL; } + + if (NULL != m_hCompletionPort) + { + CloseHandle(m_hCompletionPort); + m_hCompletionPort = NULL; + } } HRESULT @@ -97,13 +105,13 @@ Win32 error &pOverlapped, INFINITE); - DBG_ASSERT(fSuccess); + DBG_ASSERT(fSuccess); DebugPrint(1, "FILE_WATCHER::ChangeNotificationThread"); dwErrorStatus = fSuccess ? ERROR_SUCCESS : GetLastError(); if (completionKey == FILE_WATCHER_SHUTDOWN_KEY) { - continue; + break; } DBG_ASSERT(pOverlapped != NULL); @@ -117,6 +125,8 @@ Win32 error pOverlapped = NULL; cbCompletion = 0; } + + return 0; } VOID @@ -173,7 +183,7 @@ FILE_WATCHER_ENTRY::FILE_WATCHER_ENTRY(FILE_WATCHER * pFileMonitor) : _pFileMonitor(pFileMonitor), _hDirectory(INVALID_HANDLE_VALUE), _hImpersonationToken(NULL), - _pApplication(NULL), + _pApplicationInfo(NULL), _lStopMonitorCalled(0), _cRefs(1), _fIsValid(TRUE) @@ -253,7 +263,7 @@ HRESULT // Othersie we have to cache the file info // if (cbCompletion == 0) - { + { fFileChanged = TRUE; } else @@ -266,9 +276,9 @@ HRESULT // // check whether the monitored file got changed // - if (_wcsnicmp(pNotificationInfo->FileName, - _strFileName.QueryStr(), - pNotificationInfo->FileNameLength/sizeof(WCHAR)) == 0) + if (_wcsnicmp(pNotificationInfo->FileName, + _strFileName.QueryStr(), + pNotificationInfo->FileNameLength / sizeof(WCHAR)) == 0) { fFileChanged = TRUE; break; @@ -284,7 +294,7 @@ HRESULT { pNotificationInfo = (FILE_NOTIFY_INFORMATION*) ((PBYTE)pNotificationInfo + - pNotificationInfo->NextEntryOffset); + pNotificationInfo->NextEntryOffset); } } } @@ -294,7 +304,7 @@ HRESULT // // so far we only monitoring app_offline // - _pApplication->UpdateAppOfflineFileHandle(); + _pApplicationInfo->UpdateAppOfflineFileHandle(); } Finished: @@ -314,7 +324,7 @@ FILE_WATCHER_ENTRY::Monitor(VOID) ReferenceFileWatcherEntry(); ZeroMemory(&_overlapped, sizeof(_overlapped)); - if(!ReadDirectoryChangesW(_hDirectory, + if (!ReadDirectoryChangesW(_hDirectory, _buffDirectoryChanges.QueryPtr(), _buffDirectoryChanges.QuerySize(), FALSE, // Watching sub dirs. Set to False now as only monitoring app_offline @@ -355,7 +365,7 @@ HRESULT FILE_WATCHER_ENTRY::Create( _In_ PCWSTR pszDirectoryToMonitor, _In_ PCWSTR pszFileNameToMonitor, - _In_ APPLICATION* pApplication, + _In_ APPLICATION_INFO* pApplicationInfo, _In_ HANDLE hImpersonationToken ) { @@ -364,7 +374,7 @@ FILE_WATCHER_ENTRY::Create( if (pszDirectoryToMonitor == NULL || pszFileNameToMonitor == NULL || - pApplication == NULL) + pApplicationInfo == NULL) { DBG_ASSERT(FALSE); hr = HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER); @@ -374,7 +384,7 @@ FILE_WATCHER_ENTRY::Create( // //remember the application // - _pApplication = pApplication; + _pApplicationInfo = pApplicationInfo; if (FAILED(hr = _strFileName.Copy(pszFileNameToMonitor))) { diff --git a/src/AspNetCore/Src/fx_ver.cxx b/src/AspNetCore/Src/fx_ver.cxx deleted file mode 100644 index 1c844d3113..0000000000 --- a/src/AspNetCore/Src/fx_ver.cxx +++ /dev/null @@ -1,195 +0,0 @@ -// 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 -#include -#include "fx_ver.h" -#include "precomp.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/AspNetCore/Src/globalmodule.cpp b/src/AspNetCore/Src/globalmodule.cpp new file mode 100644 index 0000000000..fc0ba3c6ea --- /dev/null +++ b/src/AspNetCore/Src/globalmodule.cpp @@ -0,0 +1,59 @@ +#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 (m_pApplicationManager != NULL) + { + // we should let application manager to shudown 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 +) +{ + UNREFERENCED_PARAMETER(pProvider); + + // 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->RecycleApplication(pwszChangePath); + } + } + + // Return processing to the pipeline. + return GL_NOTIFICATION_CONTINUE; +} \ No newline at end of file diff --git a/src/AspNetCore/Src/inprocessapplication.cxx b/src/AspNetCore/Src/inprocessapplication.cxx deleted file mode 100644 index 73430009e7..0000000000 --- a/src/AspNetCore/Src/inprocessapplication.cxx +++ /dev/null @@ -1,686 +0,0 @@ -// 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" -#include - -typedef DWORD(*hostfxr_main_fn) (CONST DWORD argc, CONST WCHAR* argv[]); - -IN_PROCESS_APPLICATION* IN_PROCESS_APPLICATION::s_Application = NULL; - -IN_PROCESS_APPLICATION::IN_PROCESS_APPLICATION() : - m_ProcessExitCode ( 0 ), - m_fManagedAppLoaded ( FALSE ), - m_fLoadManagedAppError ( FALSE ), - m_fInitialized ( FALSE ) -{ -} - -IN_PROCESS_APPLICATION::~IN_PROCESS_APPLICATION() -{ - Recycle(); -} - -REQUEST_NOTIFICATION_STATUS -IN_PROCESS_APPLICATION::OnAsyncCompletion( - IHttpContext* pHttpContext, - DWORD cbCompletion, - HRESULT hrCompletionStatus -) -{ - HRESULT hr; - IN_PROCESS_STORED_CONTEXT* pInProcessStoredContext = NULL; - REQUEST_NOTIFICATION_STATUS dwRequestNotificationStatus = RQ_NOTIFICATION_CONTINUE; - - hr = IN_PROCESS_STORED_CONTEXT::GetInProcessStoredContext(pHttpContext, &pInProcessStoredContext); - if (FAILED(hr)) - { - // Finish the request as we couldn't get the callback - pHttpContext->GetResponse()->SetStatus(500, "Internal Server Error", 19, hr); - return RQ_NOTIFICATION_FINISH_REQUEST; - } - else if (pInProcessStoredContext->QueryIsManagedRequestComplete()) - { - // means PostCompletion has been called and this is the associated callback. - dwRequestNotificationStatus = pInProcessStoredContext->QueryAsyncCompletionStatus(); - // TODO cleanup whatever disconnect listener there is - return dwRequestNotificationStatus; - } - else - { - // Call the managed handler for async completion. - return m_AsyncCompletionHandler(pInProcessStoredContext->QueryManagedHttpContext(), hrCompletionStatus, cbCompletion); - } -} - -BOOL -IN_PROCESS_APPLICATION::DirectoryExists( - _In_ STRU *pstrPath -) -{ - WIN32_FILE_ATTRIBUTE_DATA data; - - if (pstrPath->IsEmpty()) - { - return false; - } - - return GetFileAttributesExW(pstrPath->QueryStr(), GetFileExInfoStandard, &data); -} - -BOOL -IN_PROCESS_APPLICATION::GetEnv( - _In_ PCWSTR pszEnvironmentVariable, - _Out_ STRU *pstrResult -) -{ - DWORD dwLength; - PWSTR pszBuffer = NULL; - BOOL fSucceeded = FALSE; - - if (pszEnvironmentVariable == NULL) - { - goto Finished; - } - pstrResult->Reset(); - dwLength = GetEnvironmentVariableW(pszEnvironmentVariable, NULL, 0); - - if (dwLength == 0) - { - goto Finished; - } - - pszBuffer = new WCHAR[dwLength]; - if (GetEnvironmentVariableW(pszEnvironmentVariable, pszBuffer, dwLength) == 0) - { - goto Finished; - } - - pstrResult->Copy(pszBuffer); - - fSucceeded = TRUE; - -Finished: - if (pszBuffer != NULL) { - delete[] pszBuffer; - } - return fSucceeded; -} - -VOID -IN_PROCESS_APPLICATION::FindDotNetFolders( - _In_ PCWSTR pszPath, - _Out_ std::vector *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); -} - -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_RequstHandlerContext = pvRequstHandlerContext; - m_ShutdownHandler = shutdown_handler; - m_ShutdownHandlerContext = pvShutdownHandlerContext; - m_AsyncCompletionHandler = async_completion_handler; - - // Initialization complete - SetEvent(m_pInitalizeEvent); -} - -// -// Initialize is guarded by a lock inside APPLICATION_MANAGER::GetApplication -// It ensures only one application will be initialized and singleton -// Error wuill happen if you call Initialized outside APPLICATION_MANAGER::GetApplication -// -__override -HRESULT -IN_PROCESS_APPLICATION::Initialize( - _In_ APPLICATION_MANAGER* pApplicationManager, - _In_ ASPNETCORE_CONFIG* pConfiguration -) -{ - HRESULT hr = S_OK; - DBG_ASSERT(pApplicationManager != NULL); - DBG_ASSERT(pConfiguration != NULL); - - m_pConfiguration = pConfiguration; - m_pApplicationManager = pApplicationManager; - hr = m_applicationKey.Initialize(pConfiguration->QueryApplicationPath()->QueryStr()); - if (FAILED(hr)) - { - goto Finished; - } - - // check app_offline - UpdateAppOfflineFileHandle(); - - if (m_pFileWatcherEntry == NULL) - { - m_pFileWatcherEntry = new FILE_WATCHER_ENTRY(m_pApplicationManager->GetFileWatcher()); - if (m_pFileWatcherEntry == NULL) - { - hr = E_OUTOFMEMORY; - 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()); - goto Finished; - } - m_fInitialized = TRUE; - -Finished: - return hr; -} - -HRESULT -IN_PROCESS_APPLICATION::LoadManagedApplication() -{ - HRESULT hr = S_OK; - DWORD dwTimeout; - DWORD dwResult; - BOOL fLocked = FALSE; - PCWSTR apsz[1]; - STACK_STRU(strEventMsg, 256); - - if (m_fManagedAppLoaded || m_fLoadManagedAppError) - { - // Core CLR has already been loaded. - // Cannot load more than once even there was a failure - goto Finished; - } - - AcquireSRWLockExclusive(&m_srwLock); - fLocked = TRUE; - if (m_fManagedAppLoaded || m_fLoadManagedAppError) - { - 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; - } - - // If the debugger is attached, never timeout - if (IsDebuggerPresent()) - { - dwTimeout = INFINITE; - } - else - { - dwTimeout = m_pConfiguration->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) - { - // do we need kill the backend thread - 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_fManagedAppLoaded = TRUE; - -Finished: - if (fLocked) - { - ReleaseSRWLockExclusive(&m_srwLock); - } - - if (FAILED(hr)) - { - // Question: in case of application loading failure, should we allow retry on - // following request or block the activation at all - m_fLoadManagedAppError = FALSE; // m_hThread != NULL ? - - if (SUCCEEDED(strEventMsg.SafeSnwprintf( - ASPNETCORE_EVENT_LOAD_CLR_FALIURE_MSG, - m_pConfiguration->QueryApplicationPath()->QueryStr(), - m_pConfiguration->QueryApplicationFullPath()->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_LOAD_CLR_FALIURE, - NULL, - 1, - 0, - apsz, - NULL); - } - } - } - return hr; -} - -VOID -IN_PROCESS_APPLICATION::Recycle( - VOID -) -{ - if (m_fInitialized) - { - DWORD dwThreadStatus = 0; - DWORD dwTimeout = m_pConfiguration->QueryShutdownTimeLimitInMS(); - - AcquireSRWLockExclusive(&m_srwLock); - - if (!g_pHttpServer->IsCommandLineLaunch() && - !g_fRecycleProcessCalled && - (g_pHttpServer->GetAdminManager() != NULL)) - { - // IIS scenario. - // notify IIS first so that new request will be routed to new worker process - g_pHttpServer->RecycleProcess(L"AspNetCore Recycle Process on Demand"); - } - - g_fRecycleProcessCalled = TRUE; - - // First call into the managed server and shutdown - if (m_ShutdownHandler != NULL) - { - m_ShutdownHandler(m_ShutdownHandlerContext); - m_ShutdownHandler = NULL; - } - - if (m_hThread != NULL && - GetExitCodeThread(m_hThread, &dwThreadStatus) != 0 && - dwThreadStatus == STILL_ACTIVE) - { - // wait for gracefullshut down, 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) - { - TerminateThread(m_hThread, STATUS_CONTROL_C_EXIT); - } - } - } - - CloseHandle(m_hThread); - m_hThread = NULL; - s_Application = NULL; - - ReleaseSRWLockExclusive(&m_srwLock); - if (g_pHttpServer && g_pHttpServer->IsCommandLineLaunch()) - { - // IISExpress scenario - // Can only call exit to terminate current process - exit(0); - } - } -} - -VOID -IN_PROCESS_APPLICATION::OnAppOfflineHandleChange() -{ - // only recycle the worker process after managed app was loaded - // app_offline scenario managed application has not been loaded yet - if (m_fManagedAppLoaded || m_fLoadManagedAppError) - { - Recycle(); - - } -} - -REQUEST_NOTIFICATION_STATUS -IN_PROCESS_APPLICATION::ExecuteRequest( - _In_ IHttpContext* pHttpContext -) -{ - if (m_RequestHandler != NULL) - { - return m_RequestHandler(pHttpContext, m_RequstHandlerContext); - } - - // - // 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, - E_APPLICATION_ACTIVATION_EXEC_FAILURE); - } - pHttpContext->GetResponse()->SetStatus(500, "Internal Server Error", 0, E_APPLICATION_ACTIVATION_EXEC_FAILURE); - return RQ_NOTIFICATION_FINISH_REQUEST; -} - -HRESULT -IN_PROCESS_APPLICATION::ExecuteApplication( - VOID -) -{ - HRESULT hr = S_OK; - - STRU strFullPath; - STRU strDotnetExeLocation; - STRU strHostFxrSearchExpression; - STRU strDotnetFolderLocation; - STRU strHighestDotnetVersion; - STRU strApplicationFullPath; - PWSTR strDelimeterContext = NULL; - PCWSTR pszDotnetExeLocation = NULL; - PCWSTR pszDotnetExeString(L"dotnet.exe"); - DWORD dwCopyLength; - HMODULE hModule; - PCWSTR argv[2]; - hostfxr_main_fn pProc; - std::vector vVersionFolders; - bool fFound = FALSE; - - // Get the System PATH value. - if (!GetEnv(L"PATH", &strFullPath)) - { - hr = ERROR_BAD_ENVIRONMENT; - goto Finished; - } - - // Split on ';', checking to see if dotnet.exe exists in any folders. - pszDotnetExeLocation = wcstok_s(strFullPath.QueryStr(), L";", &strDelimeterContext); - - while (pszDotnetExeLocation != NULL) - { - dwCopyLength = wcsnlen_s(pszDotnetExeLocation, 260); - if (dwCopyLength == 0) - { - continue; - } - - // We store both the exe and folder locations as we eventually need to check inside of host\\fxr - // which doesn't need the dotnet.exe portion of the string - // TODO consider reducing allocations. - strDotnetExeLocation.Reset(); - strDotnetFolderLocation.Reset(); - hr = strDotnetExeLocation.Copy(pszDotnetExeLocation, dwCopyLength); - if (FAILED(hr)) - { - goto Finished; - } - - hr = strDotnetFolderLocation.Copy(pszDotnetExeLocation, dwCopyLength); - if (FAILED(hr)) - { - goto Finished; - } - - if (dwCopyLength > 0 && pszDotnetExeLocation[dwCopyLength - 1] != L'\\') - { - hr = strDotnetExeLocation.Append(L"\\"); - if (FAILED(hr)) - { - goto Finished; - } - } - - hr = strDotnetExeLocation.Append(pszDotnetExeString); - if (FAILED(hr)) - { - goto Finished; - } - - if (PathFileExists(strDotnetExeLocation.QueryStr())) - { - // means we found the folder with a dotnet.exe inside of it. - fFound = TRUE; - break; - } - pszDotnetExeLocation = wcstok_s(NULL, L";", &strDelimeterContext); - } - if (!fFound) - { - // could not find dotnet.exe, error out - hr = ERROR_BAD_ENVIRONMENT; - } - - hr = strDotnetFolderLocation.Append(L"\\host\\fxr"); - if (FAILED(hr)) - { - goto Finished; - } - - if (!DirectoryExists(&strDotnetFolderLocation)) - { - // error, not found the folder - hr = ERROR_BAD_ENVIRONMENT; - goto Finished; - } - - // Find all folders under host\\fxr\\ for version numbers. - hr = strHostFxrSearchExpression.Copy(strDotnetFolderLocation); - if (FAILED(hr)) - { - goto Finished; - } - - hr = strHostFxrSearchExpression.Append(L"\\*"); - if (FAILED(hr)) - { - goto Finished; - } - - // As we use the logic from core-setup, we are opting to use std here. - // TODO remove all uses of std? - FindDotNetFolders(strHostFxrSearchExpression.QueryStr(), &vVersionFolders); - - if (vVersionFolders.size() == 0) - { - // no core framework was found - hr = ERROR_BAD_ENVIRONMENT; - goto Finished; - } - - hr = FindHighestDotNetVersion(vVersionFolders, &strHighestDotnetVersion); - if (FAILED(hr)) - { - goto Finished; - } - hr = strDotnetFolderLocation.Append(L"\\"); - if (FAILED(hr)) - { - goto Finished; - } - - hr = strDotnetFolderLocation.Append(strHighestDotnetVersion.QueryStr()); - if (FAILED(hr)) - { - goto Finished; - - } - - hr = strDotnetFolderLocation.Append(L"\\hostfxr.dll"); - if (FAILED(hr)) - { - goto Finished; - } - - hModule = LoadLibraryW(strDotnetFolderLocation.QueryStr()); - - 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; // better hrresult? - goto Finished; - } - - // The first argument is mostly ignored - argv[0] = strDotnetExeLocation.QueryStr(); - PATH::ConvertPathToFullPath(m_pConfiguration->QueryArguments()->QueryStr(), - m_pConfiguration->QueryApplicationFullPath()->QueryStr(), - &strApplicationFullPath); - argv[1] = strApplicationFullPath.QueryStr(); - - // 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; - - m_ProcessExitCode = pProc(2, argv); - if (m_ProcessExitCode != 0) - { - - } - -Finished: - // - // this method is called by the background thread and should never exit unless shutdown - // - if (!g_fRecycleProcessCalled) - { - STRU strEventMsg; - LPCWSTR apsz[1]; - if (SUCCEEDED(strEventMsg.SafeSnwprintf( - ASPNETCORE_EVENT_INPROCESS_THREAD_EXIT_MSG, - m_pConfiguration->QueryApplicationPath()->QueryStr(), - m_pConfiguration->QueryApplicationFullPath()->QueryStr(), - m_ProcessExitCode - ))) - { - 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_INPROCESS_THREAD_EXIT, - NULL, - 1, - 0, - apsz, - NULL); - } - // error. the thread exits after application started - // Question: should we shutdown current worker process or keep the application in failure state? - // for now, we reccylce to keep the same behavior as that of out-of-process - if (m_fManagedAppLoaded) - { - Recycle(); - } - } - } - return hr; -} - - -// static -VOID -IN_PROCESS_APPLICATION::ExecuteAspNetCoreProcess( - _In_ LPVOID pContext -) -{ - - IN_PROCESS_APPLICATION *pApplication = (IN_PROCESS_APPLICATION*)pContext; - DBG_ASSERT(pApplication != NULL); - 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::FindHighestDotNetVersion( - _In_ std::vector 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)) - { - max_ver = std::max(max_ver, fx_ver); - } - } - - hr = pstrResult->Copy(max_ver.as_str().c_str()); - - // we check FAILED(hr) outside of function - return hr; -} diff --git a/src/AspNetCore/Src/inprocessstoredcontext.cxx b/src/AspNetCore/Src/inprocessstoredcontext.cxx deleted file mode 100644 index c0b2d8ff16..0000000000 --- a/src/AspNetCore/Src/inprocessstoredcontext.cxx +++ /dev/null @@ -1,113 +0,0 @@ -// 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" - -IN_PROCESS_STORED_CONTEXT::IN_PROCESS_STORED_CONTEXT( - IHttpContext* pHttpContext, - PVOID pMangedHttpContext -) -{ - // TODO if we want to go by IIS patterns, we should have these in a separate initialize function - m_pManagedHttpContext = pMangedHttpContext; - m_pHttpContext = pHttpContext; - m_fManagedRequestComplete = FALSE; -} - -IN_PROCESS_STORED_CONTEXT::~IN_PROCESS_STORED_CONTEXT() -{ -} - -PVOID -IN_PROCESS_STORED_CONTEXT::QueryManagedHttpContext( - VOID -) -{ - return m_pManagedHttpContext; -} - -IHttpContext* -IN_PROCESS_STORED_CONTEXT::QueryHttpContext( - VOID -) -{ - return m_pHttpContext; -} - -BOOL -IN_PROCESS_STORED_CONTEXT::QueryIsManagedRequestComplete( - VOID -) -{ - return m_fManagedRequestComplete; -} - -VOID -IN_PROCESS_STORED_CONTEXT::IndicateManagedRequestComplete( - VOID -) -{ - m_fManagedRequestComplete = TRUE; -} - -REQUEST_NOTIFICATION_STATUS -IN_PROCESS_STORED_CONTEXT::QueryAsyncCompletionStatus( - VOID -) -{ - return m_requestNotificationStatus; -} - -VOID -IN_PROCESS_STORED_CONTEXT::SetAsyncCompletionStatus( - REQUEST_NOTIFICATION_STATUS requestNotificationStatus -) -{ - m_requestNotificationStatus = requestNotificationStatus; -} - -HRESULT -IN_PROCESS_STORED_CONTEXT::GetInProcessStoredContext( - IHttpContext* pHttpContext, - IN_PROCESS_STORED_CONTEXT** ppInProcessStoredContext -) -{ - if (pHttpContext == NULL) - { - return E_FAIL; - } - - if (ppInProcessStoredContext == NULL) - { - return E_FAIL; - } - - *ppInProcessStoredContext = (IN_PROCESS_STORED_CONTEXT*)pHttpContext->GetModuleContextContainer()->GetModuleContext(g_pModuleId); - if (*ppInProcessStoredContext == NULL) - { - return E_FAIL; - } - - return S_OK; -} - -HRESULT -IN_PROCESS_STORED_CONTEXT::SetInProcessStoredContext( - IHttpContext* pHttpContext, - IN_PROCESS_STORED_CONTEXT* pInProcessStoredContext -) -{ - if (pHttpContext == NULL) - { - return E_FAIL; - } - if (pInProcessStoredContext == NULL) - { - return E_FAIL; - } - - return pHttpContext->GetModuleContextContainer()->SetModuleContext( - pInProcessStoredContext, - g_pModuleId - ); -} \ No newline at end of file diff --git a/src/AspNetCore/Src/outprocessapplication.cxx b/src/AspNetCore/Src/outprocessapplication.cxx deleted file mode 100644 index ce76d3be14..0000000000 --- a/src/AspNetCore/Src/outprocessapplication.cxx +++ /dev/null @@ -1,121 +0,0 @@ -// 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" - -OUT_OF_PROCESS_APPLICATION::OUT_OF_PROCESS_APPLICATION() - : m_pProcessManager(NULL) -{ -} - -OUT_OF_PROCESS_APPLICATION::~OUT_OF_PROCESS_APPLICATION() -{ - if (m_pProcessManager != NULL) - { - m_pProcessManager->ShutdownAllProcesses(); - m_pProcessManager->DereferenceProcessManager(); - m_pProcessManager = NULL; - } -} - - -// -// Initialize is guarded by a lock inside APPLICATION_MANAGER::GetApplication -// It ensures only one application will be initialized and singleton -// Error will happen if you call Initialized outside APPLICATION_MANAGER::GetApplication -// -__override -HRESULT -OUT_OF_PROCESS_APPLICATION::Initialize( - _In_ APPLICATION_MANAGER* pApplicationManager, - _In_ ASPNETCORE_CONFIG* pConfiguration -) -{ - HRESULT hr = S_OK; - - DBG_ASSERT(pApplicationManager != NULL); - DBG_ASSERT(pConfiguration != NULL); - - m_pApplicationManager = pApplicationManager; - m_pConfiguration = pConfiguration; - - hr = m_applicationKey.Initialize(pConfiguration->QueryApplicationPath()->QueryStr()); - 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; -} - -__override -VOID -OUT_OF_PROCESS_APPLICATION::OnAppOfflineHandleChange() -{ - // - // Sending signal to backend process for shutdown - // - if (m_pProcessManager != NULL) - { - m_pProcessManager->SendShutdownSignal(); - } -} - -__override -REQUEST_NOTIFICATION_STATUS -OUT_OF_PROCESS_APPLICATION::ExecuteRequest( - _In_ IHttpContext* pHttpContext -) -{ - // - // TODO: - // Ideally we should wrap the fowaring logic inside FORWARDING_HANDLER inside this function - // To achieve better abstraction. It is too risky to do it now - // - return RQ_NOTIFICATION_FINISH_REQUEST; -} \ No newline at end of file diff --git a/src/AspNetCore/Src/precomp.hxx b/src/AspNetCore/Src/precomp.hxx index 403d949256..b0c2c5cc4e 100644 --- a/src/AspNetCore/Src/precomp.hxx +++ b/src/AspNetCore/Src/precomp.hxx @@ -54,13 +54,6 @@ #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 inline T max(T a, T b) @@ -97,43 +90,33 @@ inline bool IsSpace(char ch) #include #include "stringa.h" #include "stringu.h" -//#include "treehash.h" - #include "dbgutil.h" #include "ahutil.h" #include "multisz.h" #include "multisza.h" #include "base64.h" -#include "sttimer.h" #include #include #include #include #include -#include "environmentvariablehash.h" -#include "..\aspnetcore_msg.h" -#include "aspnetcore_event.h" -#include "aspnetcoreconfig.h" -#include "serverprocess.h" -#include "processmanager.h" +#include "..\..\CommonLib\environmentvariablehash.h" +#include "..\..\CommonLib\aspnetcoreconfig.h" +#include "..\..\CommonLib\application.h" +#include "..\..\CommonLib\utility.h" +#include "..\..\CommonLib\debugutil.h" +#include "..\..\CommonLib\requesthandler.h" +//#include "..\aspnetcore_msg.h" +//#include "aspnetcore_event.h" +#include "appoffline.h" #include "filewatcher.h" -#include "application.h" +#include "applicationinfo.h" #include "applicationmanager.h" -#include "inprocessstoredcontext.h" -#include "inprocessapplication.h" -#include "outprocessapplication.h" +#include "globalmodule.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" -#include "fx_ver.h" + FORCEINLINE DWORD @@ -158,11 +141,15 @@ HRESULT_FROM_GETLASTERROR() : E_FAIL; } -extern BOOL g_fAsyncDisconnectAvailable; -extern BOOL g_fWinHttpNonBlockingCallbackAvailable; extern PVOID g_pModuleId; -extern BOOL g_fWebSocketSupported; +extern BOOL g_fAspnetcoreRHAssemblyLoaded; +extern BOOL g_fAspnetcoreRHLoadedError; extern BOOL g_fEnableReferenceCountTracing; extern DWORD g_dwActiveServerProcesses; -extern DWORD g_OptionalWinHttpFlags; +extern HMODULE g_hAspnetCoreRH; +extern SRWLOCK g_srwLock; +extern PCWSTR g_pwzAspnetcoreRequestHandlerName; + +extern PFN_ASPNETCORE_CREATE_APPLICATION g_pfnAspNetCoreCreateApplication; +extern PFN_ASPNETCORE_CREATE_REQUEST_HANDLER g_pfnAspNetCoreCreateRequestHandler; #pragma warning( error : 4091) \ No newline at end of file diff --git a/src/AspNetCore/Src/processmanager.cxx b/src/AspNetCore/Src/processmanager.cxx deleted file mode 100644 index 39a9a1811d..0000000000 --- a/src/AspNetCore/Src/processmanager.cxx +++ /dev/null @@ -1,294 +0,0 @@ -// 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_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;iIsReady() ) - { - 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/AspNetCore/Src/proxymodule.cxx b/src/AspNetCore/Src/proxymodule.cxx index 45f16a68e5..6f9b6e247a 100644 --- a/src/AspNetCore/Src/proxymodule.cxx +++ b/src/AspNetCore/Src/proxymodule.cxx @@ -5,12 +5,12 @@ __override HRESULT -CProxyModuleFactory::GetHttpModule( +ASPNET_CORE_PROXY_MODULE_FACTORY::GetHttpModule( CHttpModule ** ppModule, IModuleAllocator * pAllocator ) { - CProxyModule *pModule = new (pAllocator) CProxyModule(); + ASPNET_CORE_PROXY_MODULE *pModule = new (pAllocator) ASPNET_CORE_PROXY_MODULE(); if (pModule == NULL) { return E_OUTOFMEMORY; @@ -22,7 +22,7 @@ CProxyModuleFactory::GetHttpModule( __override VOID -CProxyModuleFactory::Terminate( +ASPNET_CORE_PROXY_MODULE_FACTORY::Terminate( VOID ) /*++ @@ -41,39 +41,38 @@ Return value: --*/ { - FORWARDING_HANDLER::StaticTerminate(); + /* FORWARDING_HANDLER::StaticTerminate(); - WEBSOCKET_HANDLER::StaticTerminate(); - - if (g_pResponseHeaderHash != NULL) - { - g_pResponseHeaderHash->Clear(); - delete g_pResponseHeaderHash; - g_pResponseHeaderHash = NULL; - } + WEBSOCKET_HANDLER::StaticTerminate();*/ ALLOC_CACHE_HANDLER::StaticTerminate(); delete this; } -CProxyModule::CProxyModule( -) : m_pHandler(NULL) +ASPNET_CORE_PROXY_MODULE::ASPNET_CORE_PROXY_MODULE( +) : m_pApplicationInfo(NULL), m_pHandler(NULL) { } -CProxyModule::~CProxyModule() +ASPNET_CORE_PROXY_MODULE::~ASPNET_CORE_PROXY_MODULE() { + if (m_pApplicationInfo != NULL) + { + m_pApplicationInfo->DereferenceApplicationInfo(); + m_pApplicationInfo = NULL; + } + if (m_pHandler != NULL) { - m_pHandler->DereferenceForwardingHandler(); + m_pHandler->DereferenceRequestHandler(); m_pHandler = NULL; } } __override REQUEST_NOTIFICATION_STATUS -CProxyModule::OnExecuteRequestHandler( +ASPNET_CORE_PROXY_MODULE::OnExecuteRequestHandler( IHttpContext * pHttpContext, IHttpEventProvider * ) @@ -81,47 +80,105 @@ CProxyModule::OnExecuteRequestHandler( HRESULT hr = S_OK; ASPNETCORE_CONFIG *pConfig = NULL; APPLICATION_MANAGER *pApplicationManager = NULL; - APPLICATION *pApplication = NULL; - hr = ASPNETCORE_CONFIG::GetConfig(pHttpContext, &pConfig); + REQUEST_NOTIFICATION_STATUS retVal = RQ_NOTIFICATION_CONTINUE; + APPLICATION* pApplication = NULL; + STACK_STRU(struFileName, 256); + + hr = ASPNETCORE_CONFIG::GetConfig(g_pHttpServer, g_pModuleId, pHttpContext, &pConfig); if (FAILED(hr)) { - goto Failed; + goto Finished; } pApplicationManager = APPLICATION_MANAGER::GetInstance(); if (pApplicationManager == NULL) { hr = E_OUTOFMEMORY; - goto Failed; + goto Finished; } - hr = pApplicationManager->GetApplication( - pHttpContext, - pConfig, - &pApplication); + hr = pApplicationManager->GetApplicationInfo( + g_pHttpServer, + pConfig, + &m_pApplicationInfo); if (FAILED(hr)) { - goto Failed; + goto Finished; } - m_pHandler = new FORWARDING_HANDLER(pHttpContext, pApplication); - - if (m_pHandler == NULL) + // app_offline check to avoid loading aspnetcorerh.dll unnecessarily + if (m_pApplicationInfo->AppOfflineFound()) { - hr = E_OUTOFMEMORY; - goto Failed; + // 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; } - return m_pHandler->OnExecuteRequestHandler(); + // make sure assmebly is loaded and application is created -Failed: - pHttpContext->GetResponse()->SetStatus(500, "Internal Server Error", 0, hr); - return REQUEST_NOTIFICATION_STATUS::RQ_NOTIFICATION_FINISH_REQUEST; + hr = m_pApplicationInfo->EnsureApplicationCreated(); + if (FAILED(hr)) + { + goto Finished; + } + pApplication = m_pApplicationInfo->QueryApplication(); + DBG_ASSERT(pApplication); + + // make sure application is in running state + // cannot recreate the application as we cannot reload clr for inprocess + if (pApplication->QueryStatus() != APPLICATION_STATUS::RUNNING) + { + 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)) + { + pHttpContext->GetResponse()->SetStatus(500, "Internal Server Error", 0, hr); + retVal = RQ_NOTIFICATION_FINISH_REQUEST; + } + return retVal; } __override REQUEST_NOTIFICATION_STATUS -CProxyModule::OnAsyncCompletion( +ASPNET_CORE_PROXY_MODULE::OnAsyncCompletion( IHttpContext *, DWORD, BOOL, diff --git a/src/CommonLib/CommonLib.vcxproj b/src/CommonLib/CommonLib.vcxproj new file mode 100644 index 0000000000..33163a1158 --- /dev/null +++ b/src/CommonLib/CommonLib.vcxproj @@ -0,0 +1,204 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 15.0 + {55494E58-E061-4C4C-A0A8-837008E72F85} + Win32Proj + NewCommon + 10.0.15063.0 + + + + StaticLibrary + true + v141 + Unicode + + + StaticLibrary + false + v141 + true + Unicode + + + StaticLibrary + true + v141 + Unicode + + + StaticLibrary + false + v141 + false + Unicode + + + + + + + + + + + + + + + + + + + + + true + + + true + + + false + + + false + C:\AspNetCoreModule\src\IISLib;$(IncludePath) + + + + Use + Level4 + true + Disabled + false + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + true + MultiThreadedDebug + false + + + Windows + true + + + + + Use + Level4 + true + Disabled + false + _DEBUG;_LIB;%(PreprocessorDefinitions) + true + ProgramDatabase + false + MultiThreadedDebug + false + + + Windows + true + + + + + Use + Level4 + true + MaxSpeed + true + true + false + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + true + MultiThreaded + false + + + Windows + true + true + true + + + + + Use + Level4 + true + MaxSpeed + true + true + false + NDEBUG;_LIB;%(PreprocessorDefinitions) + true + + + + + MultiThreaded + false + + + Windows + true + true + true + + + ..\iislib + + + + + + + + + + + + + + + + + + + + + Create + Create + Create + Create + + + + + + {4787a64f-9a3e-4867-a55a-70cb4b2b2ffe} + + + + + + \ No newline at end of file diff --git a/src/CommonLib/application.cpp b/src/CommonLib/application.cpp new file mode 100644 index 0000000000..966ee83d54 --- /dev/null +++ b/src/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_pHttpServer(pHttpServer), + m_pConfig(pConfig), + m_status(APPLICATION_STATUS::UNKNOWN) +{ +} + +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; + } +} \ No newline at end of file diff --git a/src/CommonLib/application.h b/src/CommonLib/application.h new file mode 100644 index 0000000000..880875ca7e --- /dev/null +++ b/src/CommonLib/application.h @@ -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. + +#pragma once + +enum APPLICATION_STATUS +{ + UNKNOWN = 0, + RUNNING, + FAUL +}; + +class ASPNETCORE_CONFIG; + +class APPLICATION +{ +public: + APPLICATION( + _In_ IHttpServer* pHttpServer, + _In_ ASPNETCORE_CONFIG* pConfig); + + virtual + VOID + ShutDown() = 0; + + virtual + ~APPLICATION(); + + APPLICATION_STATUS + QueryStatus(); + + ASPNETCORE_CONFIG* + QueryConfig(); + + VOID + ReferenceApplication() + const; + + VOID + DereferenceApplication() + const; + +protected: + mutable LONG m_cRefs; + APPLICATION_STATUS m_status; + IHttpServer* m_pHttpServer; + ASPNETCORE_CONFIG* m_pConfig; +}; \ No newline at end of file diff --git a/src/AspNetCore/Src/aspnetcoreconfig.cxx b/src/CommonLib/aspnetcoreconfig.cxx similarity index 81% rename from src/AspNetCore/Src/aspnetcoreconfig.cxx rename to src/CommonLib/aspnetcoreconfig.cxx index 99ccac1c3e..ea0799e87e 100644 --- a/src/AspNetCore/Src/aspnetcoreconfig.cxx +++ b/src/CommonLib/aspnetcoreconfig.cxx @@ -1,56 +1,47 @@ // 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 "stdafx.h" +#include "aspnetcoreconfig.h" ASPNETCORE_CONFIG::~ASPNETCORE_CONFIG() { - if (QueryHostingModel() == HOSTING_IN_PROCESS && - !g_fRecycleProcessCalled && - (g_pHttpServer->GetAdminManager() != NULL)) - { - // There is a bug in IHttpServer::RecycleProcess. It will hit AV when worker process - // has already been in recycling state. - // To workaround, do null check on GetAdminManager(). If it is NULL, worker process is in recycling - // Do not call RecycleProcess again - - // RecycleProcess can olny be called once - // In case of configuration change for in-process app - // We want notify IIS first to let new request routed to new worker process - - g_pHttpServer->RecycleProcess(L"AspNetCore Recycle Process on Configuration Change"); - } - - // It's safe for us to set this g_fRecycleProcessCalled - // as in_process scenario will always recycle the worker process for configuration change - g_fRecycleProcessCalled = TRUE; - - m_struApplicationFullPath.Reset(); if (m_pEnvironmentVariables != NULL) { m_pEnvironmentVariables->Clear(); delete m_pEnvironmentVariables; m_pEnvironmentVariables = NULL; } +} - if (!m_struApplication.IsEmpty()) - { - APPLICATION_MANAGER::GetInstance()->RecycleApplication(m_struApplication.QueryStr()); - } +VOID +ASPNETCORE_CONFIG::ReferenceConfiguration( + VOID +) const +{ + InterlockedIncrement(&m_cRefs); +} - if (QueryHostingModel() == HOSTING_IN_PROCESS && - g_pHttpServer->IsCommandLineLaunch()) + +VOID +ASPNETCORE_CONFIG::DereferenceConfiguration( + VOID +) const +{ + DBG_ASSERT(m_cRefs != 0); + LONG cRefs = 0; + if ((cRefs = InterlockedDecrement(&m_cRefs)) == 0) { - // IISExpress scenario, only option is to call exit in case configuration change - // as CLR or application may change - exit(0); + delete this; } } HRESULT ASPNETCORE_CONFIG::GetConfig( + _In_ IHttpServer *pHttpServer, + _In_ HTTP_MODULE_ID pModuleId, _In_ IHttpContext *pHttpContext, - _Out_ ASPNETCORE_CONFIG **ppAspNetCoreConfig + _Out_ ASPNETCORE_CONFIG **ppAspNetCoreConfig ) { HRESULT hr = S_OK; @@ -67,7 +58,7 @@ ASPNETCORE_CONFIG::GetConfig( // potential bug if user sepcific config at virtual dir level pAspNetCoreConfig = (ASPNETCORE_CONFIG*) - pHttpApplication->GetModuleContextContainer()->GetModuleContext(g_pModuleId); + pHttpApplication->GetModuleContextContainer()->GetModuleContext(pModuleId); if (pAspNetCoreConfig != NULL) { @@ -83,14 +74,14 @@ ASPNETCORE_CONFIG::GetConfig( goto Finished; } - hr = pAspNetCoreConfig->Populate(pHttpContext); + hr = pAspNetCoreConfig->Populate(pHttpServer, pHttpContext); if (FAILED(hr)) { goto Finished; } hr = pHttpApplication->GetModuleContextContainer()-> - SetModuleContext(pAspNetCoreConfig, g_pModuleId); + SetModuleContext(pAspNetCoreConfig, pModuleId); if (FAILED(hr)) { if (hr == HRESULT_FROM_WIN32(ERROR_ALREADY_ASSIGNED)) @@ -99,7 +90,7 @@ ASPNETCORE_CONFIG::GetConfig( pAspNetCoreConfig = (ASPNETCORE_CONFIG*)pHttpApplication-> GetModuleContextContainer()-> - GetModuleContext(g_pModuleId); + GetModuleContext(pModuleId); _ASSERT(pAspNetCoreConfig != NULL); @@ -137,11 +128,11 @@ Finished: HRESULT ASPNETCORE_CONFIG::Populate( + IHttpServer *pHttpServer, IHttpContext *pHttpContext ) { HRESULT hr = S_OK; - STACK_STRU(strSiteConfigPath, 256); STRU strEnvName; STRU strEnvValue; STRU strExpandedEnvValue; @@ -160,6 +151,10 @@ ASPNETCORE_CONFIG::Populate( DWORD dwCounter = 0; DWORD dwPosition = 0; WCHAR* pszPath = NULL; + BSTR bstrWindowAuthSection = NULL; + BSTR bstrBasicAuthSection = NULL; + BSTR bstrAnonymousAuthSection = NULL; + BSTR bstrAspNetCoreSection = NULL; m_pEnvironmentVariables = new ENVIRONMENT_VAR_HASH(); if (m_pEnvironmentVariables == NULL) @@ -174,20 +169,20 @@ ASPNETCORE_CONFIG::Populate( goto Finished; } - pAdminManager = g_pHttpServer->GetAdminManager(); - hr = strSiteConfigPath.Copy(pHttpContext->GetApplication()->GetAppConfigPath()); + pAdminManager = pHttpServer->GetAdminManager(); + hr = m_struConfigPath.Copy(pHttpContext->GetApplication()->GetAppConfigPath()); if (FAILED(hr)) { goto Finished; } - hr = m_struApplicationFullPath.Copy(pHttpContext->GetApplication()->GetApplicationPhysicalPath()); + hr = m_struApplicationPhysicalPath.Copy(pHttpContext->GetApplication()->GetApplicationPhysicalPath()); if (FAILED(hr)) { goto Finished; } - pszPath = strSiteConfigPath.QueryStr(); + pszPath = m_struConfigPath.QueryStr(); while (pszPath[dwPosition] != NULL) { if (pszPath[dwPosition] == '/') @@ -214,8 +209,15 @@ ASPNETCORE_CONFIG::Populate( goto Finished; } - hr = pAdminManager->GetAdminSection(CS_WINDOWS_AUTHENTICATION_SECTION, - strSiteConfigPath.QueryStr(), + 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)) { @@ -235,8 +237,14 @@ ASPNETCORE_CONFIG::Populate( } } - hr = pAdminManager->GetAdminSection(CS_BASIC_AUTHENTICATION_SECTION, - strSiteConfigPath.QueryStr(), + 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)) { @@ -252,9 +260,14 @@ ASPNETCORE_CONFIG::Populate( goto Finished; } } - - hr = pAdminManager->GetAdminSection(CS_ANONYMOUS_AUTHENTICATION_SECTION, - strSiteConfigPath.QueryStr(), + 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)) { @@ -271,8 +284,14 @@ ASPNETCORE_CONFIG::Populate( } } - hr = pAdminManager->GetAdminSection(CS_ASPNETCORE_SECTION, - strSiteConfigPath.QueryStr(), + bstrAspNetCoreSection = SysAllocString(CS_ASPNETCORE_SECTION); + if (bstrAspNetCoreSection == NULL) + { + hr = E_OUTOFMEMORY; + goto Finished; + } + hr = pAdminManager->GetAdminSection(bstrAspNetCoreSection, + m_struConfigPath.QueryStr(), &pAspNetCoreElement); if (FAILED(hr)) { @@ -402,13 +421,13 @@ ASPNETCORE_CONFIG::Populate( { goto Finished; } - hr = GetElementStringProperty(pAspNetCoreElement, - CS_ASPNETCORE_STDOUT_LOG_FILE, - &m_struStdoutLogFile); - 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, diff --git a/src/AspNetCore/Inc/aspnetcoreconfig.h b/src/CommonLib/aspnetcoreconfig.h similarity index 81% rename from src/AspNetCore/Inc/aspnetcoreconfig.h rename to src/CommonLib/aspnetcoreconfig.h index b3fa4d7d8e..ffb4928cf9 100644 --- a/src/AspNetCore/Inc/aspnetcoreconfig.h +++ b/src/CommonLib/aspnetcoreconfig.h @@ -34,11 +34,13 @@ #define MIN_PORT 1025 #define MAX_PORT 48000 -#define HEX_TO_ASCII(c) ((CHAR)(((c) < 10) ? ((c) + '0') : ((c) + 'a' - 10))) +#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))) -extern HTTP_MODULE_ID g_pModuleId; -extern IHttpServer * g_pHttpServer; -extern BOOL g_fRecycleProcessCalled; +//#define HEX_TO_ASCII(c) ((CHAR)(((c) < 10) ? ((c) + '0') : ((c) + 'a' - 10))) + +#include "stdafx.h" enum APP_HOSTING_MODEL { @@ -57,14 +59,16 @@ public: VOID CleanupStoredContext() { - delete this; + DereferenceConfiguration(); } static HRESULT GetConfig( - _In_ IHttpContext *pHttpContext, - _Out_ ASPNETCORE_CONFIG **ppAspNetCoreConfig + _In_ IHttpServer *pHttpServer, + _In_ HTTP_MODULE_ID pModuleId, + _In_ IHttpContext *pHttpContext, + _Out_ ASPNETCORE_CONFIG **ppAspNetCoreConfig ); ENVIRONMENT_VAR_HASH* @@ -132,11 +136,11 @@ public: } STRU* - QueryApplicationFullPath( + QueryApplicationPhysicalPath( VOID ) { - return &m_struApplicationFullPath; + return &m_struApplicationPhysicalPath; } STRU* @@ -149,30 +153,22 @@ public: STRU* QueryProcessPath( - VOID - ) + VOID + ) { return &m_struProcessPath; } APP_HOSTING_MODEL QueryHostingModel( - VOID + VOID ) { return m_hostingModel; } - STRU* - QueryHostingModelStr( - VOID - ) - { - return &m_strHostingModel; - } - BOOL - QueryStdoutLogEnabled() + QueryStdoutLogEnabled() { return m_fStdoutLogEnabled; } @@ -213,6 +209,36 @@ public: return &m_struStdoutLogFile; } + STRU* + QueryConfigPath() + { + return &m_struConfigPath; + } + + STRU* + QueryHostfxrPath() + { + return &m_struHostFxrPath; + } + + BOOL + QueryIsStandAloneApplication( + VOID + ) + { + return m_fIsStandAloneApplication; + } + + VOID + ReferenceConfiguration( + VOID + ) const; + + VOID + DereferenceConfiguration( + VOID + ) const; + private: // @@ -221,33 +247,40 @@ private: ASPNETCORE_CONFIG(): m_fStdoutLogEnabled( FALSE ), m_pEnvironmentVariables( NULL ), + m_cRefs( 1 ), m_hostingModel( HOSTING_UNKNOWN ) { } 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_struApplication; STRU m_struArguments; STRU m_struProcessPath; STRU m_struStdoutLogFile; - STRU m_struApplicationFullPath; - STRU m_strHostingModel; + STRU m_struApplication; + STRU m_struApplicationPhysicalPath; STRU m_struApplicationVirtualPath; + STRU m_struConfigPath; + STRU m_strHostingModel; + STRU m_struHostFxrPath; BOOL m_fStdoutLogEnabled; BOOL m_fForwardWindowsAuthToken; BOOL m_fDisableStartUpErrorPage; BOOL m_fWindowsAuthEnabled; BOOL m_fBasicAuthEnabled; BOOL m_fAnonymousAuthEnabled; + BOOL m_fIsStandAloneApplication; APP_HOSTING_MODEL m_hostingModel; ENVIRONMENT_VAR_HASH* m_pEnvironmentVariables; }; diff --git a/src/AspNetCore/Inc/debugutil.h b/src/CommonLib/debugutil.h similarity index 99% rename from src/AspNetCore/Inc/debugutil.h rename to src/CommonLib/debugutil.h index aee17b4fba..16fce88edd 100644 --- a/src/AspNetCore/Inc/debugutil.h +++ b/src/CommonLib/debugutil.h @@ -2,7 +2,6 @@ // 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 diff --git a/src/AspNetCore/Inc/environmentvariablehash.h b/src/CommonLib/environmentvariablehash.h similarity index 100% rename from src/AspNetCore/Inc/environmentvariablehash.h rename to src/CommonLib/environmentvariablehash.h diff --git a/src/CommonLib/fx_ver.cxx b/src/CommonLib/fx_ver.cxx new file mode 100644 index 0000000000..7aeb0999c0 --- /dev/null +++ b/src/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/CommonLib/fx_ver.h b/src/CommonLib/fx_ver.h new file mode 100644 index 0000000000..1626b2697c --- /dev/null +++ b/src/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/CommonLib/hostfxr_utility.cpp b/src/CommonLib/hostfxr_utility.cpp new file mode 100644 index 0000000000..a5ec15fabb --- /dev/null +++ b/src/CommonLib/hostfxr_utility.cpp @@ -0,0 +1,259 @@ +// 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() +{ +} + +HRESULT +HOSTFXR_UTILITY::FindHostFxrDll( + ASPNETCORE_CONFIG *pConfig, + STRU* struHostFxrDllLocation, + BOOL* fStandAlone +) +{ + HRESULT hr = S_OK; + + // If the process path isn't dotnet, assume we are a standalone appliction. + // TODO: this should be a path equivalent check + if (!(pConfig->QueryProcessPath()->Equals(L".\\dotnet") + || pConfig->QueryProcessPath()->Equals(L"dotnet") + || pConfig->QueryProcessPath()->Equals(L".\\dotnet.exe") + || pConfig->QueryProcessPath()->Equals(L"dotnet.exe"))) + { + // hostfxr is in the same folder, parse and use it. + hr = GetStandaloneHostfxrLocation(struHostFxrDllLocation, pConfig); + *fStandAlone = TRUE; + } + else + { + hr = GetPortableHostfxrLocation(struHostFxrDllLocation); + fStandAlone = FALSE; + } + + return hr; +} + +// +// 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::GetStandaloneHostfxrLocation( + STRU* struHostfxrPath, + ASPNETCORE_CONFIG *pConfig +) +{ + HRESULT hr = S_OK; + HANDLE hFileHandle = INVALID_HANDLE_VALUE; + SECURITY_ATTRIBUTES saAttr; + + // Get the full path to the exe and check if it exists + if (FAILED(hr = UTILITY::ConvertPathToFullPath(L"\\hostfxr.dll", + pConfig->QueryApplicationPhysicalPath()->QueryStr(), + struHostfxrPath))) + { + goto Finished; + } + + + saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); + saAttr.bInheritHandle = TRUE; + saAttr.lpSecurityDescriptor = NULL; + + hFileHandle = CreateFile(struHostfxrPath->QueryStr(), + GENERIC_READ, + FILE_SHARE_READ, + &saAttr, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); + if (hFileHandle == INVALID_HANDLE_VALUE) + { + // Treat access isseu as File not found + hr = ERROR_FILE_NOT_FOUND; + goto Finished; + } + else + { + CloseHandle(hFileHandle); + } + +Finished: + return hr; +} + +HRESULT +HOSTFXR_UTILITY::GetPortableHostfxrLocation( + STRU* struHostfxrPath +) +{ + HRESULT hr = S_OK; + + STRU struSystemPathVariable; + STRU strDotnetExeLocation; + STRU strHostFxrSearchExpression; + STRU strHighestDotnetVersion; + PWSTR pwzDelimeterContext = NULL; + PCWSTR pszDotnetLocation = NULL; + PCWSTR pszDotnetExeString(L"dotnet.exe"); + DWORD dwCopyLength; + BOOL fFound = FALSE; + HANDLE hFileHandle = INVALID_HANDLE_VALUE; + SECURITY_ATTRIBUTES saAttr; + std::vector vVersionFolders; + + if (FAILED(hr)) + { + goto Finished; + } + + // Get the System PATH value. + if (!UTILITY::GetSystemPathVariable(L"PATH", &struSystemPathVariable)) + { + hr = ERROR_BAD_ENVIRONMENT; + goto Finished; + } + + // Split on ';', checking to see if dotnet.exe exists in any folders. + pszDotnetLocation = wcstok_s(struSystemPathVariable.QueryStr(), L";", &pwzDelimeterContext); + while (pszDotnetLocation != NULL) + { + dwCopyLength = (DWORD) wcsnlen_s(pszDotnetLocation, 260); + + // We store both the exe and folder locations as we eventually need to check inside of host\\fxr + // which doesn't need the dotnet.exe portion of the string + hr = strDotnetExeLocation.Copy(pszDotnetLocation, dwCopyLength); + if (FAILED(hr)) + { + goto Finished; + } + + if (dwCopyLength > 0 && pszDotnetLocation[dwCopyLength - 1] != L'\\') + { + hr = strDotnetExeLocation.Append(L"\\"); + if (FAILED(hr)) + { + goto Finished; + } + } + + hr = struHostfxrPath->Copy(strDotnetExeLocation); + if (FAILED(hr)) + { + goto Finished; + } + + hr = strDotnetExeLocation.Append(pszDotnetExeString); + if (FAILED(hr)) + { + goto Finished; + } + + saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); + saAttr.bInheritHandle = TRUE; + saAttr.lpSecurityDescriptor = NULL; + + hFileHandle = CreateFile(strDotnetExeLocation.QueryStr(), + GENERIC_READ, + FILE_SHARE_READ, + &saAttr, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); + if (hFileHandle != INVALID_HANDLE_VALUE) + { + // means we found the folder with a dotnet.exe inside of it. + fFound = TRUE; + CloseHandle(hFileHandle); + break; + } + pszDotnetLocation = wcstok_s(NULL, L";", &pwzDelimeterContext); + } + + if (!fFound) + { + // could not find dotnet.exe, error out + hr = ERROR_BAD_ENVIRONMENT; + goto Finished; + } + + hr = struHostfxrPath->Append(L"host\\fxr"); + if (FAILED(hr)) + { + goto Finished; + } + + if (!UTILITY::DirectoryExists(struHostfxrPath)) + { + // error, not found the folder + hr = ERROR_BAD_ENVIRONMENT; + goto Finished; + } + + // Find all folders under host\\fxr\\ for version numbers. + hr = strHostFxrSearchExpression.Copy(struHostfxrPath); + if (FAILED(hr)) + { + goto Finished; + } + + hr = strHostFxrSearchExpression.Append(L"\\*"); + if (FAILED(hr)) + { + goto Finished; + } + + // As we use the logic from core-setup, we are opting to use std here. + // TODO remove all uses of std? + UTILITY::FindDotNetFolders(strHostFxrSearchExpression.QueryStr(), &vVersionFolders); + + if (vVersionFolders.size() == 0) + { + // no core framework was found + hr = ERROR_BAD_ENVIRONMENT; + goto Finished; + } + + hr = UTILITY::FindHighestDotNetVersion(vVersionFolders, &strHighestDotnetVersion); + if (FAILED(hr)) + { + goto Finished; + } + hr = struHostfxrPath->Append(L"\\"); + if (FAILED(hr)) + { + goto Finished; + } + + hr = struHostfxrPath->Append(strHighestDotnetVersion.QueryStr()); + if (FAILED(hr)) + { + goto Finished; + + } + + hr = struHostfxrPath->Append(L"\\hostfxr.dll"); + if (FAILED(hr)) + { + goto Finished; + } + +Finished: + return hr; +} \ No newline at end of file diff --git a/src/CommonLib/hostfxr_utility.h b/src/CommonLib/hostfxr_utility.h new file mode 100644 index 0000000000..adff785388 --- /dev/null +++ b/src/CommonLib/hostfxr_utility.h @@ -0,0 +1,33 @@ +// 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 HOSTFXR_UTILITY +{ +public: + HOSTFXR_UTILITY(); + ~HOSTFXR_UTILITY(); + + static + HRESULT + FindHostFxrDll( + ASPNETCORE_CONFIG *pConfig, + STRU* struHostFxrDllLocation, + BOOL* fStandAlone + ); + + static + HRESULT + GetStandaloneHostfxrLocation( + STRU* struHostfxrPath, + ASPNETCORE_CONFIG *pConfig + ); + + static + HRESULT + GetPortableHostfxrLocation( + STRU* struHostfxrPath + ); +}; + diff --git a/src/CommonLib/requesthandler.cxx b/src/CommonLib/requesthandler.cxx new file mode 100644 index 0000000000..bcf1887d35 --- /dev/null +++ b/src/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/CommonLib/requesthandler.h b/src/CommonLib/requesthandler.h new file mode 100644 index 0000000000..28f4fb725e --- /dev/null +++ b/src/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/CommonLib/stdafx.cpp b/src/CommonLib/stdafx.cpp new file mode 100644 index 0000000000..18b5b37fe1 Binary files /dev/null and b/src/CommonLib/stdafx.cpp differ diff --git a/src/CommonLib/stdafx.h b/src/CommonLib/stdafx.h new file mode 100644 index 0000000000..89eb66cdc4 Binary files /dev/null and b/src/CommonLib/stdafx.h differ diff --git a/src/CommonLib/targetver.h b/src/CommonLib/targetver.h new file mode 100644 index 0000000000..567cd346ef Binary files /dev/null and b/src/CommonLib/targetver.h differ diff --git a/src/AspNetCore/Src/path.cxx b/src/CommonLib/utility.cxx similarity index 71% rename from src/AspNetCore/Src/path.cxx rename to src/CommonLib/utility.cxx index a4ef464539..10876c104e 100644 --- a/src/AspNetCore/Src/path.cxx +++ b/src/CommonLib/utility.cxx @@ -1,11 +1,11 @@ // 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"stdafx.h" // static HRESULT -PATH::SplitUrl( +UTILITY::SplitUrl( PCWSTR pszDestinationUrl, BOOL *pfSecure, STRU *pstrDestination, @@ -95,7 +95,7 @@ Return Value: // static HRESULT -PATH::UnEscapeUrl( +UTILITY::UnEscapeUrl( PCWSTR pszUrl, DWORD cchUrl, bool fCopyQuery, @@ -151,7 +151,7 @@ PATH::UnEscapeUrl( // static HRESULT -PATH::UnEscapeUrl( +UTILITY::UnEscapeUrl( PCWSTR pszUrl, DWORD cchUrl, STRU * pstrResult @@ -231,7 +231,7 @@ PATH::UnEscapeUrl( } HRESULT -PATH::EscapeAbsPath( +UTILITY::EscapeAbsPath( IHttpRequest * pRequest, STRU * strEscapedUrl ) @@ -269,7 +269,7 @@ Finished: // static bool -PATH::IsValidAttributeNameChar( +UTILITY::IsValidAttributeNameChar( WCHAR ch ) { @@ -282,7 +282,7 @@ PATH::IsValidAttributeNameChar( // static bool -PATH::FindInMultiString( +UTILITY::FindInMultiString( PCWSTR pszMultiString, PCWSTR pszStringToFind ) @@ -301,7 +301,7 @@ PATH::FindInMultiString( // static bool -PATH::IsValidQueryStringName( +UTILITY::IsValidQueryStringName( PCWSTR pszName ) { @@ -322,7 +322,7 @@ PATH::IsValidQueryStringName( // static bool -PATH::IsValidHeaderName( +UTILITY::IsValidHeaderName( PCWSTR pszName ) { @@ -342,7 +342,7 @@ PATH::IsValidHeaderName( } HRESULT -PATH::IsPathUnc( +UTILITY::IsPathUnc( __in LPCWSTR pszPath, __out BOOL * pfIsUnc ) @@ -373,7 +373,7 @@ Finished: } HRESULT -PATH::ConvertPathToFullPath( +UTILITY::ConvertPathToFullPath( _In_ LPCWSTR pszPath, _In_ LPCWSTR pszRootPath, _Out_ STRU* pStruFullPath @@ -384,7 +384,7 @@ PATH::ConvertPathToFullPath( LPWSTR pszFullPath = NULL; // if relative path, prefix with root path and then convert to absolute path. - if( pszPath[0] == L'.' ) + if ( pszPath[0] == L'.' ) { hr = strFileFullPath.Copy(pszRootPath); if(FAILED(hr)) @@ -403,13 +403,13 @@ PATH::ConvertPathToFullPath( } hr = strFileFullPath.Append( pszPath ); - if(FAILED(hr)) + if (FAILED(hr)) { goto Finished; } pszFullPath = new WCHAR[ strFileFullPath.QueryCCH() + 1]; - if( pszFullPath == NULL ) + if ( pszFullPath == NULL ) { hr = E_OUTOFMEMORY; goto Finished; @@ -425,18 +425,185 @@ PATH::ConvertPathToFullPath( // convert to canonical path hr = MakePathCanonicalizationProof( pszFullPath, pStruFullPath ); - if(FAILED(hr)) + if (FAILED(hr)) { goto Finished; } Finished: - if( pszFullPath != NULL ) + 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 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); +} + +BOOL +UTILITY::GetSystemPathVariable( + _In_ PCWSTR pszEnvironmentVariable, + _Out_ STRU *pstrResult +) +{ + DWORD dwLength; + PWSTR pszBuffer = NULL; + BOOL fSucceeded = FALSE; + + if (pszEnvironmentVariable == NULL) + { + goto Finished; + } + pstrResult->Reset(); + dwLength = GetEnvironmentVariableW(pszEnvironmentVariable, NULL, 0); + + if (dwLength == 0) + { + goto Finished; + } + + pszBuffer = new WCHAR[dwLength]; + if (GetEnvironmentVariableW(pszEnvironmentVariable, pszBuffer, dwLength) == 0) + { + goto Finished; + } + + pstrResult->Copy(pszBuffer); + + fSucceeded = TRUE; + +Finished: + if (pszBuffer != NULL) { + delete[] pszBuffer; + } + return fSucceeded; +} + +VOID +UTILITY::FindDotNetFolders( + _In_ PCWSTR pszPath, + _Out_ std::vector *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); } \ No newline at end of file diff --git a/src/AspNetCore/Inc/path.h b/src/CommonLib/utility.h similarity index 69% rename from src/AspNetCore/Inc/path.h rename to src/CommonLib/utility.h index a553ccfe05..7ad0119445 100644 --- a/src/AspNetCore/Inc/path.h +++ b/src/CommonLib/utility.h @@ -3,7 +3,7 @@ #pragma once -class PATH +class UTILITY { public: @@ -79,17 +79,41 @@ public: _Out_ STRU* pStrFullPath ); -private: - - PATH() {} - ~PATH() {} + static + HRESULT + EnsureDirectoryPathExist( + _In_ LPCWSTR pszPath + ); static - CHAR - ToHexDigit( - UINT nDigit - ) - { - return static_cast(nDigit > 9 ? nDigit - 10 + 'A' : nDigit + '0'); - } + BOOL + DirectoryExists( + _In_ STRU *pstrPath + ); + + static + BOOL + GetSystemPathVariable( + _In_ PCWSTR pszEnvironmentVariable, + _Out_ STRU *pstrResult + ); + + static + VOID + FindDotNetFolders( + _In_ PCWSTR pszPath, + _Out_ std::vector *pvFolders + ); + + static + HRESULT + FindHighestDotNetVersion( + _In_ std::vector vFolders, + _Out_ STRU *pstrResult + ); + +private: + + UTILITY() {} + ~UTILITY() {} }; \ No newline at end of file diff --git a/src/IISLib/IISLib.vcxproj b/src/IISLib/IISLib.vcxproj index 4f9f36678a..05a4e90bf5 100644 --- a/src/IISLib/IISLib.vcxproj +++ b/src/IISLib/IISLib.vcxproj @@ -23,7 +23,7 @@ Win32Proj IISLib IISLib - 10.0.15063.0 + 8.1
@@ -78,6 +78,8 @@ WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) true ProgramDatabase + MultiThreadedDebug + false Windows @@ -94,6 +96,7 @@ true ProgramDatabase MultiThreadedDebug + false Windows @@ -111,6 +114,7 @@ WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) true MultiThreaded + false Windows @@ -130,6 +134,7 @@ WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) true MultiThreaded + false Windows diff --git a/src/IISLib/precomp.h b/src/IISLib/precomp.h index 0dc0cd7b52..9cccea4045 100644 --- a/src/IISLib/precomp.h +++ b/src/IISLib/precomp.h @@ -4,6 +4,9 @@ #include #include #pragma warning( disable:4127 ) +#include +#include +#include #include #include #include @@ -16,3 +19,4 @@ #include "ahutil.h" #include "acache.h" //#include "base64.hxx" + diff --git a/src/RequestHandler/RequestHandler.rc b/src/RequestHandler/RequestHandler.rc new file mode 100644 index 0000000000..6d28532915 Binary files /dev/null and b/src/RequestHandler/RequestHandler.rc differ diff --git a/src/RequestHandler/RequestHandler.vcxproj b/src/RequestHandler/RequestHandler.vcxproj new file mode 100644 index 0000000000..68424230df --- /dev/null +++ b/src/RequestHandler/RequestHandler.vcxproj @@ -0,0 +1,287 @@ + + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 15.0 + {D57EA297-6DC2-4BC0-8C91-334863327863} + Win32Proj + RequestHandler + 10.0.15063.0 + RequestHandler + + + + DynamicLibrary + true + v141 + Unicode + + + DynamicLibrary + false + v141 + true + Unicode + + + DynamicLibrary + true + v141 + Unicode + + + DynamicLibrary + false + v141 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + aspnetcorerh + $(SolutionDir)artifacts\build\AspNetCore\bin\$(Configuration)\$(Platform) + + + true + aspnetcorerh + $(SolutionDir)artifacts\build\AspNetCore\bin\$(Configuration)\$(Platform) + + + false + aspnetcorerh + $(SolutionDir)artifacts\build\AspNetCore\bin\$(Configuration)\$(Platform) + + + false + aspnetcorerh + $(SolutionDir)artifacts\build\AspNetCore\bin\$(Configuration)\$(Platform) + + + + NotUsing + Level4 + Disabled + WIN32;_DEBUG;REQUESTHANDLER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + precomp.hxx + $(IntDir)$(TargetName).pch + ProgramDatabase + MultiThreadedDebug + ..\IISLib;..\CommonLib;.\Inc + true + true + true + false + SyncCThrow + 8Bytes + true + false + true + CompileAsCpp + true + + + Windows + true + 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) + Source.def + + + + + NotUsing + Level4 + Disabled + WIN32;_DEBUG;REQUESTHANDLER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + precomp.hxx + $(IntDir)$(TargetName).pch + ProgramDatabase + MultiThreadedDebug + ..\IISLib;..\CommonLib;.\Inc + true + true + true + false + SyncCThrow + 8Bytes + true + false + true + CompileAsCpp + true + + + Windows + true + 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) + Source.def + + + + + Level4 + NotUsing + MaxSpeed + true + true + WIN32;NDEBUG;_WINDOWS;_USRDLL;REQUESTHANDLER_EXPORTS;%(PreprocessorDefinitions) + precomp.hxx + MultiThreaded + ..\IISLib;..\CommonLib;.\Inc + true + true + true + false + SyncCThrow + 8Bytes + true + false + true + CompileAsCpp + true + + + Windows + false + true + true + Source.def + 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) + + + + + Level4 + NotUsing + MaxSpeed + true + true + NDEBUG;REQUESTHANDLER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + precomp.hxx + MultiThreaded + ..\IISLib;..\CommonLib;.\Inc + true + true + true + false + SyncCThrow + 8Bytes + true + false + true + CompileAsCpp + true + + + Windows + false + true + true + Source.def + 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) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Document + mc %(FullPath) + Compiling Event Messages ... + %(Filename).rc;%(Filename).h;MSG0409.bin + mc %(FullPath) + Compiling Event Messages ... + %(Filename).rc;%(Filename).h;MSG0409.bin + mc %(FullPath) + Compiling Event Messages ... + %(Filename).rc;%(Filename).h;MSG0409.bin + mc %(FullPath) + Compiling Event Messages ... + %(Filename).rc;%(Filename).h;MSG0409.bin + + + + + {55494e58-e061-4c4c-a0a8-837008e72f85} + + + {4787a64f-9a3e-4867-a55a-70cb4b2b2ffe} + + + + + + + + + + + + \ No newline at end of file diff --git a/src/RequestHandler/RequestHandler.vcxproj.filters b/src/RequestHandler/RequestHandler.vcxproj.filters new file mode 100644 index 0000000000..b891f5ff15 --- /dev/null +++ b/src/RequestHandler/RequestHandler.vcxproj.filters @@ -0,0 +1,109 @@ + + + + + + InProcess + + + InProcess + + + InProcess + + + OutOfProcess + + + OutOfProcess + + + OutOfProcess + + + OutOfProcess + + + OutOfProcess + + + OutOfProcess + + + OutOfProcess + + + OutOfProcess + + + OutOfProcess + + + + + + + InProcess + + + InProcess + + + OutOfProcess + + + OutOfProcess + + + OutOfProcess + + + OutOfProcess + + + OutOfProcess + + + OutOfProcess + + + OutOfProcess + + + OutOfProcess + + + OutOfProcess + + + OutOfProcess + + + + + + + + + + + + + + + + + + + + + {e567abb5-bac5-4f05-a320-5e25dcfc0000} + + + {5568209f-269e-4d0a-bbb7-ba14f874ccb7} + + + + + + \ No newline at end of file diff --git a/src/RequestHandler/Resource.rc b/src/RequestHandler/Resource.rc new file mode 100644 index 0000000000..0241f12cce Binary files /dev/null and b/src/RequestHandler/Resource.rc differ diff --git a/src/RequestHandler/Source.cpp b/src/RequestHandler/Source.cpp new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/RequestHandler/Source.def b/src/RequestHandler/Source.def new file mode 100644 index 0000000000..889bd1a39b --- /dev/null +++ b/src/RequestHandler/Source.def @@ -0,0 +1,6 @@ +LIBRARY aspnetcorerh + +EXPORTS + CreateApplication + CreateRequestHandler + diff --git a/src/AspNetCore/Inc/aspnetcore_event.h b/src/RequestHandler/aspnetcore_event.h similarity index 100% rename from src/AspNetCore/Inc/aspnetcore_event.h rename to src/RequestHandler/aspnetcore_event.h diff --git a/src/RequestHandler/aspnetcore_msg.h b/src/RequestHandler/aspnetcore_msg.h new file mode 100644 index 0000000000..f99bc99084 --- /dev/null +++ b/src/RequestHandler/aspnetcore_msg.h @@ -0,0 +1,165 @@ +/*++ + + 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_ + +// +// Values are 32 bit values laid out as follows: +// +// 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 +// 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 +// +---+-+-+-----------------------+-------------------------------+ +// |Sev|C|R| Facility | Code | +// +---+-+-+-----------------------+-------------------------------+ +// +// where +// +// Sev - is the severity code +// +// 00 - Success +// 01 - Informational +// 10 - Warning +// 11 - Error +// +// C - is the Customer code flag +// +// R - is a reserved bit +// +// Facility - is the facility code +// +// Code - is the facility's status code +// +// +// Define the facility codes +// + + +// +// Define the severity codes +// + + +// +// MessageId: ASPNETCORE_EVENT_PROCESS_START_ERROR +// +// MessageText: +// +// %1 +// +#define ASPNETCORE_EVENT_PROCESS_START_ERROR ((DWORD)0x000003E8L) + +// +// MessageId: ASPNETCORE_EVENT_PROCESS_START_SUCCESS +// +// MessageText: +// +// %1 +// +#define ASPNETCORE_EVENT_PROCESS_START_SUCCESS ((DWORD)0x000003E9L) + +// +// MessageId: ASPNETCORE_EVENT_PROCESS_CRASH +// +// MessageText: +// +// %1 +// +#define ASPNETCORE_EVENT_PROCESS_CRASH ((DWORD)0x000003EAL) + +// +// MessageId: ASPNETCORE_EVENT_RAPID_FAIL_COUNT_EXCEEDED +// +// MessageText: +// +// %1 +// +#define ASPNETCORE_EVENT_RAPID_FAIL_COUNT_EXCEEDED ((DWORD)0x000003EBL) + +// +// MessageId: ASPNETCORE_EVENT_CONFIG_ERROR +// +// MessageText: +// +// %1 +// +#define ASPNETCORE_EVENT_CONFIG_ERROR ((DWORD)0x000003ECL) + +// +// MessageId: ASPNETCORE_EVENT_GRACEFUL_SHUTDOWN_FAILURE +// +// MessageText: +// +// %1 +// +#define ASPNETCORE_EVENT_GRACEFUL_SHUTDOWN_FAILURE ((DWORD)0x000003EDL) + +// +// MessageId: ASPNETCORE_EVENT_SENT_SHUTDOWN_HTTP_REQUEST +// +// MessageText: +// +// %1 +// +#define ASPNETCORE_EVENT_SENT_SHUTDOWN_HTTP_REQUEST ((DWORD)0x000003EEL) + +// +// MessageId: ASPNETCORE_EVENT_LOAD_CLR_FALIURE +// +// MessageText: +// +// %1 +// +#define ASPNETCORE_EVENT_LOAD_CLR_FALIURE ((DWORD)0x000003EFL) + +// +// MessageId: ASPNETCORE_EVENT_DUPLICATED_INPROCESS_APP +// +// MessageText: +// +// %1 +// +#define ASPNETCORE_EVENT_DUPLICATED_INPROCESS_APP ((DWORD)0x000003F0L) + +// +// MessageId: ASPNETCORE_EVENT_MIXED_HOSTING_MODEL_ERROR +// +// MessageText: +// +// %1 +// +#define ASPNETCORE_EVENT_MIXED_HOSTING_MODEL_ERROR ((DWORD)0x000003F1L) + +// +// MessageId: ASPNETCORE_EVENT_ADD_APPLICATION_ERROR +// +// MessageText: +// +// %1 +// +#define ASPNETCORE_EVENT_ADD_APPLICATION_ERROR ((DWORD)0x000003F2L) + +// +// MessageId: ASPNETCORE_EVENT_INPROCESS_THREAD_EXIT +// +// MessageText: +// +// %1 +// +#define ASPNETCORE_EVENT_INPROCESS_THREAD_EXIT ((DWORD)0x000003F3L) + + +#endif // _ASPNETCORE_MODULE_MSG_H_ diff --git a/src/AspNetCore/Src/aspnetcore_msg.mc b/src/RequestHandler/aspnetcore_msg.mc similarity index 100% rename from src/AspNetCore/Src/aspnetcore_msg.mc rename to src/RequestHandler/aspnetcore_msg.mc diff --git a/src/RequestHandler/aspnetcore_msg.rc b/src/RequestHandler/aspnetcore_msg.rc new file mode 100644 index 0000000000..0abcb0fa2c --- /dev/null +++ b/src/RequestHandler/aspnetcore_msg.rc @@ -0,0 +1,2 @@ +LANGUAGE 0x9,0x1 +1 11 "MSG00001.bin" diff --git a/src/RequestHandler/disconnectcontext.h b/src/RequestHandler/disconnectcontext.h new file mode 100644 index 0000000000..e43a49c0a0 --- /dev/null +++ b/src/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/RequestHandler/dllmain.cxx b/src/RequestHandler/dllmain.cxx new file mode 100644 index 0000000000..f4b476a856 --- /dev/null +++ b/src/RequestHandler/dllmain.cxx @@ -0,0 +1,340 @@ +// dllmain.cpp : Defines the entry point for the DLL application. +#include "precomp.hxx" +#include +#include + +BOOL g_fNsiApiNotSupported = FALSE; +BOOL g_fWebSocketSupported = FALSE; +BOOL g_fEnableReferenceCountTracing = FALSE; +BOOL g_fOutOfProcessInitialize = FALSE; +BOOL g_fOutOfProcessInitializeError = FALSE; +BOOL g_fWinHttpNonBlockingCallbackAvailable = 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; + + +VOID +InitializeGlobalConfiguration( + 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; + } + + // WebSocket is supported on Win8 and above only + // todo: test on win7 + g_fWebSocketSupported = IsWindows8OrGreater(); + +} + +// +// Global initialization routine for OutOfProcess +// +HRESULT +EnsureOutOfProcessInitializtion( IHttpServer* pServer) +{ + + DBG_ASSERT(pServer); + + HRESULT hr = S_OK; + BOOL fLocked = FALSE; + + g_pHttpServer = pServer; + + 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; + } + + // Initialze some global variables here + InitializeGlobalConfiguration(); + + g_hWinHttpModule = GetModuleHandle(TEXT("winhttp.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); + // Initialze some global variables here + InitializeGlobalConfiguration(); + break; + default: + break; + } + return TRUE; +} + +HRESULT +__stdcall +CreateApplication( + _In_ IHttpServer *pServer, + _In_ ASPNETCORE_CONFIG *pConfig, + _Out_ APPLICATION **ppApplication +) +{ + HRESULT hr = S_OK; + APPLICATION *pApplication = NULL; + + //REQUEST_HANDLER::StaticInitialize(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(pServer); + 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/RequestHandler/inprocess/inprocessapplication.cpp b/src/RequestHandler/inprocess/inprocessapplication.cpp new file mode 100644 index 0000000000..075287ec3d --- /dev/null +++ b/src/RequestHandler/inprocess/inprocessapplication.cpp @@ -0,0 +1,889 @@ +#include "..\precomp.hxx" + +typedef DWORD(*hostfxr_main_fn) (CONST DWORD argc, CONST WCHAR* argv[]); + +IN_PROCESS_APPLICATION* IN_PROCESS_APPLICATION::s_Application = NULL; + +IN_PROCESS_APPLICATION::IN_PROCESS_APPLICATION( + IHttpServer* pHttpServer, + ASPNETCORE_CONFIG* pConfig) : + APPLICATION(pHttpServer, pConfig), + m_ProcessExitCode(0), + m_fManagedAppLoaded(FALSE), + m_fLoadManagedAppError(FALSE), + m_fInitialized(FALSE), + m_fRecycleProcessCalled(FALSE), + m_hLogFileHandle(INVALID_HANDLE_VALUE), + m_fDoneStdRedirect(FALSE) +{ + // 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_fInitialized = TRUE; + m_status = APPLICATION_STATUS::RUNNING; +} + +IN_PROCESS_APPLICATION::~IN_PROCESS_APPLICATION() +{ + Recycle(); +} + +__override +VOID +IN_PROCESS_APPLICATION::ShutDown() +{ + //todo +} + +// This is the same function as before, TODO configrm if we need to change anything for configuration. +VOID +IN_PROCESS_APPLICATION::Recycle( + VOID +) +{ + if (m_fInitialized) + { + DWORD dwThreadStatus = 0; + DWORD dwTimeout = m_pConfig->QueryShutdownTimeLimitInMS(); + HANDLE handle = NULL; + WIN32_FIND_DATA fileData; + + 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, if logging is not enabled + handle = FindFirstFile(m_struLogFilePath.QueryStr(), &fileData); + if (handle != INVALID_HANDLE_VALUE && + fileData.nFileSizeHigh && + 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()); + } + + AcquireSRWLockExclusive(&m_srwLock); + + if (!m_pHttpServer->IsCommandLineLaunch() && + !m_fRecycleProcessCalled && + (m_pHttpServer->GetAdminManager() != NULL)) + { + // IIS scenario. + // notify IIS first so that new request will be routed to new worker process + m_pHttpServer->RecycleProcess(L"AspNetCore Recycle Process on Demand"); + } + + m_fRecycleProcessCalled = TRUE; + + // First call into the managed server and shutdown + if (m_ShutdownHandler != NULL) + { + m_ShutdownHandler(m_ShutdownHandlerContext); + m_ShutdownHandler = NULL; + } + + if (m_hThread != NULL && + GetExitCodeThread(m_hThread, &dwThreadStatus) != 0 && + dwThreadStatus == STILL_ACTIVE) + { + // wait for gracefullshut down, 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) + { + TerminateThread(m_hThread, STATUS_CONTROL_C_EXIT); + } + } + } + + CloseHandle(m_hThread); + m_hThread = NULL; + s_Application = NULL; + + ReleaseSRWLockExclusive(&m_srwLock); + if (m_pHttpServer && m_pHttpServer->IsCommandLineLaunch()) + { + // IISExpress scenario + // Can only call exit to terminate current process + exit(0); + } + } +} + +REQUEST_NOTIFICATION_STATUS +IN_PROCESS_APPLICATION::OnAsyncCompletion( + DWORD cbCompletion, + HRESULT hrCompletionStatus, + IN_PROCESS_HANDLER* pInProcessHandler +) +{ + + REQUEST_NOTIFICATION_STATUS dwRequestNotificationStatus = RQ_NOTIFICATION_CONTINUE; + + if (pInProcessHandler->QueryIsManagedRequestComplete()) + { + // means PostCompletion has been called and this is the associated callback. + dwRequestNotificationStatus = pInProcessHandler->QueryAsyncCompletionStatus(); + // TODO cleanup whatever disconnect listener there is + return dwRequestNotificationStatus; + } + else + { + // Call the managed handler for async completion. + return m_AsyncCompletionHandler(pInProcessHandler->QueryManagedHttpContext(), hrCompletionStatus, cbCompletion); + } +} + +REQUEST_NOTIFICATION_STATUS +IN_PROCESS_APPLICATION::OnExecuteRequest( + _In_ IHttpContext* pHttpContext, + _In_ IN_PROCESS_HANDLER* pInProcessHandler +) +{ + if (m_RequestHandler != NULL) + { + return m_RequestHandler(pInProcessHandler, m_RequestHandlerContext); + } + + // + // 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); + + return RQ_NOTIFICATION_FINISH_REQUEST; +} + +BOOL +IN_PROCESS_APPLICATION::DirectoryExists( + _In_ STRU *pstrPath +) +{ + WIN32_FILE_ATTRIBUTE_DATA data; + + if (pstrPath->IsEmpty()) + { + return false; + } + + return GetFileAttributesExW(pstrPath->QueryStr(), GetFileExInfoStandard, &data); +} + +BOOL +IN_PROCESS_APPLICATION::GetEnv( + _In_ PCWSTR pszEnvironmentVariable, + _Out_ STRU *pstrResult +) +{ + DWORD dwLength; + PWSTR pszBuffer = NULL; + BOOL fSucceeded = FALSE; + + if (pszEnvironmentVariable == NULL) + { + goto Finished; + } + pstrResult->Reset(); + dwLength = GetEnvironmentVariableW(pszEnvironmentVariable, NULL, 0); + + if (dwLength == 0) + { + goto Finished; + } + + pszBuffer = new WCHAR[dwLength]; + if (GetEnvironmentVariableW(pszEnvironmentVariable, pszBuffer, dwLength) == 0) + { + goto Finished; + } + + pstrResult->Copy(pszBuffer); + + fSucceeded = TRUE; + +Finished: + if (pszBuffer != NULL) { + delete[] pszBuffer; + } + return fSucceeded; +} + +VOID +IN_PROCESS_APPLICATION::FindDotNetFolders( + _In_ PCWSTR pszPath, + _Out_ std::vector *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); +} + +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; + + // Initialization complete + SetEvent(m_pInitalizeEvent); +} + +HRESULT +IN_PROCESS_APPLICATION::FindHighestDotNetVersion( + _In_ std::vector 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; +} + +VOID +IN_PROCESS_APPLICATION::SetStdOut( + VOID +) +{ + HRESULT hr = S_OK; + BOOL fLocked = FALSE; + STRU struPath; + + SYSTEMTIME systemTime; + SECURITY_ATTRIBUTES saAttr = { 0 }; + + if (!m_fDoneStdRedirect) + { + // Have not set stdout yet, redirect stdout to log file + AcquireSRWLockExclusive(&m_srwLock); + fLocked = TRUE; + if (!m_fDoneStdRedirect) + { + 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; + } + + saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); + saAttr.bInheritHandle = TRUE; + saAttr.lpSecurityDescriptor = NULL; + + m_hLogFileHandle = CreateFileW(m_struLogFilePath.QueryStr(), + 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; + } + + // + // 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()) + { + // + // SetStdHandle works as w3wp does not have Console + // Current process does not have a console + // + SetStdHandle(STD_ERROR_HANDLE, m_hLogFileHandle); + if (m_pConfig->QueryStdoutLogEnabled()) + { + SetStdHandle(STD_OUTPUT_HANDLE, m_hLogFileHandle); + // 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 + { + // The process has console, e.g., IIS Express scenario + CloseHandle(m_hLogFileHandle); + m_hLogFileHandle = INVALID_HANDLE_VALUE; + + if (m_pConfig->QueryStdoutLogEnabled()) + { + 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)); + } + // not 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; + } + else + { + // delete the file as log is disabled + WIN32_FIND_DATA fileData; + HANDLE handle = FindFirstFile(m_struLogFilePath.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_struLogFilePath.QueryStr()); + } + } + } + } + } + +Finished: + m_fDoneStdRedirect = TRUE; + if (fLocked) + { + ReleaseSRWLockExclusive(&m_srwLock); + } + if (FAILED(hr) && m_pConfig->QueryStdoutLogEnabled()) + { + //todo log an warning + //STRU strEventMsg; + //LPCWSTR apsz[1]; + + //if (SUCCEEDED(strEventMsg.SafeSnwprintf( + // ASPNETCORE_EVENT_INVALID_STDOUT_LOG_FILE_MSG, + // m_struLogFilePath.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); + // } + //} + } +} + +// Will be called by the inprocesshandler +HRESULT +IN_PROCESS_APPLICATION::LoadManagedApplication +( + VOID +) +{ + HRESULT hr = S_OK; + DWORD dwTimeout; + DWORD dwResult; + BOOL fLocked = FALSE; + //PCWSTR apsz[1]; + //STACK_STRU(strEventMsg, 256); + + if (m_fManagedAppLoaded || m_fLoadManagedAppError) + { + // Core CLR has already been loaded. + // Cannot load more than once even there was a failure + goto Finished; + } + + // Set up stdout redirect + SetStdOut(); + + AcquireSRWLockExclusive(&m_srwLock); + fLocked = TRUE; + if (m_fManagedAppLoaded || m_fLoadManagedAppError) + { + 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_fManagedAppLoaded = TRUE; + +Finished: + if (fLocked) + { + ReleaseSRWLockExclusive(&m_srwLock); + } + + if (FAILED(hr)) + { + // Question: in case of application loading failure, should we allow retry on + // following request or block the activation at all + m_fLoadManagedAppError = FALSE; // m_hThread != NULL ? + + // TODO + //if (SUCCEEDED(strEventMsg.SafeSnwprintf( + // ASPNETCORE_EVENT_LOAD_CLR_FALIURE_MSG, + // m_pConfiguration->QueryApplicationPath()->QueryStr(), + // m_pConfiguration->QueryApplicationPhysicalPath()->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_LOAD_CLR_FALIURE, + // NULL, + // 1, + // 0, + // apsz, + // NULL); + // } + //} + } + return hr; +} + +// static +VOID +IN_PROCESS_APPLICATION::ExecuteAspNetCoreProcess( + _In_ LPVOID pContext +) +{ + + IN_PROCESS_APPLICATION *pApplication = (IN_PROCESS_APPLICATION*)pContext; + DBG_ASSERT(pApplication != NULL); + 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::ExecuteApplication( + VOID +) +{ + HRESULT hr = S_OK; + + STRU strFullPath; + STRU strDotnetExeLocation; + STRU strHostFxrSearchExpression; + STRU strDotnetFolderLocation; + STRU strHighestDotnetVersion; + STRU strApplicationFullPath; + PWSTR strDelimeterContext = NULL; + PCWSTR pszDotnetExeLocation = NULL; + PCWSTR pszDotnetExeString(L"dotnet.exe"); + DWORD dwCopyLength; + HMODULE hModule; + PCWSTR argv[2]; + hostfxr_main_fn pProc; + std::vector vVersionFolders; + bool fFound = FALSE; + + // Get the System PATH value. + if (!GetEnv(L"PATH", &strFullPath)) + { + hr = ERROR_BAD_ENVIRONMENT; + goto Finished; + } + + // Split on ';', checking to see if dotnet.exe exists in any folders. + pszDotnetExeLocation = wcstok_s(strFullPath.QueryStr(), L";", &strDelimeterContext); + + while (pszDotnetExeLocation != NULL) + { + dwCopyLength = (DWORD) wcsnlen_s(pszDotnetExeLocation, 260); + if (dwCopyLength == 0) + { + continue; + } + + // We store both the exe and folder locations as we eventually need to check inside of host\\fxr + // which doesn't need the dotnet.exe portion of the string + // TODO consider reducing allocations. + strDotnetExeLocation.Reset(); + strDotnetFolderLocation.Reset(); + hr = strDotnetExeLocation.Copy(pszDotnetExeLocation, dwCopyLength); + if (FAILED(hr)) + { + goto Finished; + } + + hr = strDotnetFolderLocation.Copy(pszDotnetExeLocation, dwCopyLength); + if (FAILED(hr)) + { + goto Finished; + } + + if (dwCopyLength > 0 && pszDotnetExeLocation[dwCopyLength - 1] != L'\\') + { + hr = strDotnetExeLocation.Append(L"\\"); + if (FAILED(hr)) + { + goto Finished; + } + } + + hr = strDotnetExeLocation.Append(pszDotnetExeString); + if (FAILED(hr)) + { + goto Finished; + } + + if (PathFileExists(strDotnetExeLocation.QueryStr())) + { + // means we found the folder with a dotnet.exe inside of it. + fFound = TRUE; + break; + } + pszDotnetExeLocation = wcstok_s(NULL, L";", &strDelimeterContext); + } + if (!fFound) + { + // could not find dotnet.exe, error out + hr = ERROR_BAD_ENVIRONMENT; + } + + hr = strDotnetFolderLocation.Append(L"\\host\\fxr"); + if (FAILED(hr)) + { + goto Finished; + } + + if (!DirectoryExists(&strDotnetFolderLocation)) + { + // error, not found the folder + hr = ERROR_BAD_ENVIRONMENT; + goto Finished; + } + + // Find all folders under host\\fxr\\ for version numbers. + hr = strHostFxrSearchExpression.Copy(strDotnetFolderLocation); + if (FAILED(hr)) + { + goto Finished; + } + + hr = strHostFxrSearchExpression.Append(L"\\*"); + if (FAILED(hr)) + { + goto Finished; + } + + // As we use the logic from core-setup, we are opting to use std here. + // TODO remove all uses of std? + FindDotNetFolders(strHostFxrSearchExpression.QueryStr(), &vVersionFolders); + + if (vVersionFolders.size() == 0) + { + // no core framework was found + hr = ERROR_BAD_ENVIRONMENT; + goto Finished; + } + + hr = FindHighestDotNetVersion(vVersionFolders, &strHighestDotnetVersion); + if (FAILED(hr)) + { + goto Finished; + } + hr = strDotnetFolderLocation.Append(L"\\"); + if (FAILED(hr)) + { + goto Finished; + } + + hr = strDotnetFolderLocation.Append(strHighestDotnetVersion.QueryStr()); + if (FAILED(hr)) + { + goto Finished; + + } + + hr = strDotnetFolderLocation.Append(L"\\hostfxr.dll"); + if (FAILED(hr)) + { + goto Finished; + } + + hModule = LoadLibraryW(strDotnetFolderLocation.QueryStr()); + + 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; // better hrresult? + goto Finished; + } + + // The first argument is mostly ignored + argv[0] = strDotnetExeLocation.QueryStr(); + UTILITY::ConvertPathToFullPath(m_pConfig->QueryArguments()->QueryStr(), + m_pConfig->QueryApplicationPhysicalPath()->QueryStr(), + &strApplicationFullPath); + argv[1] = strApplicationFullPath.QueryStr(); + + // 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; + + RunDotnetApplication(argv, pProc); + +Finished: + // + // this method is called by the background thread and should never exit unless shutdown + // + if (!m_fRecycleProcessCalled) + { + //STRU strEventMsg; + //LPCWSTR apsz[1]; + //if (SUCCEEDED(strEventMsg.SafeSnwprintf( + // ASPNETCORE_EVENT_INPROCESS_THREAD_EXIT_MSG, + // m_pConfig->QueryApplicationPath()->QueryStr(), + // m_pConfig->QueryApplicationPhysicalPath()->QueryStr(), + // m_ProcessExitCode + //))) + //{ + // 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_INPROCESS_THREAD_EXIT, + // NULL, + // 1, + // 0, + // apsz, + // NULL); + // } + // // error. the thread exits after application started + // // Question: should we shutdown current worker process or keep the application in failure state? + // // for now, we reccylce to keep the same behavior as that of out-of-process + //} + if (m_fManagedAppLoaded) + { + Recycle(); + } + } + return hr; +} + +// +// 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. +// +HRESULT +IN_PROCESS_APPLICATION::RunDotnetApplication(PCWSTR* argv, hostfxr_main_fn pProc) +{ + HRESULT hr = S_OK; + __try + { + m_ProcessExitCode = pProc(2, argv); + } + __except (FilterException(GetExceptionCode(), GetExceptionInformation())) + { + // TODO Log error message here. + hr = E_FAIL; + } + 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/AspNetCore/Inc/inprocessapplication.h b/src/RequestHandler/inprocess/inprocessapplication.h similarity index 68% rename from src/AspNetCore/Inc/inprocessapplication.h rename to src/RequestHandler/inprocess/inprocessapplication.h index 88aeb1c2fd..faa2d374b2 100644 --- a/src/AspNetCore/Inc/inprocessapplication.h +++ b/src/RequestHandler/inprocess/inprocessapplication.h @@ -4,37 +4,21 @@ #pragma once typedef void(*request_handler_cb) (int error, IHttpContext* pHttpContext, void* pvCompletionContext); -typedef REQUEST_NOTIFICATION_STATUS(*PFN_REQUEST_HANDLER) (IHttpContext* pHttpContext, void* pvRequstHandlerContext); +typedef REQUEST_NOTIFICATION_STATUS(*PFN_REQUEST_HANDLER) (IN_PROCESS_HANDLER* pInProcessHandler, void* pvRequestHandlerContext); typedef BOOL(*PFN_SHUTDOWN_HANDLER) (void* pvShutdownHandlerContext); typedef REQUEST_NOTIFICATION_STATUS(*PFN_MANAGED_CONTEXT_HANDLER)(void *pvManagedHttpContext, HRESULT hrCompletionStatus, DWORD cbCompletion); - -#include "application.h" +typedef DWORD(*hostfxr_main_fn) (CONST DWORD argc, CONST WCHAR* argv[]); class IN_PROCESS_APPLICATION : public APPLICATION { public: - IN_PROCESS_APPLICATION(); + IN_PROCESS_APPLICATION(IHttpServer* pHttpServer, ASPNETCORE_CONFIG *pConfig); ~IN_PROCESS_APPLICATION(); __override - HRESULT - Initialize(_In_ APPLICATION_MANAGER* pApplicationManager, - _In_ ASPNETCORE_CONFIG* pConfiguration); - VOID - Recycle( - VOID - ); - - __override - VOID OnAppOfflineHandleChange(); - - __override - REQUEST_NOTIFICATION_STATUS - ExecuteRequest( - _In_ IHttpContext* pHttpContext - ); + ShutDown(); VOID SetCallbackHandles( @@ -45,6 +29,11 @@ public: _In_ VOID* pvShutdownHandlerContext ); + VOID + Recycle( + VOID + ); + // Executes the .NET Core process HRESULT ExecuteApplication( @@ -53,14 +42,31 @@ public: HRESULT LoadManagedApplication( - VOID - ); + VOID + ); REQUEST_NOTIFICATION_STATUS OnAsyncCompletion( - IHttpContext* pHttpContext, DWORD cbCompletion, - HRESULT hrCompletionStatus + HRESULT hrCompletionStatus, + IN_PROCESS_HANDLER* pInProcessHandler + ); + + REQUEST_NOTIFICATION_STATUS + OnExecuteRequest + ( + IHttpContext* pHttpContext, + IN_PROCESS_HANDLER* pInProcessHandler + ); + + static + INT + FilterException(unsigned int code, struct _EXCEPTION_POINTERS *ep); + + HRESULT + RunDotnetApplication( + PCWSTR* argv, + hostfxr_main_fn pProc ); static @@ -72,14 +78,13 @@ public: return s_Application; } - private: // Thread executing the .NET Core process HANDLE m_hThread; // The request handler callback from managed code PFN_REQUEST_HANDLER m_RequestHandler; - VOID* m_RequstHandlerContext; + VOID* m_RequestHandlerContext; // The shutdown handler callback from managed code PFN_SHUTDOWN_HANDLER m_ShutdownHandler; @@ -90,6 +95,10 @@ private: // The event that gets triggered when managed initialization is complete HANDLE m_pInitalizeEvent; + // The std log file handle + HANDLE m_hLogFileHandle; + STRU m_struLogFilePath; + // The exit code of the .NET Core process INT m_ProcessExitCode; @@ -97,9 +106,20 @@ private: BOOL m_fLoadManagedAppError; BOOL m_fInitialized; BOOL m_fIsWebSocketsConnection; + BOOL m_fDoneStdRedirect; + BOOL m_fRecycleProcessCalled; + + FILE* m_pStdFile; + STTIMER m_Timer; + SRWLOCK m_srwLock; static IN_PROCESS_APPLICATION* s_Application; + VOID + SetStdOut( + VOID + ); + static VOID FindDotNetFolders( @@ -117,7 +137,7 @@ private: static BOOL DirectoryExists( - _In_ STRU *pstrPath //todo: this does not need to be stru, can be PCWSTR + _In_ STRU *pstrPath //todo: this does not need to be stru, can be PCWSTR ); static BOOL @@ -131,5 +151,4 @@ private: ExecuteAspNetCoreProcess( _In_ LPVOID pContext ); - }; \ No newline at end of file diff --git a/src/RequestHandler/inprocess/inprocesshandler.cpp b/src/RequestHandler/inprocess/inprocesshandler.cpp new file mode 100644 index 0000000000..92e41649cc --- /dev/null +++ b/src/RequestHandler/inprocess/inprocesshandler.cpp @@ -0,0 +1,146 @@ +#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 +) +{ + HRESULT hr; + if (FAILED(hrCompletionStatus)) + { + return RQ_NOTIFICATION_FINISH_REQUEST; + } + else + { + // For now we are assuming we are in our own self contained box. + // TODO refactor Finished and Failure sections to handle in process and out of process failure. + // TODO verify that websocket's OnAsyncCompletion is not calling this. + IN_PROCESS_APPLICATION* application = (IN_PROCESS_APPLICATION*)m_pApplication; + if (application == NULL) + { + hr = E_FAIL; + return RQ_NOTIFICATION_FINISH_REQUEST; + } + + 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::SetManangedHttpContext( + PVOID pManagedHttpContext +) +{ + m_pManagedHttpContext = pManagedHttpContext; +} \ No newline at end of file diff --git a/src/RequestHandler/inprocess/inprocesshandler.h b/src/RequestHandler/inprocess/inprocesshandler.h new file mode 100644 index 0000000000..3e976d0b95 --- /dev/null +++ b/src/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 + SetManangedHttpContext( + 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/AspNetCore/Src/managedexports.cxx b/src/RequestHandler/managedexports.cxx similarity index 68% rename from src/AspNetCore/Src/managedexports.cxx rename to src/RequestHandler/managedexports.cxx index d05df89705..464f31e2ee 100644 --- a/src/AspNetCore/Src/managedexports.cxx +++ b/src/RequestHandler/managedexports.cxx @@ -28,83 +28,64 @@ register_callbacks( EXTERN_C __MIDL_DECLSPEC_DLLEXPORT HTTP_REQUEST* http_get_raw_request( - _In_ IHttpContext* pHttpContext + _In_ IN_PROCESS_HANDLER* pInProcessHandler ) { - return pHttpContext->GetRequest()->GetRawHttpRequest(); + return pInProcessHandler->QueryHttpContext()->GetRequest()->GetRawHttpRequest(); } EXTERN_C __MIDL_DECLSPEC_DLLEXPORT HTTP_RESPONSE* http_get_raw_response( - _In_ IHttpContext* pHttpContext + _In_ IN_PROCESS_HANDLER* pInProcessHandler ) { - return pHttpContext->GetResponse()->GetRawHttpResponse(); + return pInProcessHandler->QueryHttpContext()->GetResponse()->GetRawHttpResponse(); } EXTERN_C __MIDL_DECLSPEC_DLLEXPORT VOID http_set_response_status_code( - _In_ IHttpContext* pHttpContext, + _In_ IN_PROCESS_HANDLER* pInProcessHandler, _In_ USHORT statusCode, _In_ PCSTR pszReason ) { - pHttpContext->GetResponse()->SetStatus(statusCode, pszReason); + pInProcessHandler->QueryHttpContext()->GetResponse()->SetStatus(statusCode, pszReason); } EXTERN_C __MIDL_DECLSPEC_DLLEXPORT HRESULT http_post_completion( - _In_ IHttpContext* pHttpContext, + _In_ IN_PROCESS_HANDLER* pInProcessHandler, DWORD cbBytes ) { - return pHttpContext->PostCompletion(cbBytes); + return pInProcessHandler->QueryHttpContext()->PostCompletion(cbBytes); } EXTERN_C __MIDL_DECLSPEC_DLLEXPORT HRESULT http_set_completion_status( - _In_ IHttpContext* pHttpContext, - REQUEST_NOTIFICATION_STATUS requestNotificationStatus + _In_ IN_PROCESS_HANDLER* pInProcessHandler, + _In_ REQUEST_NOTIFICATION_STATUS requestNotificationStatus ) { HRESULT hr = S_OK; - IN_PROCESS_STORED_CONTEXT* pInProcessStoredContext = NULL; - hr = IN_PROCESS_STORED_CONTEXT::GetInProcessStoredContext( - pHttpContext, - &pInProcessStoredContext - ); - - if (FAILED(hr)) - { - return hr; - } - pInProcessStoredContext->IndicateManagedRequestComplete(); - pInProcessStoredContext->SetAsyncCompletionStatus(requestNotificationStatus); + pInProcessHandler->IndicateManagedRequestComplete(); + pInProcessHandler->SetAsyncCompletionStatus(requestNotificationStatus); return hr; } EXTERN_C __MIDL_DECLSPEC_DLLEXPORT HRESULT http_set_managed_context( - _In_ IHttpContext* pHttpContext, + _In_ IN_PROCESS_HANDLER* pInProcessHandler, _In_ PVOID pvManagedContext ) { - HRESULT hr; - IN_PROCESS_STORED_CONTEXT* pInProcessStoredContext = new IN_PROCESS_STORED_CONTEXT(pHttpContext, pvManagedContext); - if (pInProcessStoredContext == NULL) - { - return E_OUTOFMEMORY; - } - - hr = IN_PROCESS_STORED_CONTEXT::SetInProcessStoredContext(pHttpContext, pInProcessStoredContext); - if (hr == HRESULT_FROM_WIN32(ERROR_ALREADY_ASSIGNED)) - { - hr = S_OK; - } + // todo: should we consider changing the signature + HRESULT hr = S_OK; + pInProcessHandler->SetManangedHttpContext(pvManagedContext); return hr; } @@ -112,11 +93,11 @@ http_set_managed_context( EXTERN_C __MIDL_DECLSPEC_DLLEXPORT VOID http_indicate_completion( - _In_ IHttpContext* pHttpContext, + _In_ IN_PROCESS_HANDLER* pInProcessHandler, _In_ REQUEST_NOTIFICATION_STATUS notificationStatus ) { - pHttpContext->IndicateCompletion(notificationStatus); + pInProcessHandler->QueryHttpContext()->IndicateCompletion(notificationStatus); } EXTERN_C __MIDL_DECLSPEC_DLLEXPORT @@ -153,7 +134,7 @@ http_get_application_properties( { ASPNETCORE_CONFIG* pConfiguration = NULL; IN_PROCESS_APPLICATION* pApplication = IN_PROCESS_APPLICATION::GetInstance(); - + if (pApplication == NULL) { return E_FAIL; @@ -161,7 +142,7 @@ http_get_application_properties( pConfiguration = pApplication->QueryConfig(); - pIISCofigurationData->pwzFullApplicationPath = SysAllocString(pConfiguration->QueryApplicationFullPath()->QueryStr()); + pIISCofigurationData->pwzFullApplicationPath = SysAllocString(pConfiguration->QueryApplicationPhysicalPath()->QueryStr()); pIISCofigurationData->pwzVirtualApplicationPath = SysAllocString(pConfiguration->QueryApplicationVirtualPath()->QueryStr()); pIISCofigurationData->fWindowsAuthEnabled = pConfiguration->QueryWindowsAuthEnabled(); pIISCofigurationData->fBasicAuthEnabled = pConfiguration->QueryBasicAuthEnabled(); @@ -173,7 +154,7 @@ http_get_application_properties( EXTERN_C __MIDL_DECLSPEC_DLLEXPORT HRESULT http_read_request_bytes( - _In_ IHttpContext* pHttpContext, + _In_ IN_PROCESS_HANDLER* pInProcessHandler, _Out_ CHAR* pvBuffer, _In_ DWORD dwCbBuffer, _Out_ DWORD* pdwBytesReceived, @@ -182,7 +163,7 @@ http_read_request_bytes( { HRESULT hr; - if (pHttpContext == NULL) + if (pInProcessHandler == NULL) { return E_FAIL; } @@ -190,7 +171,7 @@ http_read_request_bytes( { return E_FAIL; } - IHttpRequest *pHttpRequest = (IHttpRequest*)pHttpContext->GetRequest(); + IHttpRequest *pHttpRequest = (IHttpRequest*)pInProcessHandler->QueryHttpContext()->GetRequest(); BOOL fAsync = TRUE; @@ -213,13 +194,13 @@ http_read_request_bytes( EXTERN_C __MIDL_DECLSPEC_DLLEXPORT HRESULT http_write_response_bytes( - _In_ IHttpContext* pHttpContext, + _In_ IN_PROCESS_HANDLER* pInProcessHandler, _In_ HTTP_DATA_CHUNK* pDataChunks, _In_ DWORD dwChunks, _In_ BOOL* pfCompletionExpected ) { - IHttpResponse *pHttpResponse = (IHttpResponse*)pHttpContext->GetResponse(); + IHttpResponse *pHttpResponse = (IHttpResponse*)pInProcessHandler->QueryHttpContext()->GetResponse(); BOOL fAsync = TRUE; BOOL fMoreData = TRUE; DWORD dwBytesSent = 0; @@ -238,11 +219,11 @@ http_write_response_bytes( EXTERN_C __MIDL_DECLSPEC_DLLEXPORT HRESULT http_flush_response_bytes( - _In_ IHttpContext* pHttpContext, + _In_ IN_PROCESS_HANDLER* pInProcessHandler, _Out_ BOOL* pfCompletionExpected ) { - IHttpResponse *pHttpResponse = (IHttpResponse*)pHttpContext->GetResponse(); + IHttpResponse *pHttpResponse = (IHttpResponse*)pInProcessHandler->QueryHttpContext()->GetResponse(); BOOL fAsync = TRUE; BOOL fMoreData = TRUE; @@ -259,7 +240,7 @@ http_flush_response_bytes( EXTERN_C __MIDL_DECLSPEC_DLLEXPORT HRESULT http_websockets_read_bytes( - _In_ IHttpContext* pHttpContext, + _In_ IN_PROCESS_HANDLER* pInProcessHandler, _In_ CHAR* pvBuffer, _In_ DWORD cbBuffer, _In_ PFN_ASYNC_COMPLETION pfnCompletionCallback, @@ -268,7 +249,7 @@ http_websockets_read_bytes( _In_ BOOL* pfCompletionPending ) { - IHttpRequest3 *pHttpRequest = (IHttpRequest3*)pHttpContext->GetRequest(); + IHttpRequest3 *pHttpRequest = (IHttpRequest3*)pInProcessHandler->QueryHttpContext()->GetRequest(); BOOL fAsync = TRUE; @@ -293,7 +274,7 @@ http_websockets_read_bytes( EXTERN_C __MIDL_DECLSPEC_DLLEXPORT HRESULT http_websockets_write_bytes( - _In_ IHttpContext* pHttpContext, + _In_ IN_PROCESS_HANDLER* pInProcessHandler, _In_ HTTP_DATA_CHUNK* pDataChunks, _In_ DWORD dwChunks, _In_ PFN_ASYNC_COMPLETION pfnCompletionCallback, @@ -301,7 +282,7 @@ http_websockets_write_bytes( _In_ BOOL* pfCompletionExpected ) { - IHttpResponse2 *pHttpResponse = (IHttpResponse2*)pHttpContext->GetResponse(); + IHttpResponse2 *pHttpResponse = (IHttpResponse2*)pInProcessHandler->QueryHttpContext()->GetResponse(); BOOL fAsync = TRUE; BOOL fMoreData = TRUE; @@ -323,13 +304,13 @@ http_websockets_write_bytes( EXTERN_C __MIDL_DECLSPEC_DLLEXPORT HRESULT http_websockets_flush_bytes( - _In_ IHttpContext* pHttpContext, + _In_ IN_PROCESS_HANDLER* pInProcessHandler, _In_ PFN_ASYNC_COMPLETION pfnCompletionCallback, _In_ VOID* pvCompletionContext, _In_ BOOL* pfCompletionExpected ) { - IHttpResponse2 *pHttpResponse = (IHttpResponse2*)pHttpContext->GetResponse(); + IHttpResponse2 *pHttpResponse = (IHttpResponse2*)pInProcessHandler->QueryHttpContext()->GetResponse(); BOOL fAsync = TRUE; BOOL fMoreData = TRUE; @@ -348,16 +329,16 @@ http_websockets_flush_bytes( EXTERN_C __MIDL_DECLSPEC_DLLEXPORT HRESULT http_enable_websockets( - _In_ IHttpContext* pHttpContext + _In_ IN_PROCESS_HANDLER* pInProcessHandler ) { - if (!g_fWebSocketSupported) - { - return E_FAIL; - } + //if (!g_fWebSocketSupported) + //{ + // return E_FAIL; + //} - ((IHttpContext3*)pHttpContext)->EnableFullDuplex(); - ((IHttpResponse2*)pHttpContext->GetResponse())->DisableBuffering(); + ((IHttpContext3*)pInProcessHandler->QueryHttpContext())->EnableFullDuplex(); + ((IHttpResponse2*)pInProcessHandler->QueryHttpContext()->GetResponse())->DisableBuffering(); return S_OK; } @@ -365,51 +346,50 @@ http_enable_websockets( EXTERN_C __MIDL_DECLSPEC_DLLEXPORT HRESULT http_cancel_io( - _In_ IHttpContext* pHttpContext + _In_ IN_PROCESS_HANDLER* pInProcessHandler ) { - return pHttpContext->CancelIo(); + return pInProcessHandler->QueryHttpContext()->CancelIo(); } EXTERN_C __MIDL_DECLSPEC_DLLEXPORT HRESULT http_response_set_unknown_header( - _In_ IHttpContext* pHttpContext, + _In_ IN_PROCESS_HANDLER* pInProcessHandler, _In_ PCSTR pszHeaderName, _In_ PCSTR pszHeaderValue, _In_ USHORT usHeaderValueLength, _In_ BOOL fReplace ) { - return pHttpContext->GetResponse()->SetHeader( pszHeaderName, pszHeaderValue, usHeaderValueLength, fReplace ); + return pInProcessHandler->QueryHttpContext()->GetResponse()->SetHeader(pszHeaderName, pszHeaderValue, usHeaderValueLength, fReplace); } EXTERN_C __MIDL_DECLSPEC_DLLEXPORT HRESULT http_response_set_known_header( - _In_ IHttpContext* pHttpContext, + _In_ IN_PROCESS_HANDLER* pInProcessHandler, _In_ HTTP_HEADER_ID dwHeaderId, _In_ PCSTR pszHeaderValue, _In_ USHORT usHeaderValueLength, _In_ BOOL fReplace ) { - return pHttpContext->GetResponse()->SetHeader( dwHeaderId, pszHeaderValue, usHeaderValueLength, fReplace ); + return pInProcessHandler->QueryHttpContext()->GetResponse()->SetHeader(dwHeaderId, pszHeaderValue, usHeaderValueLength, fReplace); } EXTERN_C __MIDL_DECLSPEC_DLLEXPORT HRESULT http_get_authentication_information( - _In_ IHttpContext* pHttpContext, + _In_ IN_PROCESS_HANDLER* pInProcessHandler, _Out_ BSTR* pstrAuthType, _Out_ VOID** pvToken ) { - *pstrAuthType = SysAllocString(pHttpContext->GetUser()->GetAuthenticationType()); - *pvToken = pHttpContext->GetUser()->GetPrimaryToken(); + *pstrAuthType = SysAllocString(pInProcessHandler->QueryHttpContext()->GetUser()->GetAuthenticationType()); + *pvToken = pInProcessHandler->QueryHttpContext()->GetUser()->GetPrimaryToken(); return S_OK; } - // End of export \ No newline at end of file diff --git a/src/AspNetCore/Src/forwarderconnection.cxx b/src/RequestHandler/outofprocess/forwarderconnection.cxx similarity index 93% rename from src/AspNetCore/Src/forwarderconnection.cxx rename to src/RequestHandler/outofprocess/forwarderconnection.cxx index 9dd853992d..99990f938c 100644 --- a/src/AspNetCore/Src/forwarderconnection.cxx +++ b/src/RequestHandler/outofprocess/forwarderconnection.cxx @@ -1,7 +1,7 @@ // 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 "..\precomp.hxx" FORWARDER_CONNECTION::FORWARDER_CONNECTION( VOID @@ -23,7 +23,7 @@ FORWARDER_CONNECTION::Initialize( goto Finished; } - m_hConnection = WinHttpConnect(FORWARDING_HANDLER::sm_hSession, + m_hConnection = WinHttpConnect(g_hWinhttpSession, L"127.0.0.1", (USHORT) dwPort, 0); diff --git a/src/AspNetCore/Inc/forwarderconnection.h b/src/RequestHandler/outofprocess/forwarderconnection.h similarity index 100% rename from src/AspNetCore/Inc/forwarderconnection.h rename to src/RequestHandler/outofprocess/forwarderconnection.h diff --git a/src/AspNetCore/Src/forwardinghandler.cxx b/src/RequestHandler/outofprocess/forwardinghandler.cpp similarity index 60% rename from src/AspNetCore/Src/forwardinghandler.cxx rename to src/RequestHandler/outofprocess/forwardinghandler.cpp index 6eee4af412..293c56bfd5 100644 --- a/src/AspNetCore/Src/forwardinghandler.cxx +++ b/src/RequestHandler/outofprocess/forwardinghandler.cpp @@ -1,85 +1,55 @@ -// 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 -#include - +#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 STR_ANCM_CHILDREQUEST "ANCM_WasCreateProcessFailure" -HINTERNET FORWARDING_HANDLER::sm_hSession = NULL; -STRU FORWARDING_HANDLER::sm_strErrorFormat; -HANDLE FORWARDING_HANDLER::sm_hEventLog = NULL; +#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 APPLICATION * pApplication -) : m_Signature(FORWARDING_HANDLER_SIGNATURE), -m_cRefs(1), -m_pW3Context(pW3Context), -m_pApplication(pApplication), -m_pChildRequestContext(NULL), -m_hRequest(NULL), -m_fHandleClosedDueToClient(FALSE), -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_pAppOfflineHtm(NULL), -m_fErrorHandled(FALSE), -m_fWebSocketUpgrade(FALSE), -m_fFinishRequest(FALSE), -m_fClientDisconnected(FALSE), -m_fHasError(FALSE) + _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_fHandleClosedDueToClient(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) { -#ifdef DEBUG - DBGPRINTF((DBG_CONTEXT, - "FORWARDING_HANDLER::FORWARDING_HANDLER \n")); -#endif // DEBUG - - InitializeSRWLock(&m_RequestLock); + DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO, + "FORWARDING_HANDLER::FORWARDING_HANDLER"); } FORWARDING_HANDLER::~FORWARDING_HANDLER( - VOID ) { // // Destructor has started. // -#ifdef DEBUG - DBGPRINTF((DBG_CONTEXT, - "FORWARDING_HANDLER::~FORWARDING_HANDLER \n")); -#endif // DEBUG - m_Signature = FORWARDING_HANDLER_SIGNATURE_FREE; + DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO, + "FORWARDING_HANDLER::~FORWARDING_HANDLER"); // // RemoveRequest() should already have been called and m_pDisconnect // has been freed or m_pDisconnect was never initialized. @@ -91,6 +61,12 @@ FORWARDING_HANDLER::~FORWARDING_HANDLER( // DBG_ASSERT(m_pDisconnect == NULL); + if (m_pDisconnect != NULL) + { + m_pDisconnect->ResetHandler(); + m_pDisconnect = NULL; + } + FreeResponseBuffers(); if (m_pWebSocket) @@ -98,542 +74,693 @@ FORWARDING_HANDLER::~FORWARDING_HANDLER( m_pWebSocket->Terminate(); m_pWebSocket = NULL; } +} - if (m_pChildRequestContext != 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); + + // override Protocol related config from aspNetCore config + pProtocol->OverrideConfig(m_pApplication->QueryConfig()); + + // check connection + pClientConnection = m_pW3Context->GetConnection(); + if (pClientConnection == NULL || + !pClientConnection->IsConnected()) { - m_pChildRequestContext->ReleaseClonedContext(); - m_pChildRequestContext = NULL; + hr = HRESULT_FROM_WIN32(WSAECONNRESET); + goto Failure; + } + + pApplication = static_cast (m_pApplication); + if (pApplication == NULL) + { + hr = E_INVALIDARG; + goto Finished; + } + + 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 (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, + pServerProcess); + if (FAILED(hr)) + { + goto Failure; + } + + // Set client disconnect callback contract with IIS + m_pDisconnect = static_cast( + 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; } // - // The m_pDisconnect must have happened by now the m_pServer - // is the only cleanup left. + // Begins normal request handling. Send request to server. // + m_RequestStatus = FORWARDER_SENDING_REQUEST; - RemoveRequest(); + // + // 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(static_cast(this)))) + { + hr = HRESULT_FROM_WIN32(GetLastError()); + DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO, + "FORWARDING_HANDLER::OnExecuteRequestHandler, Send request failed"); + + // 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; + + //disbale client disconnect callback + if (m_pDisconnect != NULL) + { + if (fHandleSet) + { + m_pDisconnect->ResetHandler(); + } + m_pDisconnect->CleanupStoredContext(); + m_pDisconnect = NULL; + } + + pResponse->DisableKernelCache(); + pResponse->GetRawHttpResponse()->EntityChunkCount = 0; + if (hr == HRESULT_FROM_WIN32(WSAECONNRESET)) + { + pResponse->SetStatus(400, "Bad Request", 0, hr); + } + else + { + 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); + } + // + // 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); + } + 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; + + 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(static_cast(cbCompletion)), + reinterpret_cast(static_cast(hrCompletionStatus))); + } + + if (TlsGetValue(g_dwTlsIndex) != this) + { + DBG_ASSERT(TlsGetValue(g_dwTlsIndex) == NULL); + AcquireSRWLockShared(&m_RequestLock); + TlsSetValue(g_dwTlsIndex, this); + DBG_ASSERT(TlsGetValue(g_dwTlsIndex) == this); + + fLocked = TRUE; + } + + if (m_hRequest == NULL) + { + // Request is Done + if (m_fFinishRequest) + { + if (m_fHasError) + { + retVal = RQ_NOTIFICATION_FINISH_REQUEST; + } + else + { + retVal = RQ_NOTIFICATION_CONTINUE; + } + goto Finished; + } + + fClientError = m_fHandleClosedDueToClient; + goto Failure; + } + + // + // Begins normal completion handling. There is already a shared acquired + // for protecting the WinHTTP request handle from being closed. + // + switch (m_RequestStatus) + { + case 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 Finished; + } + + hr = m_pWebSocket->ProcessRequest(this, m_pW3Context, m_hRequest); + if (FAILED(hr)) + { + goto Failure; + } + + // + // WebSocket upgrade is successful. Close the WinHttpRequest Handle + // + fClosed = WinHttpCloseHandle(m_hRequest); + + DBG_ASSERT(fClosed); + if (fClosed) + { + m_hRequest = NULL; + } + else + { + hr = HRESULT_FROM_WIN32(GetLastError()); + goto Failure; + } + break; + + 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); + 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: + + m_fHasError = TRUE; + m_RequestStatus = FORWARDER_DONE; + + //disbale client disconnect callback + if (m_pDisconnect != NULL) + { + m_pDisconnect->ResetHandler(); + m_pDisconnect = NULL; + } + + // + // Do the right thing based on where the error originated from. + // + IHttpResponse *pResponse = m_pW3Context->GetResponse(); + pResponse->DisableKernelCache(); + pResponse->GetRawHttpResponse()->EntityChunkCount = 0; + + if (fClientError) + { + 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_hModule, +// IDS_SERVER_ERROR, +// strDescription.QueryStr(), +// strDescription.QuerySizeCCH());*/ +// } +// +// (VOID)strDescription.SyncWithBuffer(); +// if (strDescription.QueryCCH() != 0) +// { +// pResponse->SetErrorDescription( +// strDescription.QueryStr(), +// strDescription.QueryCCH(), +// FALSE); +// } + } + + // + // Finish the request on failure. + // Let IIS pipeline continue only after receiving handle close callback + // from WinHttp. This ensures no more callback from WinHttp + // 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, NULL, NULL); - WinHttpCloseHandle(m_hRequest); - m_hRequest = NULL; + if (WinHttpCloseHandle(m_hRequest)) + { + m_hRequest = NULL; + } + else + { + // Failed to close the handle + // which should never happen as we registered a callback with WinHttp + // For this unexpected failure, let conitnue IIS pipeline + /* retVal = RQ_NOTIFICATION_FINISH_REQUEST; + DebugBreak();*/ + } } + retVal = RQ_NOTIFICATION_PENDING; - if (m_pApplication != NULL) +Finished: + if (fLocked) { - m_pApplication->DereferenceApplication(); - m_pApplication = NULL; + DBG_ASSERT(TlsGetValue(g_dwTlsIndex) == this); + TlsSetValue(g_dwTlsIndex, NULL); + ReleaseSRWLockShared(&m_RequestLock); + DBG_ASSERT(TlsGetValue(g_dwTlsIndex) == NULL); } - if (m_pAppOfflineHtm != NULL) - { - m_pAppOfflineHtm->DereferenceAppOfflineHtm(); - m_pAppOfflineHtm = NULL; - } - - m_pW3Context = NULL; + DereferenceRequestHandler(); + // + // No code after this point, as the handle might be gone + // + return retVal; } // static -void * FORWARDING_HANDLER::operator new(size_t) +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 + +--*/ { - DBG_ASSERT(sm_pAlloc != NULL); + HRESULT hr = S_OK; + + sm_pAlloc = new ALLOC_CACHE_HANDLER; if (sm_pAlloc == NULL) { - return NULL; + hr = E_OUTOFMEMORY; + goto Finished; } - return sm_pAlloc->Alloc(); + + 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( + " \ + \ + \ + \ + IIS 502.5 Error \ +
\ +

HTTP Error 502.5 - Process Failure

\ +
\ +

Common causes of this issue:

\ +
  • The application process failed to start
  • \ +
  • The application process started but then stopped
  • \ +
  • The application process started but failed to listen on the configured port
\ +
\ +
\ +

Troubleshooting steps:

\ +
  • Check the system event log for error messages
  • \ +
  • Enable logging the application process' stdout messages
  • \ +
  • Attach a debugger to the application process and inspect
\ +

For more information visit: \ + https://go.microsoft.com/fwlink/?LinkID=808681

\ +
\ +
\ +
"); + +Finished: + if (FAILED(hr)) + { + StaticTerminate(); + } + return hr; } -// static -void FORWARDING_HANDLER::operator delete(void * pMemory) +//static +VOID +FORWARDING_HANDLER::StaticTerminate() { - DBG_ASSERT(sm_pAlloc != NULL); + 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) { - sm_pAlloc->Free(pMemory); + delete sm_pAlloc; + sm_pAlloc = NULL; } } -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 = 0; - if ((cRefs = InterlockedDecrement(&m_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(strchr(pszHeaders, ' ')); - if (pchStatus == NULL) - { - return HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER); - } - while (*pchStatus == ' ') - { - pchStatus++; - } - USHORT uStatus = static_cast(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(pchNewline - pszHeaders) + 1; - pszHeaders[index] != '\r' && pszHeaders[index] != '\n' && pszHeaders[index] != '\0'; - index = static_cast(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(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(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(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(headerIndex), - strHeaderValue.QueryStr(), - static_cast(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(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(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; iUnknownHeaderCount; 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(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(pszHeader), strTemp.QueryCCH() + 1, strTemp.QueryStr()); - pHeaders->pUnknownHeaders[i].pRawValue = pszHeader; - pHeaders->pUnknownHeaders[i].RawValueLength = static_cast(strTemp.QueryCCH()); - - break; - } - } - - return S_OK; -} - HRESULT FORWARDING_HANDLER::GetHeaders( - const PROTOCOL_CONFIG * pProtocol, - PCWSTR * ppszHeaders, - DWORD * pcchHeaders, - ASPNETCORE_CONFIG* pAspNetCoreConfig, - SERVER_PROCESS* pServerProcess + _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; @@ -656,7 +783,7 @@ FORWARDING_HANDLER::GetHeaders( // if (!pProtocol->QueryPreserveHostHeader()) { - if (FAILED(hr = PATH::SplitUrl(pRequest->GetRawHttpRequest()->CookedUrl.pFullUrl, + if (FAILED(hr = UTILITY::SplitUrl(pRequest->GetRawHttpRequest()->CookedUrl.pFullUrl, &fSecure, &struDestination, &struUrl)) || @@ -708,7 +835,7 @@ FORWARDING_HANDLER::GetHeaders( } } - if (pAspNetCoreConfig->QueryForwardWindowsAuthToken() && + if (fForwardWindowsAuthToken && (_wcsicmp(m_pW3Context->GetUser()->GetAuthenticationType(), L"negotiate") == 0 || _wcsicmp(m_pW3Context->GetUser()->GetAuthenticationType(), L"ntlm") == 0)) { @@ -901,12 +1028,12 @@ FORWARDING_HANDLER::GetHeaders( 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 + _In_ const IHttpRequest * pRequest, + _In_ const PROTOCOL_CONFIG * pProtocol, + _In_ HINTERNET hConnect, + _Inout_ STRU * pstrUrl, +// _In_ ASPNETCORE_CONFIG* pAspNetCoreConfig, + _In_ SERVER_PROCESS* pServerProcess ) { HRESULT hr = S_OK; @@ -1011,10 +1138,10 @@ FORWARDING_HANDLER::CreateWinHttpRequest( } hr = GetHeaders(pProtocol, - &m_pszHeaders, - &m_cchHeaders, - pAspNetCoreConfig, - pServerProcess); + m_pApplication->QueryConfig()->QueryForwardWindowsAuthToken(), + pServerProcess, + &m_pszHeaders, + &m_cchHeaders); if (FAILED(hr)) { goto Finished; @@ -1025,1067 +1152,34 @@ Finished: return hr; } -REQUEST_NOTIFICATION_STATUS -FORWARDING_HANDLER::OnExecuteRequestHandler( - VOID -) -{ - REQUEST_NOTIFICATION_STATUS retVal = RQ_NOTIFICATION_CONTINUE; - HRESULT hr = S_OK; - bool fRequestLocked = FALSE; - 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; - SERVER_PROCESS *pServerProcess = NULL; - USHORT cchHostName = 0; - BOOL fSecure = FALSE; - BOOL fProcessStartFailure = FALSE; - BOOL fInternalError = FALSE; - HTTP_DATA_CHUNK *pDataChunk = NULL; - - DBG_ASSERT(m_RequestStatus == FORWARDER_START); - DBG_ASSERT(m_pApplication); - - // - // Take a reference so that object does not go away as a result of - // async completion. - // - ReferenceForwardingHandler(); - - // get application configuation - pAspNetCoreConfig = m_pApplication->QueryConfig(); - - - // check connection - IHttpConnection * pClientConnection = m_pW3Context->GetConnection(); - if (pClientConnection == NULL || - !pClientConnection->IsConnected()) - { - hr = HRESULT_FROM_WIN32(WSAECONNRESET); - goto Failure; - } - - // check offline - m_pAppOfflineHtm = m_pApplication->QueryAppOfflineHtm(); - if (m_pAppOfflineHtm != NULL) - { - m_pAppOfflineHtm->ReferenceAppOfflineHtm(); - } - - if (m_pApplication->AppOfflineFound() && m_pAppOfflineHtm != NULL) - { - HTTP_DATA_CHUNK DataChunk; - PCSTR pszANCMHeader; - DWORD cchANCMHeader; - BOOL fCompletionExpected = FALSE; - - if (FAILED(m_pW3Context->GetServerVariable(STR_ANCM_CHILDREQUEST, - &pszANCMHeader, - &cchANCMHeader))) // first time failure - { - if (SUCCEEDED(hr = m_pW3Context->CloneContext( - CLONE_FLAG_BASICS | CLONE_FLAG_HEADERS | CLONE_FLAG_ENTITY, - &m_pChildRequestContext - )) && - SUCCEEDED(hr = m_pChildRequestContext->SetServerVariable( - STR_ANCM_CHILDREQUEST, - L"1")) && - SUCCEEDED(hr = m_pW3Context->ExecuteRequest( - TRUE, // fAsync - m_pChildRequestContext, - EXECUTE_FLAG_DISABLE_CUSTOM_ERROR, // by pass Custom Error module - NULL, // pHttpUser - &fCompletionExpected))) - { - if (!fCompletionExpected) - { - retVal = RQ_NOTIFICATION_CONTINUE; - } - else - { - retVal = RQ_NOTIFICATION_PENDING; - } - goto Finished; - } - // - // fail to create child request, fall back to default 502 error - // - } - - DataChunk.DataChunkType = HttpDataChunkFromMemory; - DataChunk.FromMemory.pBuffer = (PVOID)m_pAppOfflineHtm->m_Contents.QueryStr(); - DataChunk.FromMemory.BufferLength = m_pAppOfflineHtm->m_Contents.QueryCB(); - - if (FAILED(hr = pResponse->WriteEntityChunkByReference(&DataChunk))) - { - goto Finished; - } - pResponse->SetStatus(503, "Service Unavailable", 0, hr); - pResponse->SetHeader("Content-Type", - "text/html", - (USHORT)strlen("text/html"), - FALSE - ); // no need to check return hresult - - m_fHasError = TRUE; - goto Finished; - } - - switch (pAspNetCoreConfig->QueryHostingModel()) - { - case HOSTING_IN_PROCESS: - { - - hr = ((IN_PROCESS_APPLICATION*)m_pApplication)->LoadManagedApplication(); - if (FAILED(hr)) - { - _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; - goto Failure; - } - - // 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 m_pApplication->ExecuteRequest(m_pW3Context); - } - case HOSTING_OUT_PROCESS: - { - m_pszOriginalHostHeader = pRequest->GetHeader(HttpHeaderHost, &cchHostName); - - // 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(); - hr = ((OUT_OF_PROCESS_APPLICATION*)m_pApplication)->GetProcess( - m_pW3Context, - &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; - } - - AcquireSRWLockShared(&m_RequestLock); - fRequestLocked = TRUE; - - 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; - - // - // 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); - - // - // WinHttpSendRequest can operate asynchronously. - // - // Take reference so that object does not go away as a result of - // async completion. - // - ReferenceForwardingHandler(); - - //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(static_cast(this)))) - { - hr = HRESULT_FROM_WIN32(GetLastError()); - DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO, - "FORWARDING_HANDLER::OnExecuteRequestHandler, Send request failed"); - if (ANCMEvents::ANCM_REQUEST_FORWARD_FAIL::IsEnabled(m_pW3Context->GetTraceContext())) - { - ANCMEvents::ANCM_REQUEST_FORWARD_FAIL::RaiseEvent( - m_pW3Context->GetTraceContext(), - NULL, - hr); - } - - DereferenceForwardingHandler(); - 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; - - } - - default: - hr = E_UNEXPECTED; - fInternalError = TRUE; - goto Failure; - } - -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 (fInternalError) - { - // set a special sub error code indicating loading application error - pResponse->SetStatus(500, "Internal Server Error", 19, hr); - goto Finished; - } - else if (fProcessStartFailure && !pAspNetCoreConfig->QueryDisableStartUpErrorPage()) - { - PCSTR pszANCMHeader; - DWORD cchANCMHeader; - BOOL fCompletionExpected = FALSE; - - if (FAILED(m_pW3Context->GetServerVariable(STR_ANCM_CHILDREQUEST, - &pszANCMHeader, - &cchANCMHeader))) // first time failure - { - if (SUCCEEDED(hr = m_pW3Context->CloneContext( - CLONE_FLAG_BASICS | - CLONE_FLAG_HEADERS | - CLONE_FLAG_ENTITY | - CLONE_FLAG_SERVER_VARIABLE, - &m_pChildRequestContext)) && - SUCCEEDED(hr = m_pChildRequestContext->SetServerVariable( - STR_ANCM_CHILDREQUEST, - L"1")) && - SUCCEEDED(hr = m_pW3Context->ExecuteRequest( - TRUE, // fAsync - m_pChildRequestContext, - EXECUTE_FLAG_DISABLE_CUSTOM_ERROR, // by pass Custom Error module - NULL, // pHttpUser - &fCompletionExpected))) - { - if (!fCompletionExpected) - { - m_pW3Context->SetRequestHandled(); - retVal = RQ_NOTIFICATION_CONTINUE; - } - else - { - retVal = RQ_NOTIFICATION_PENDING; - } - goto Finished; - } - // - // fail to create child request, fall back to default 502 error - // - } - else - { - if (SUCCEEDED(APPLICATION_MANAGER::GetInstance()->Get502ErrorPage(&pDataChunk))) - { - if (FAILED(hr = pResponse->WriteEntityChunkByReference(pDataChunk))) - { - goto Finished; - } - pResponse->SetStatus(502, "Bad Gateway", 5, hr); - pResponse->SetHeader("Content-Type", - "text/html", - (USHORT)strlen("text/html"), - FALSE - ); - 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) == 0) - { - 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 (fRequestLocked) - { - DBG_ASSERT(TlsGetValue(g_dwTlsIndex) == this); - TlsSetValue(g_dwTlsIndex, NULL); - ReleaseSRWLockShared(&m_RequestLock); - DBG_ASSERT(TlsGetValue(g_dwTlsIndex) == NULL); - } - - if (retVal != RQ_NOTIFICATION_PENDING) - { - // - // Remove request so that load-balancing algorithms like minCurrentRequests/minAverageResponseTime - // get the correct time when we received the last byte of response, rather than when we received - // ack from client about last byte of response - which could be much later. - // - RemoveRequest(); - } - - DereferenceForwardingHandler(); - // - // Do not use this object after dereferencing it, it may be gone. - // - return retVal; -} - VOID -FORWARDING_HANDLER::RemoveRequest() -{ - if (m_pDisconnect != NULL) - { - m_pDisconnect->ResetHandler(); - m_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_CONTINUE; - BOOL fLocked = FALSE; - bool fClientError = FALSE; - BOOL fClosed = FALSE; - - if (sm_pTraceLog != NULL) - { - WriteRefTraceLogEx(sm_pTraceLog, - m_cRefs, - this, - "FORWARDING_HANDLER::OnAsyncCompletion Enter", - reinterpret_cast(static_cast(cbCompletion)), - reinterpret_cast(static_cast(hrCompletionStatus))); - } - - if (m_pApplication->QueryConfig()->QueryHostingModel() == HOSTING_IN_PROCESS) - { - if (FAILED(hrCompletionStatus)) - { - return RQ_NOTIFICATION_FINISH_REQUEST; - } - else - { - // For now we are assuming we are in our own self contained box. - // TODO refactor Finished and Failure sections to handle in process and out of process failure. - // TODO verify that websocket's OnAsyncCompletion is not calling this. - IN_PROCESS_APPLICATION* application = (IN_PROCESS_APPLICATION*)m_pApplication; - if (application == NULL) - { - hr = E_FAIL; - return RQ_NOTIFICATION_FINISH_REQUEST; - } - - return application->OnAsyncCompletion(m_pW3Context, cbCompletion, hrCompletionStatus); - } - } - else if (m_pApplication->QueryConfig()->QueryHostingModel() == HOSTING_OUT_PROCESS) - { - // - // Take a reference so that object does not go away as a result of - // async completion. - // - // Read lock on the WinHTTP handle to protect from server closing - // the handle while it is in use. - // - ReferenceForwardingHandler(); - - DBG_ASSERT(m_pW3Context != NULL); - __analysis_assume(m_pW3Context != NULL); - - // - // 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); - AcquireSRWLockShared(&m_RequestLock); - TlsSetValue(g_dwTlsIndex, this); - DBG_ASSERT(TlsGetValue(g_dwTlsIndex) == this); - - fLocked = TRUE; - } - - if (m_hRequest == NULL) - { - if (m_RequestStatus == FORWARDER_DONE && m_fFinishRequest) - { - if (m_fHasError) - { - retVal = RQ_NOTIFICATION_FINISH_REQUEST; - } - goto Finished; - } - - fClientError = m_fHandleClosedDueToClient; - goto Failure; - } - else 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 Finished; - } - - hr = m_pWebSocket->ProcessRequest(this, m_pW3Context, m_hRequest); - if (FAILED(hr)) - { - goto Failure; - } - - // - // WebSocket upgrade is successful. Close the WinHttpRequest Handle - // - WinHttpSetStatusCallback(m_hRequest, - FORWARDING_HANDLER::OnWinHttpCompletion, - WINHTTP_CALLBACK_FLAG_HANDLES, - NULL); - fClosed = WinHttpCloseHandle(m_hRequest); - DBG_ASSERT(fClosed); - if (fClosed) - { - m_fWebSocketUpgrade = TRUE; - m_hRequest = NULL; - } - else - { - hr = HRESULT_FROM_WIN32(GetLastError()); - goto Failure; - } - retVal = RQ_NOTIFICATION_PENDING; - goto Finished; - } - else if (m_RequestStatus == FORWARDER_RESET_CONNECTION) - { - hr = HRESULT_FROM_WIN32(ERROR_WINHTTP_INVALID_SERVER_RESPONSE); - goto Failure; - - } - - // - // 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); - 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; - 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; - - // double check to set right status code - if (!m_pW3Context->GetConnection()->IsConnected()) - { - fClientError = TRUE; - } - - if (fClientError) - { - 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_hModule, - 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)) - { - pResponse->ResetConnection(); - goto Finished; - } - } - - // - // Finish the request on failure. - // Let IIS pipeline continue only after receiving handle close callback - // from WinHttp. This ensures no more callback from WinHttp - // - if (m_hRequest != NULL) - { - if (WinHttpCloseHandle(m_hRequest)) - { - m_hRequest = NULL; - } - } - retVal = RQ_NOTIFICATION_PENDING; - } - -Finished: - - if (fLocked) - { - DBG_ASSERT(TlsGetValue(g_dwTlsIndex) == this); - - TlsSetValue(g_dwTlsIndex, NULL); - ReleaseSRWLockShared(&m_RequestLock); - DBG_ASSERT(TlsGetValue(g_dwTlsIndex) == NULL); - } - - if (retVal != RQ_NOTIFICATION_PENDING) - { - // - // Remove request so that load-balancing algorithms like minCurrentRequests/minAverageResponseTime - // get the correct time when we received the last byte of response, rather than when we received - // ack from client about last byte of response - which could be much later. - // - RemoveRequest(); - } - - DereferenceForwardingHandler(); - - // - // Do not use this object after dereferencing it, it may be gone. - // - - return retVal; -} - -HRESULT -FORWARDING_HANDLER::OnSendingRequest( - DWORD cbCompletion, - HRESULT hrCompletionStatus, - __out bool * pfClientError +FORWARDING_HANDLER::OnWinHttpCompletion( + HINTERNET hRequest, + DWORD_PTR dwContext, + DWORD dwInternetStatus, + LPVOID lpvStatusInformation, + DWORD dwStatusInformationLength ) { - 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)) + FORWARDING_HANDLER * pThis = static_cast(reinterpret_cast(dwContext)); + if (pThis == NULL) { - 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. - // - ReferenceForwardingHandler(); - if (!WinHttpWriteData(m_hRequest, - "0\r\n\r\n", - 5, - NULL)) - { - hr = HRESULT_FROM_WIN32(GetLastError()); - DereferenceForwardingHandler(); - 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. - // - ReferenceForwardingHandler(); - if (!WinHttpReceiveResponse(m_hRequest, NULL)) - { - hr = HRESULT_FROM_WIN32(GetLastError()); - DereferenceForwardingHandler(); - goto Failure; - } - } + //error happened, nothing can be done here + return; } - 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. - // - ReferenceForwardingHandler(); - if (!WinHttpWriteData(m_hRequest, - m_pEntityBuffer + cbOffset, - cbCompletion, - NULL)) - { - hr = HRESULT_FROM_WIN32(GetLastError()); - DereferenceForwardingHandler(); - 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. - // - // Take reference so that object does not go away as a result of - // async completion. - // - ReferenceForwardingHandler(); - if (!WinHttpQueryDataAvailable(m_hRequest, NULL)) - { - hr = HRESULT_FROM_WIN32(GetLastError()); - DereferenceForwardingHandler(); - 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. - // - // Take reference so that object does not go away as a result of - // async completion. - // - ReferenceForwardingHandler(); - if (!WinHttpReadData(m_hRequest, - m_pEntityBuffer, - min(m_BytesToSend, BUFFER_SIZE), - NULL)) - { - hr = HRESULT_FROM_WIN32(GetLastError()); - DereferenceForwardingHandler(); - goto Failure; - } - } - -Failure: - - return hr; + DBG_ASSERT(pThis->m_Signature == FORWARDING_HANDLER_SIGNATURE); + pThis->OnWinHttpCompletionInternal(hRequest, + dwInternetStatus, + lpvStatusInformation, + dwStatusInformationLength); } VOID FORWARDING_HANDLER::OnWinHttpCompletionInternal( - HINTERNET hRequest, - DWORD dwInternetStatus, - LPVOID lpvStatusInformation, - DWORD dwStatusInformationLength + _In_ HINTERNET hRequest, + _In_ DWORD dwInternetStatus, + _In_ LPVOID lpvStatusInformation, + _In_ DWORD dwStatusInformationLength ) /*++ @@ -2107,14 +1201,18 @@ None --*/ { HRESULT hr = S_OK; - bool fIsCompletionThread = FALSE; + bool fLockAcquired = FALSE; bool fClientError = FALSE; bool fAnotherCompletionExpected = FALSE; + bool fDoPostCompletion = FALSE; + bool fEndRequest = (dwInternetStatus == WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING); + DBG_ASSERT(m_pW3Context != NULL); __analysis_assume(m_pW3Context != NULL); IHttpResponse * pResponse = m_pW3Context->GetResponse(); - BOOL fDerefForwardingHandler = TRUE; - BOOL fEndRequest = FALSE; + + // Reference the request handler to prevent it from being released prematurely + ReferenceRequestHandler(); UNREFERENCED_PARAMETER(dwStatusInformationLength); @@ -2136,6 +1234,7 @@ None NULL, dwInternetStatus); } + // // ReadLock on the winhttp handle to protect from a client disconnect/ // server stop closing the handle while we are using it. @@ -2144,10 +1243,6 @@ None // we have to account for that and not try to take the lock again, // otherwise, we could end up in a deadlock. // - // Take a reference so that object does not go away as a result of - // async completion - release one reference when async operation is - // initiated, two references if async operation is not initiated - // if (TlsGetValue(g_dwTlsIndex) != this) { @@ -2155,51 +1250,37 @@ None AcquireSRWLockShared(&m_RequestLock); TlsSetValue(g_dwTlsIndex, this); - fIsCompletionThread = TRUE; + fLockAcquired = TRUE; DBG_ASSERT(TlsGetValue(g_dwTlsIndex) == this); } #ifdef DEBUG - DBGPRINTF((DBG_CONTEXT, - "FORWARDING_HANDLER::OnWinHttpCompletionInternal %x -- %d --%p\n", dwInternetStatus, m_fWebSocketUpgrade, m_pW3Context)); + DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO, + "FORWARDING_HANDLER::OnWinHttpCompletionInternal %x -- %d --%p\n", dwInternetStatus, GetCurrentThreadId(), m_pW3Context); #endif // DEBUG - fEndRequest = (dwInternetStatus == WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING); if (!fEndRequest) { if (!m_pW3Context->GetConnection()->IsConnected()) { - m_fClientDisconnected = TRUE; - if (m_hRequest != NULL) - { - WinHttpSetStatusCallback(m_hRequest, - FORWARDING_HANDLER::OnWinHttpCompletion, - WINHTTP_CALLBACK_FLAG_HANDLES, - NULL); - if (WinHttpCloseHandle(m_hRequest)) - { - m_hRequest = NULL; - } - else - { - // if WinHttpCloseHandle failed, we are already in failure path - // nothing can can be done here - } - } hr = ERROR_CONNECTION_ABORTED; fClientError = m_fHandleClosedDueToClient = TRUE; - fDerefForwardingHandler = FALSE; - // wait for HANDLE_CLOSING callback to clean up - fAnotherCompletionExpected = !fEndRequest; + fAnotherCompletionExpected = TRUE; 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) { - fDerefForwardingHandler = FALSE; fAnotherCompletionExpected = TRUE; - if (m_pWebSocket == NULL) { goto Finished; @@ -2232,8 +1313,6 @@ None goto Finished; } - - switch (dwInternetStatus) { case WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE: @@ -2270,7 +1349,6 @@ None // This is a notification, not a completion. This notifiation happens // during the Send Request operation. // - fDerefForwardingHandler = FALSE; fAnotherCompletionExpected = TRUE; break; @@ -2280,7 +1358,6 @@ None // for WINHTTP_CALLBACK_STATUS_SENDING_REQUEST (which we actually need). // hr = S_OK; - fDerefForwardingHandler = FALSE; fAnotherCompletionExpected = TRUE; break; @@ -2291,18 +1368,15 @@ None m_pW3Context->GetTraceContext(), NULL); } - if (m_RequestStatus != FORWARDER_DONE) + if (m_RequestStatus != FORWARDER_DONE || m_fHandleClosedDueToClient) { hr = ERROR_CONNECTION_ABORTED; fClientError = m_fHandleClosedDueToClient; } - else - { - fDerefForwardingHandler = m_fClientDisconnected && !m_fWebSocketUpgrade; - } m_hRequest = NULL; fAnotherCompletionExpected = FALSE; break; + case WINHTTP_CALLBACK_STATUS_CONNECTION_CLOSED: hr = ERROR_CONNECTION_ABORTED; break; @@ -2339,43 +1413,41 @@ None goto Finished; Failure: + m_RequestStatus = FORWARDER_DONE; + m_fHasError = TRUE; - if (!m_fErrorHandled) + pResponse->DisableKernelCache(); + pResponse->GetRawHttpResponse()->EntityChunkCount = 0; + + if (hr == HRESULT_FROM_WIN32(ERROR_WINHTTP_INVALID_SERVER_RESPONSE)) { - m_fErrorHandled = TRUE; - if (hr == HRESULT_FROM_WIN32(ERROR_WINHTTP_INVALID_SERVER_RESPONSE)) - { - m_RequestStatus = FORWARDER_RESET_CONNECTION; - goto Finished; - } + m_fResetConnection = TRUE; + } - pResponse->DisableKernelCache(); - pResponse->GetRawHttpResponse()->EntityChunkCount = 0; - fClientError = !m_pW3Context->GetConnection()->IsConnected(); - if (fClientError) + if (fClientError || m_fHandleClosedDueToClient) + { + if (!m_fResponseHeadersReceivedAndSet) { - 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. - // - } + pResponse->SetStatus(400, "Bad Request", 0, HRESULT_FROM_WIN32(WSAECONNRESET)); } else { - STACK_STRU(strDescription, 128); + // + // 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)) || + 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, @@ -2399,9 +1471,9 @@ Failure: strDescription.QueryStr(), strDescription.QueryCCH(), FALSE); - } - } + }*/ } + //} // FREB log if (ANCMEvents::ANCM_REQUEST_FORWARD_FAIL::IsEnabled(m_pW3Context->GetTraceContext())) @@ -2414,7 +1486,7 @@ Failure: Finished: - if (fIsCompletionThread) + if (fLockAcquired) { DBG_ASSERT(TlsGetValue(g_dwTlsIndex) == this); TlsSetValue(g_dwTlsIndex, NULL); @@ -2422,22 +1494,15 @@ Finished: DBG_ASSERT(TlsGetValue(g_dwTlsIndex) == NULL); } - if (fDerefForwardingHandler) - { - DereferenceForwardingHandler(); - } - // - // Do not use this object after dereferencing it, it may be gone. - // - - // - // Completion may had been already posted to IIS if an async - // operation was started in this method (either WinHTTP or IIS e.g. ReadyEntityBody) - // If fAnotherCompletionExpected is false, this method must post the completion. - // - if (m_RequestStatus == FORWARDER_DONE) { + //disbale client disconnect callback + if (m_pDisconnect != NULL) + { + m_pDisconnect->ResetHandler(); + m_pDisconnect = NULL; + } + if (m_hRequest != NULL) { WinHttpSetStatusCallback(m_hRequest, @@ -2448,6 +1513,13 @@ Finished: { m_hRequest = NULL; } + else + { + // unexpected WinHttp error, log it + /*DebugBreak(); + m_RequestStatus = FORWARDER_FINISH_REQUEST; + fDoPostCompletion = TRUE;*/ + } } // @@ -2465,22 +1537,27 @@ Finished: // in case of websocket, m_hRequest has already been closed after upgrade // websocket will handle completion m_fFinishRequest = TRUE; - m_pW3Context->PostCompletion(0); - + fDoPostCompletion = TRUE; } } + // + // Completion may had been already posted to IIS if an async + // operation was started in this method (either WinHTTP or IIS e.g. ReadyEntityBody) + // If fAnotherCompletionExpected is false, this method must post the completion. + // else if (!fAnotherCompletionExpected) { // // Since we use TLS to guard WinHttp operation, call PostCompletion instead of // IndicateCompletion to allow cleaning up the TLS before thread reuse. // + fDoPostCompletion = TRUE; + } + DereferenceRequestHandler(); + if (fDoPostCompletion) + { m_pW3Context->PostCompletion(0); - - // - // No code executed after posting the completion. - // } } @@ -2549,14 +1626,14 @@ FORWARDING_HANDLER::OnWinHttpCompletionSendRequestOrWriteComplete( // Take reference so that object does not go away as a result of // async completion. // - ReferenceForwardingHandler(); + //ReferenceForwardingHandler(); if (!WinHttpWriteData(m_hRequest, "0\r\n\r\n", 5, NULL)) { hr = HRESULT_FROM_WIN32(GetLastError()); - DereferenceForwardingHandler(); + //DereferenceForwardingHandler(); goto Finished; } *pfAnotherCompletionExpected = TRUE; @@ -2582,17 +1659,9 @@ FORWARDING_HANDLER::OnWinHttpCompletionSendRequestOrWriteComplete( m_RequestStatus = FORWARDER_RECEIVING_RESPONSE; - // - // WinHttpReceiveResponse can operate asynchronously. - // - // Take reference so that object does not go away as a result of - // async completion. - // - ReferenceForwardingHandler(); if (!WinHttpReceiveResponse(hRequest, NULL)) { hr = HRESULT_FROM_WIN32(GetLastError()); - DereferenceForwardingHandler(); goto Finished; } *pfAnotherCompletionExpected = TRUE; @@ -2719,7 +1788,7 @@ HRESULT FORWARDING_HANDLER::OnWinHttpCompletionStatusDataAvailable( HINTERNET hRequest, DWORD dwBytes, - __out bool * pfAnotherCompletionExpected + _Out_ bool * pfAnotherCompletionExpected ) { HRESULT hr = S_OK; @@ -2760,14 +1829,14 @@ FORWARDING_HANDLER::OnWinHttpCompletionStatusDataAvailable( // Take reference so that object does not go away as a result of // async completion. // - ReferenceForwardingHandler(); + //ReferenceForwardingHandler(); if (!WinHttpReadData(hRequest, m_pEntityBuffer, min(m_BytesToSend, BUFFER_SIZE), NULL)) { hr = HRESULT_FROM_WIN32(GetLastError()); - DereferenceForwardingHandler(); + //DereferenceForwardingHandler(); goto Finished; } *pfAnotherCompletionExpected = TRUE; @@ -2862,331 +1931,190 @@ Finished: return hr; } -// static HRESULT -FORWARDING_HANDLER::StaticInitialize( - BOOL fEnableReferenceCountTracing +FORWARDING_HANDLER::OnSendingRequest( + DWORD cbCompletion, + HRESULT hrCompletionStatus, + __out bool * pfClientError ) -/*++ - -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), - 64); // nThreshold - if (FAILED(hr)) - { - goto Failure; - } - + HRESULT hr = S_OK; // - // Open the session handle, specify random user-agent that will be - // overwritten by the client + // 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 // - sm_hSession = WinHttpOpen(L"", - WINHTTP_ACCESS_TYPE_NO_PROXY, - WINHTTP_NO_PROXY_NAME, - WINHTTP_NO_PROXY_BYPASS, - WINHTTP_FLAG_ASYNC); - if (sm_hSession == NULL) + if (hrCompletionStatus == HRESULT_FROM_WIN32(ERROR_HANDLE_EOF)) { - hr = HRESULT_FROM_WIN32(GetLastError()); - goto Failure; + 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; + } + } } - - // - // 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) + else if (SUCCEEDED(hrCompletionStatus)) { - hr = HRESULT_FROM_WIN32(GetLastError()); - goto Failure; - } + DWORD cbOffset; - // - // 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; - } + 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'; - // Initialize Application Manager - APPLICATION_MANAGER *pApplicationManager = APPLICATION_MANAGER::GetInstance(); - if (pApplicationManager == NULL) - { - hr = E_OUTOFMEMORY; - goto Failure; - } + m_pEntityBuffer[cbCompletion + 6] = '\r'; + m_pEntityBuffer[cbCompletion + 7] = '\n'; - hr = pApplicationManager->Initialize(); - if (FAILED(hr)) - { - goto Failure; - } + 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); - // Initialize PROTOCOL_CONFIG - sm_ProtocolConfig.Initialize(); + 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 (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); + if (!WinHttpWriteData(m_hRequest, + m_pEntityBuffer + cbOffset, + cbCompletion, + NULL)) + { + hr = HRESULT_FROM_WIN32(GetLastError()); + goto Failure; + } } else { - sm_hEventLog = RegisterEventSource(NULL, ASPNETCORE_EVENT_PROVIDER); - } - - g_dwTlsIndex = TlsAlloc(); - if (g_dwTlsIndex == TLS_OUT_OF_INDEXES) - { - hr = HRESULT_FROM_WIN32(GetLastError()); + hr = hrCompletionStatus; + *pfClientError = TRUE; goto Failure; } - if (fEnableReferenceCountTracing) - { - sm_pTraceLog = CreateRefTraceLog(10000, 0); - } - - return S_OK; - Failure: - StaticTerminate(); - return hr; } -// static -VOID -FORWARDING_HANDLER::StaticTerminate( - VOID +HRESULT +FORWARDING_HANDLER::OnReceivingResponse( ) -/*++ - -Routine Description: - -Global termination routine for FORWARDING_HANDLERs - -Arguments: - -None - -Return Value: - -None - ---*/ { - // - // Delete all the statics - // + HRESULT hr = S_OK; - 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 (m_cBytesBuffered >= m_cMinBufferLimit) { - if ((GetTickCount() - tickCount) > 10000) + 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) { - break; + // + // Disable buffering. + // + m_BytesToSend = 0; } - 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(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 -) -{ - if (m_pApplication->QueryConfig()->QueryHostingModel() == HOSTING_IN_PROCESS) + if (m_BytesToSend == 0) { // - // Todo: need inform managed layer to abort the request + // No buffering enabled. // + if (!WinHttpQueryDataAvailable(m_hRequest, NULL)) + { + hr = HRESULT_FROM_WIN32(GetLastError()); + goto Failure; + } } else { - bool fAcquiredLock = FALSE; - - if (TlsGetValue(g_dwTlsIndex) != this) + // + // Buffering enabled. + // + if (m_pEntityBuffer == NULL) { - DBG_ASSERT(TlsGetValue(g_dwTlsIndex) == NULL); - AcquireSRWLockShared(&m_RequestLock); - TlsSetValue(g_dwTlsIndex, this); - DBG_ASSERT(TlsGetValue(g_dwTlsIndex) == this); - fAcquiredLock = TRUE; - } - - if (m_hRequest != NULL) - { - WinHttpSetStatusCallback(m_hRequest, - FORWARDING_HANDLER::OnWinHttpCompletion, - WINHTTP_CALLBACK_FLAG_HANDLES, - NULL); - if (WinHttpCloseHandle(m_hRequest)) + m_pEntityBuffer = GetNewResponseBuffer(min(m_BytesToSend, BUFFER_SIZE)); + if (m_pEntityBuffer == NULL) { - m_hRequest = NULL; + hr = E_OUTOFMEMORY; + goto Failure; } - m_fHandleClosedDueToClient = fClientInitiated; } - // - // If the request is a websocket request, initiate cleanup. - // - - if (m_pWebSocket != NULL) + if (!WinHttpReadData(m_hRequest, + m_pEntityBuffer, + min(m_BytesToSend, BUFFER_SIZE), + NULL)) { - m_pWebSocket->TerminateRequest(); - } - - if (fAcquiredLock) - { - DBG_ASSERT(TlsGetValue(g_dwTlsIndex) == this); - TlsSetValue(g_dwTlsIndex, NULL); - ReleaseSRWLockShared(&m_RequestLock); - DBG_ASSERT(TlsGetValue(g_dwTlsIndex) == NULL); + hr = HRESULT_FROM_WIN32(GetLastError()); + goto Failure; } } + +Failure: + return hr; } BYTE * @@ -3232,43 +2160,468 @@ FORWARDING_HANDLER::FreeResponseBuffers() } HRESULT -FORWARDING_HANDLER::SetHttpSysDisconnectCallback() +FORWARDING_HANDLER::SetStatusAndHeaders( + PCSTR pszHeaders, + DWORD +) { - HRESULT hr = S_OK; - IHttpConnection * pClientConnection = m_pW3Context->GetConnection(); + 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; - if (g_fAsyncDisconnectAvailable) + _ASSERT(pszHeaders != NULL); + + // + // The first line is the status line + // + PSTR pchStatus = const_cast(strchr(pszHeaders, ' ')); + if (pchStatus == NULL) { - m_pDisconnect = static_cast( - pClientConnection->GetModuleContextContainer()-> - GetConnectionModuleContext(g_pModuleId)); - if (m_pDisconnect == NULL) - { - m_pDisconnect = new ASYNC_DISCONNECT_CONTEXT; - if (m_pDisconnect == NULL) - { - hr = E_OUTOFMEMORY; - goto Finished; - } + return HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER); + } + while (*pchStatus == ' ') + { + pchStatus++; + } + USHORT uStatus = static_cast(atoi(pchStatus)); - hr = pClientConnection->GetModuleContextContainer()-> - SetConnectionModuleContext(m_pDisconnect, - g_pModuleId); - DBG_ASSERT(hr != HRESULT_FROM_WIN32(ERROR_ALREADY_ASSIGNED)); - if (FAILED(hr)) - { - goto Finished; - } + 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--) + { } // - // 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. + // Copy the status description // - m_pDisconnect->SetHandler(this); - - Finished: - return hr; + 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(pchNewline - pszHeaders) + 1; + pszHeaders[index] != '\r' && pszHeaders[index] != '\n' && pszHeaders[index] != '\0'; + index = static_cast(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(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(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(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(headerIndex), + strHeaderValue.QueryStr(), + static_cast(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(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(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; iUnknownHeaderCount; 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(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(pszHeader), strTemp.QueryCCH() + 1, strTemp.QueryStr()); + pHeaders->pUnknownHeaders[i].pRawValue = pszHeader; + pHeaders->pUnknownHeaders[i].RawValueLength = static_cast(strTemp.QueryCCH()); + + break; + } + } + + return S_OK; +} + +VOID +FORWARDING_HANDLER::TerminateRequest( + bool fClientInitiated +) +{ + UNREFERENCED_PARAMETER(fClientInitiated); + AcquireSRWLockExclusive(&m_RequestLock); + // 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 + TlsSetValue(g_dwTlsIndex, this); + DBG_ASSERT(TlsGetValue(g_dwTlsIndex) == this); + + if (m_hRequest != NULL) + { +#ifdef DEBUG + DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO, + "FORWARDING_HANDLER::TerminateRequest %d --%p\n", GetCurrentThreadId(), m_pW3Context); +#endif // DEBUG + m_fHandleClosedDueToClient = fClientInitiated; + WinHttpCloseHandle(m_hRequest); + } + + // + // If the request is a websocket request, initiate cleanup. + // + if (m_pWebSocket != NULL) + { + m_pWebSocket->TerminateRequest(); + } + + TlsSetValue(g_dwTlsIndex, NULL); + ReleaseSRWLockExclusive(&m_RequestLock); + DBG_ASSERT(TlsGetValue(g_dwTlsIndex) == NULL); +} + diff --git a/src/RequestHandler/outofprocess/forwardinghandler.h b/src/RequestHandler/outofprocess/forwardinghandler.h new file mode 100644 index 0000000000..1db353019b --- /dev/null +++ b/src/RequestHandler/outofprocess/forwardinghandler.h @@ -0,0 +1,199 @@ +#pragma once + +extern DWORD g_OptionalWinHttpFlags; + + +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: + HRESULT + CreateWinHttpRequest( + _In_ const IHttpRequest * pRequest, + _In_ const PROTOCOL_CONFIG * pProtocol, + _In_ HINTERNET hConnect, + _Inout_ STRU * pstrUrl, +// _In_ ASPNETCORE_CONFIG* pAspNetCoreConfig, + _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 + ); + + 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_fHandleClosedDueToClient; + bool m_fFinishRequest; + bool m_fHasError; + BOOL m_fDoReverseRewriteHeaders; + PCSTR m_pszOriginalHostHeader; + PCWSTR m_pszHeaders; + 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 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; +}; \ No newline at end of file diff --git a/src/RequestHandler/outofprocess/outprocessapplication.cpp b/src/RequestHandler/outofprocess/outprocessapplication.cpp new file mode 100644 index 0000000000..7e14145585 --- /dev/null +++ b/src/RequestHandler/outofprocess/outprocessapplication.cpp @@ -0,0 +1,66 @@ +#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; + //todo +} + +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() +{ + if (m_pProcessManager != NULL) + { + m_pProcessManager->ShutdownAllProcesses(); + m_pProcessManager->DereferenceProcessManager(); + m_pProcessManager = NULL; + } +} diff --git a/src/RequestHandler/outofprocess/outprocessapplication.h b/src/RequestHandler/outofprocess/outprocessapplication.h new file mode 100644 index 0000000000..8961135c28 --- /dev/null +++ b/src/RequestHandler/outofprocess/outprocessapplication.h @@ -0,0 +1,25 @@ +#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(); + +private: + PROCESS_MANAGER * m_pProcessManager; +}; diff --git a/src/RequestHandler/outofprocess/processmanager.cxx b/src/RequestHandler/outofprocess/processmanager.cxx new file mode 100644 index 0000000000..98ba30441f --- /dev/null +++ b/src/RequestHandler/outofprocess/processmanager.cxx @@ -0,0 +1,296 @@ +// 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; + //PCWSTR apsz[1]; + STACK_STRU(strEventMsg, 256); + 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. + // + + //todo: + //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) + { + + 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->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; +} \ No newline at end of file diff --git a/src/AspNetCore/Inc/processmanager.h b/src/RequestHandler/outofprocess/processmanager.h similarity index 97% rename from src/AspNetCore/Inc/processmanager.h rename to src/RequestHandler/outofprocess/processmanager.h index 1cc8a6ab54..9523e8a819 100644 --- a/src/AspNetCore/Inc/processmanager.h +++ b/src/RequestHandler/outofprocess/processmanager.h @@ -4,6 +4,7 @@ #pragma once #define ONE_MINUTE_IN_MILLISECONDS 60000 +class SERVER_PROCESS; class PROCESS_MANAGER { @@ -29,7 +30,6 @@ public: HRESULT GetProcess( - _In_ IHttpContext *context, _In_ ASPNETCORE_CONFIG *pConfig, _Out_ SERVER_PROCESS **ppServerProcess ); @@ -104,6 +104,8 @@ public: m_fServerProcessListReady(FALSE), m_cRefs( 1 ) { + m_ppServerProcessList = NULL; + m_fServerProcessListReady = FALSE; InitializeSRWLock( &m_srwLock ); } diff --git a/src/AspNetCore/Src/protocolconfig.cxx b/src/RequestHandler/outofprocess/protocolconfig.cxx similarity index 97% rename from src/AspNetCore/Src/protocolconfig.cxx rename to src/RequestHandler/outofprocess/protocolconfig.cxx index 85fd86aa61..9faebab82a 100644 --- a/src/AspNetCore/Src/protocolconfig.cxx +++ b/src/RequestHandler/outofprocess/protocolconfig.cxx @@ -1,7 +1,7 @@ // 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 "..\precomp.hxx" HRESULT PROTOCOL_CONFIG::Initialize() diff --git a/src/AspNetCore/Inc/protocolconfig.h b/src/RequestHandler/outofprocess/protocolconfig.h similarity index 98% rename from src/AspNetCore/Inc/protocolconfig.h rename to src/RequestHandler/outofprocess/protocolconfig.h index f7d915d6a9..0bb34aa53d 100644 --- a/src/AspNetCore/Inc/protocolconfig.h +++ b/src/RequestHandler/outofprocess/protocolconfig.h @@ -3,8 +3,6 @@ #pragma once -#include "aspnetcoreconfig.h" - class PROTOCOL_CONFIG { public: diff --git a/src/AspNetCore/Src/responseheaderhash.cxx b/src/RequestHandler/outofprocess/responseheaderhash.cxx similarity index 97% rename from src/AspNetCore/Src/responseheaderhash.cxx rename to src/RequestHandler/outofprocess/responseheaderhash.cxx index 02653c29b7..f2fae274d5 100644 --- a/src/AspNetCore/Src/responseheaderhash.cxx +++ b/src/RequestHandler/outofprocess/responseheaderhash.cxx @@ -1,9 +1,7 @@ // 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" - -RESPONSE_HEADER_HASH * g_pResponseHeaderHash = NULL; +#include "..\precomp.hxx" HEADER_RECORD RESPONSE_HEADER_HASH::sm_rgHeaders[] = { diff --git a/src/AspNetCore/Inc/responseheaderhash.h b/src/RequestHandler/outofprocess/responseheaderhash.h similarity index 97% rename from src/AspNetCore/Inc/responseheaderhash.h rename to src/RequestHandler/outofprocess/responseheaderhash.h index b7781e45b9..54f9c82954 100644 --- a/src/AspNetCore/Inc/responseheaderhash.h +++ b/src/RequestHandler/outofprocess/responseheaderhash.h @@ -106,5 +106,3 @@ private: 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/AspNetCore/Src/serverprocess.cxx b/src/RequestHandler/outofprocess/serverprocess.cxx similarity index 80% rename from src/AspNetCore/Src/serverprocess.cxx rename to src/RequestHandler/outofprocess/serverprocess.cxx index b9f8010902..4c94331de9 100644 --- a/src/AspNetCore/Src/serverprocess.cxx +++ b/src/RequestHandler/outofprocess/serverprocess.cxx @@ -1,14 +1,15 @@ // 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 "..\precomp.hxx" #include -#include +//#include -extern BOOL g_fNsiApiNotSupported; +//extern BOOL g_fNsiApiNotSupported; #define STARTUP_TIME_LIMIT_INCREMENT_IN_MILLISECONDS 5000 + HRESULT SERVER_PROCESS::Initialize( PROCESS_MANAGER *pProcessManager, @@ -21,7 +22,10 @@ SERVER_PROCESS::Initialize( BOOL fAnonymousAuthEnabled, ENVIRONMENT_VAR_HASH *pEnvironmentVariables, BOOL fStdoutLogEnabled, - STRU *pstruStdoutLogFile + STRU *pstruStdoutLogFile, + STRU *pszAppPhysicalPath, + STRU *pszAppPath, + STRU *pszAppVirtualPath ) { HRESULT hr = S_OK; @@ -38,6 +42,9 @@ SERVER_PROCESS::Initialize( 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))) { goto Finished; @@ -188,14 +195,10 @@ Finished: 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); @@ -207,51 +210,14 @@ SERVER_PROCESS::SetupAppPath( 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//. - 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())) || + + if (FAILED(hr = pEntry->Initialize(ASPNETCORE_APP_PATH_ENV_STR, m_struAppVirtualPath.QueryStr())) || FAILED(hr = pEnvironmentVarTable->InsertRecord(pEntry))) { goto Finished; @@ -614,7 +580,7 @@ SERVER_PROCESS::SetupCommandLine( 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())) || + if (FAILED(hr = strRelativePath.Copy(m_struPhysicalPath.QueryStr())) || FAILED(hr = strRelativePath.Append(L"\\")) || FAILED(hr = strRelativePath.Append(pszPath))) { @@ -658,11 +624,10 @@ Finished: return hr; } - HRESULT SERVER_PROCESS::PostStartCheck( - const STRU* const pStruCommandline, - STRU* pStruErrorMessage) + VOID +) { HRESULT hr = S_OK; @@ -690,13 +655,13 @@ SERVER_PROCESS::PostStartCheck( if (processStatus != STILL_ACTIVE) { hr = E_FAIL; - pStruErrorMessage->SafeSnwprintf( + /*pStruErrorMessage->SafeSnwprintf( ASPNETCORE_EVENT_PROCESS_START_ERROR_MSG, m_struAppFullPath.QueryStr(), m_pszRootApplicationPath.QueryStr(), - pStruCommandline->QueryStr(), + m_pStruCommandline->QueryStr(), hr, - processStatus); + processStatus);*/ goto Finished; } } @@ -785,13 +750,13 @@ SERVER_PROCESS::PostStartCheck( // 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); + //pStruErrorMessage->SafeSnwprintf( + // ASPNETCORE_EVENT_PROCESS_START_WRONGPORT_ERROR_MSG, + // m_struAppFullPath.QueryStr(), + // m_pszRootApplicationPath.QueryStr(), + // m_struCommandline.QueryStr(), + // m_dwPort, + // hr); hr = HRESULT_FROM_WIN32(ERROR_CREATE_FAILED); goto Finished; } @@ -805,13 +770,13 @@ SERVER_PROCESS::PostStartCheck( if (dwTimeDifference >= m_dwStartupTimeLimitInMS) { hr = HRESULT_FROM_WIN32(ERROR_TIMEOUT); - pStruErrorMessage->SafeSnwprintf( + /*pStruErrorMessage->SafeSnwprintf( ASPNETCORE_EVENT_PROCESS_START_NOTREADY_ERROR_MSG, m_struAppFullPath.QueryStr(), m_pszRootApplicationPath.QueryStr(), pStruCommandline->QueryStr(), m_dwPort, - hr); + hr);*/ } goto Finished; } @@ -829,13 +794,13 @@ SERVER_PROCESS::PostStartCheck( 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); + //pStruErrorMessage->SafeSnwprintf( + // ASPNETCORE_EVENT_PROCESS_START_NOTREADY_ERROR_MSG, + // m_struAppFullPath.QueryStr(), + // m_pszRootApplicationPath.QueryStr(), + // pStruCommandline->QueryStr(), + // m_dwPort, + // hr); goto Finished; } } @@ -844,12 +809,6 @@ SERVER_PROCESS::PostStartCheck( // 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(); @@ -879,244 +838,257 @@ SERVER_PROCESS::PostStartCheck( m_fReady = TRUE; Finished: + if (FAILED(hr)) + { + if (m_pForwarderConnection != NULL) + { + m_pForwarderConnection->DereferenceForwarderConnection(); + m_pForwarderConnection = NULL; + } + } return hr; } HRESULT SERVER_PROCESS::StartProcess( - IHttpContext *context + VOID ) { HRESULT hr = S_OK; PROCESS_INFORMATION processInformation = {0}; STARTUPINFOW startupInfo = {0}; - BOOL fDonePrepareCommandLine = FALSE; +// BOOL fDonePrepareCommandLine = FALSE; + DWORD dwRetryCount = 2; // should we allow customer to config it DWORD dwCreationFlags = 0; - STACK_STRU( strEventMsg, 256); - STRU strFullProcessPath; - STRU struRelativePath; - STRU struApplicationId; - STRU struCommandLine; - - LPCWSTR apsz[1]; - +// STACK_STRU( strEventMsg, 256); +// STRU strFullProcessPath; +// STRU struRelativePath; +// STRU struApplicationId; +// +// 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; - } + SetupStdHandles(&startupInfo); // // generate process command line. // - if (FAILED(hr = SetupCommandLine(&struCommandLine))) + if (FAILED(hr = SetupCommandLine(&m_struCommandLine))) { goto Finished; } - fDonePrepareCommandLine = TRUE; + while (dwRetryCount > 0) + { + dwRetryCount--; + if (FAILED(hr = InitEnvironmentVariablesTable(&pHashTable))) + { + goto Finished; + } - dwCreationFlags = CREATE_NO_WINDOW | - CREATE_UNICODE_ENVIRONMENT | - CREATE_SUSPENDED | - CREATE_NEW_PROCESS_GROUP; + // + // setup the the port that the backend process will listen on + // + if (FAILED(hr = SetupListenPort(pHashTable))) + { + goto Finished; + } - if (!CreateProcessW( - NULL, // applicationName - struCommandLine.QueryStr(), + // + // get app path + // + if (FAILED(hr = SetupAppPath(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; + } + + 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_pszRootApplicationPath.QueryStr(), // currentDir + m_struPhysicalPath.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); + // 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; } - // FREB log - if (ANCMEvents::ANCM_START_APPLICATION_SUCCESS::IsEnabled(context->GetTraceContext())) + m_hProcessHandle = processInformation.hProcess; + m_dwProcessId = processInformation.dwProcessId; + + if (m_hJobObject != NULL) { - ANCMEvents::ANCM_START_APPLICATION_SUCCESS::RaiseEvent( - context->GetTraceContext(), - NULL, - apsz[0]); - } - } - -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) + if (!AssignProcessToJobObject(m_hJobObject, m_hProcessHandle)) { - 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); + hr = HRESULT_FROM_WIN32(GetLastError()); + if (hr != HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED)) + { + goto Finished; + } } } - apsz[0] = strEventMsg.QueryStr(); - - // not checking return code because if ReportEvent - // fails, we cannot do anything. - // - if (FORWARDING_HANDLER::QueryEventLog() != NULL) + if (ResumeThread(processInformation.hThread) == -1) { - ReportEventW(FORWARDING_HANDLER::QueryEventLog(), - EVENTLOG_ERROR_TYPE, - 0, - ASPNETCORE_EVENT_PROCESS_START_ERROR, - NULL, - 1, - 0, - apsz, - NULL); + hr = HRESULT_FROM_WIN32(GetLastError()); + goto Finished; } - // FREB log - if (ANCMEvents::ANCM_START_APPLICATION_FAIL::IsEnabled(context->GetTraceContext())) + // + // need to make sure the server is up and listening on the port specified. + // + if (FAILED(hr = PostStartCheck())) { - ANCMEvents::ANCM_START_APPLICATION_FAIL::RaiseEvent( - context->GetTraceContext(), - NULL, - strEventMsg.QueryStr()); + goto Finished; + } + + // Backend process starts successfully. Set retry counter to 0 + dwRetryCount = 0; + + // + // 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); + // } + // + // // FREB log + //if (ANCMEvents::ANCM_START_APPLICATION_SUCCESS::IsEnabled(context->GetTraceContext())) + //{ + // ANCMEvents::ANCM_START_APPLICATION_SUCCESS::RaiseEvent( + // context->GetTraceContext(), + // NULL, + // apsz[0]); + //} + // } + // + + 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); +// } +// +// // FREB log +// if (ANCMEvents::ANCM_START_APPLICATION_FAIL::IsEnabled(context->GetTraceContext())) +// { +// ANCMEvents::ANCM_START_APPLICATION_FAIL::RaiseEvent( +// context->GetTraceContext(), +// NULL, +// strEventMsg.QueryStr()); +// } +// } + if (FAILED(hr) || m_fReady == FALSE) { if (m_hStdoutHandle != NULL) @@ -1173,7 +1145,7 @@ SERVER_PROCESS::SetWindowsAuthToken( FALSE, DUPLICATE_SAME_ACCESS )) { - hr = HRESULT_FROM_GETLASTERROR(); + hr = HRESULT_FROM_WIN32(GetLastError()); goto Finished; } } @@ -1185,160 +1157,134 @@ Finished: 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; + SECURITY_ATTRIBUTES saAttr = { 0 }; + + STRU struPath; + //STRU strEventMsg; + //LPCWSTR apsz[1]; DBG_ASSERT(pStartupInfo); - if (m_fStdoutLogEnabled) + if (m_hStdoutHandle != NULL && m_hStdoutHandle != INVALID_HANDLE_VALUE) { - 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)) + if (!CloseHandle(m_hStdoutHandle)) { + hr = HRESULT_FROM_WIN32(GetLastError()); goto Finished; } - - GetSystemTime(&systemTime); - hr = struLogFileName.SafeSnwprintf(L"%s_%d%02d%02d%02d%02d%02d_%d.log", - struAbsLogFilePath.QueryStr(), - systemTime.wYear, - systemTime.wMonth, - systemTime.wDay, - systemTime.wHour, - systemTime.wMinute, - systemTime.wSecond, - GetCurrentProcessId() ); - 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); - } + m_hStdoutHandle = NULL; } - if ((!m_fStdoutLogEnabled || fStdoutLoggingFailed) && - m_pProcessManager->QueryNULHandle() != NULL && - m_pProcessManager->QueryNULHandle() != INVALID_HANDLE_VALUE) + hr = UTILITY::ConvertPathToFullPath( + m_struLogFile.QueryStr(), + m_struPhysicalPath.QueryStr(), + &struPath); + if (FAILED(hr)) + { + goto Finished; + } + + hr = UTILITY::EnsureDirectoryPathExist(struPath.QueryStr()); + 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; + } + + 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; + } + + if (m_fStdoutLogEnabled) { pStartupInfo->dwFlags = STARTF_USESTDHANDLES; pStartupInfo->hStdInput = INVALID_HANDLE_VALUE; - pStartupInfo->hStdError = m_pProcessManager->QueryNULHandle(); - pStartupInfo->hStdOutput = m_pProcessManager->QueryNULHandle(); + 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); + } + else + { // only enable stderr + pStartupInfo->dwFlags = STARTF_USESTDHANDLES; + pStartupInfo->hStdInput = INVALID_HANDLE_VALUE; + pStartupInfo->hStdError = m_hStdoutHandle; + pStartupInfo->hStdOutput = INVALID_HANDLE_VALUE; } 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) + if (FAILED(hr)) { - hr = HRESULT_FROM_GETLASTERROR(); - } + // The log file was not created yet in case of failure. No need to clean it + m_struFullLogFile.Reset(); + pStartupInfo->dwFlags = STARTF_USESTDHANDLES; + pStartupInfo->hStdInput = INVALID_HANDLE_VALUE; + pStartupInfo->hStdError = INVALID_HANDLE_VALUE; + pStartupInfo->hStdOutput = INVALID_HANDLE_VALUE; - CloseHandle(hStdoutHandle); + if (m_fStdoutLogEnabled) + { + // Log the error + //if (SUCCEEDED(strEventMsg.SafeSnwprintf( + // ASPNETCORE_EVENT_INVALID_STDOUT_LOG_FILE_MSG, + // m_struFullLogFile.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); + // }*/ + //} + } + } + return hr; } HRESULT @@ -1510,7 +1456,9 @@ SERVER_PROCESS::SendSignal( hr = HRESULT_FROM_WIN32(ERROR_TIMEOUT); goto Finished; } - + // thread should already exit + CloseHandle(hThread); + hThread = NULL; Finished: if (hThread != NULL) @@ -1539,11 +1487,11 @@ Finished: 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 @@ -1882,7 +1830,7 @@ SERVER_PROCESS::StopAllProcessesInJobObject( { if (!TerminateProcess(hProcess, 1)) { - hr = HRESULT_FROM_GETLASTERROR(); + hr = HRESULT_FROM_WIN32(GetLastError()); } else { @@ -1924,7 +1872,7 @@ SERVER_PROCESS::SERVER_PROCESS() : m_hListeningProcessHandle(NULL), m_hShutdownHandle(NULL) { - InterlockedIncrement(&g_dwActiveServerProcesses); + //InterlockedIncrement(&g_dwActiveServerProcesses); srand(GetTickCount()); for (INT i=0; i 1) + 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_struAppPath); + strUrl.Copy(m_struAppVirtualPath); } strUrl.Append(L"/iisintegration"); @@ -2217,7 +2182,7 @@ SERVER_PROCESS::SendShutdownHttpMessage() } // log - if (SUCCEEDED(strEventMsg.SafeSnwprintf( + /*if (SUCCEEDED(strEventMsg.SafeSnwprintf( ASPNETCORE_EVENT_SENT_SHUTDOWN_HTTP_REQUEST_MSG, m_dwProcessId, dwStatusCode))) @@ -2235,7 +2200,7 @@ SERVER_PROCESS::SendShutdownHttpMessage() apsz, NULL); } - } + }*/ Finished: if (hRequest) @@ -2295,7 +2260,8 @@ SERVER_PROCESS::SendShutDownSignalInternal( if (AttachConsole(m_dwProcessId)) { - // call ctrl-break instead of ctrl-c as child process may ignore ctrl-c + // 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 @@ -2325,8 +2291,8 @@ SERVER_PROCESS::TerminateBackendProcess( VOID ) { - LPCWSTR apsz[1]; - STACK_STRU(strEventMsg, 256); + //LPCWSTR apsz[1]; + //STACK_STRU(strEventMsg, 256); if (InterlockedCompareExchange(&m_lStopping, 1L, 0L) == 0L) { @@ -2334,6 +2300,11 @@ SERVER_PROCESS::TerminateBackendProcess( 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; } @@ -2344,12 +2315,8 @@ SERVER_PROCESS::TerminateBackendProcess( 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( + /*if (SUCCEEDED(strEventMsg.SafeSnwprintf( ASPNETCORE_EVENT_GRACEFUL_SHUTDOWN_FAILURE_MSG, m_dwProcessId))) { @@ -2366,6 +2333,6 @@ SERVER_PROCESS::TerminateBackendProcess( apsz, NULL); } - } + }*/ } } \ No newline at end of file diff --git a/src/AspNetCore/Inc/serverprocess.h b/src/RequestHandler/outofprocess/serverprocess.h similarity index 83% rename from src/AspNetCore/Inc/serverprocess.h rename to src/RequestHandler/outofprocess/serverprocess.h index 16a7fd33e6..04579fc372 100644 --- a/src/AspNetCore/Inc/serverprocess.h +++ b/src/RequestHandler/outofprocess/serverprocess.h @@ -23,7 +23,6 @@ #define ASPNETCORE_IIS_AUTH_NONE L"none" class PROCESS_MANAGER; -class FORWARDER_CONNECTION; class SERVER_PROCESS { @@ -42,14 +41,14 @@ public: _In_ BOOL fAnonymousAuthEnabled, _In_ ENVIRONMENT_VAR_HASH* pEnvironmentVariables, _In_ BOOL fStdoutLogEnabled, - _In_ STRU *pstruStdoutLogFile + _In_ STRU *pstruStdoutLogFile, + _In_ STRU *pszAppPhysicalPath, + _In_ STRU *pszAppPath, + _In_ STRU *pszAppVirtualPath ); - HRESULT - StartProcess( - _In_ IHttpContext *context - ); + StartProcess( VOID ); HRESULT SetWindowsAuthToken( @@ -70,7 +69,7 @@ public: VOID ); - DWORD + DWORD GetPort() { return m_dwPort; @@ -90,7 +89,6 @@ public: ) { _ASSERT(m_cRefs != 0 ); - if (InterlockedDecrement(&m_cRefs) == 0) { delete this; @@ -100,7 +98,15 @@ public: virtual ~SERVER_PROCESS(); - HRESULT + static + VOID + CALLBACK + ProcessHandleCallback( + _In_ PVOID pContext, + _In_ BOOL + ); + + HRESULT HandleProcessExit( VOID ); @@ -113,38 +119,11 @@ public: 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( @@ -165,8 +144,7 @@ private: HRESULT SetupStdHandles( - _In_ IHttpContext *context, - _In_ LPSTARTUPINFOW pStartupInfo + _Inout_ LPSTARTUPINFOW pStartupInfo ); HRESULT @@ -184,6 +162,7 @@ private: HRESULT GetChildProcessHandles( + VOID ); HRESULT @@ -193,7 +172,6 @@ private: HRESULT SetupAppPath( - IHttpContext* pContext, ENVIRONMENT_VAR_HASH* pEnvironmentVarTable ); @@ -220,8 +198,7 @@ private: HRESULT PostStartCheck( - const STRU* const pStruCommandline, - STRU* pStruErrorMessage + VOID ); HRESULT @@ -230,28 +207,6 @@ private: 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( @@ -286,10 +241,12 @@ private: STRU m_struFullLogFile; STRU m_ProcessPath; STRU m_Arguments; - STRU m_struAppPath; - STRU m_struAppFullPath; + 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_pszRootApplicationPath; + STRU m_struCommandLine; + volatile LONG m_lStopping; volatile BOOL m_fReady; mutable LONG m_cRefs; diff --git a/src/AspNetCore/Src/websockethandler.cxx b/src/RequestHandler/outofprocess/websockethandler.cxx similarity index 99% rename from src/AspNetCore/Src/websockethandler.cxx rename to src/RequestHandler/outofprocess/websockethandler.cxx index 1958c6a9c4..c64bbe4adb 100644 --- a/src/AspNetCore/Src/websockethandler.cxx +++ b/src/RequestHandler/outofprocess/websockethandler.cxx @@ -27,7 +27,7 @@ This prevents the need for data buffering at the Asp.Net Core Module level. --*/ -#include "precomp.hxx" +#include "..\precomp.hxx" SRWLOCK WEBSOCKET_HANDLER::sm_RequestsListLock; @@ -48,7 +48,6 @@ WEBSOCKET_HANDLER::WEBSOCKET_HANDLER() : DebugPrintf (ASPNETCORE_DEBUG_FLAG_INFO, "WEBSOCKET_HANDLER::WEBSOCKET_HANDLER"); InitializeCriticalSectionAndSpinCount(&_RequestLock, 1000); - InsertRequest(); } @@ -103,7 +102,6 @@ WEBSOCKET_HANDLER::StaticInitialize( // If tracing is enabled, keep track of all websocket requests // for debugging purposes. // - InitializeListHead (&sm_RequestsListHead); sm_pTraceLog = CreateRefTraceLog( 10000, 0 ); } @@ -137,9 +135,7 @@ WEBSOCKET_HANDLER::InsertRequest( if (g_fEnableReferenceCountTracing) { AcquireSRWLockExclusive(&sm_RequestsListLock); - InsertTailList(&sm_RequestsListHead, &_listEntry); - ReleaseSRWLockExclusive( &sm_RequestsListLock); } } @@ -153,9 +149,7 @@ WEBSOCKET_HANDLER::RemoveRequest( if (g_fEnableReferenceCountTracing) { AcquireSRWLockExclusive(&sm_RequestsListLock); - RemoveEntryList(&_listEntry); - ReleaseSRWLockExclusive( &sm_RequestsListLock); } } @@ -166,7 +160,6 @@ WEBSOCKET_HANDLER::IncrementOutstandingIo( ) { InterlockedIncrement(&_dwOutstandingIo); - if (sm_pTraceLog) { WriteRefTraceLog(sm_pTraceLog, _dwOutstandingIo, this); @@ -213,8 +206,8 @@ WEBSOCKET_HANDLER::IndicateCompletionToIIS( --*/ { - DebugPrintf (ASPNETCORE_DEBUG_FLAG_INFO, - "WEBSOCKET_HANDLER::IndicateCompletionToIIS"); + /*DebugPrintf (ASPNETCORE_DEBUG_FLAG_INFO, + "WEBSOCKET_HANDLER::IndicateCompletionToIIS");*/ _pHandler->SetStatus(FORWARDER_DONE); @@ -254,14 +247,12 @@ Routine Description: _pHandler = pHandler; EnterCriticalSection(&_RequestLock); - DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO, "WEBSOCKET_HANDLER::ProcessRequest"); // // Cache the points to IHttpContext3 // - hr = HttpGetExtendedInterface(g_pHttpServer, pHttpContext, &_pHttpContext); @@ -285,7 +276,6 @@ Routine Description: // // Get Handle to Winhttp's websocket context. // - _hWebSocketRequest = WINHTTP_HELPER::sm_pfnWinHttpWebSocketCompleteUpgrade( hRequest, (DWORD_PTR) pHandler); @@ -331,7 +321,6 @@ Routine Description: // // Initiate Read on IIS // - hr = DoIisWebSocketReceive(); if (FAILED(hr)) { @@ -374,7 +363,6 @@ Routine Description: --*/ { HRESULT hr = S_OK; - DWORD dwBufferSize = RECEIVE_BUFFER_SIZE; BOOL fUtf8Encoded; BOOL fFinalFragment; @@ -398,10 +386,8 @@ Routine Description: if (FAILED(hr)) { DecrementOutstandingIo(); - DebugPrintf(ASPNETCORE_DEBUG_FLAG_ERROR, "WEBSOCKET_HANDLER::DoIisWebSocketSend failed with %08x", hr); - } return hr; @@ -438,12 +424,9 @@ Routine Description: if (dwError != NO_ERROR) { DecrementOutstandingIo(); - hr = HRESULT_FROM_WIN32(dwError); - DebugPrintf(ASPNETCORE_DEBUG_FLAG_ERROR, "WEBSOCKET_HANDLER::DoWinHttpWebSocketReceive failed with %08x", hr); - } return hr; @@ -463,7 +446,6 @@ Routine Description: --*/ { HRESULT hr = S_OK; - BOOL fUtf8Encoded = FALSE; BOOL fFinalFragment = FALSE; BOOL fClose = FALSE; @@ -498,7 +480,6 @@ Routine Description: // // Convert close reason to WCHAR // - hr = strCloseReason.CopyA((PCSTR)&_WinHttpReceiveBuffer, dwReceived); if (FAILED(hr)) @@ -517,7 +498,6 @@ Routine Description: // // Send close to IIS. // - hr = _pWebSocketContext->SendConnectionClose( TRUE, uStatus, @@ -542,7 +522,6 @@ Routine Description: // // Do the Send. // - hr = _pWebSocketContext->WriteFragment( &_WinHttpReceiveBuffer, &cbData, @@ -552,7 +531,6 @@ Routine Description: OnWriteIoCompletion, this, NULL); - } if (FAILED(hr)) @@ -598,7 +576,6 @@ Routine Description: // // Get Close status from IIS. // - hr = _pWebSocketContext->GetCloseStatus(&uStatus, &pszReason); @@ -610,7 +587,6 @@ Routine Description: // // Convert status to UTF8 // - hr = strCloseReason.CopyWToUTF8Unescaped(pszReason); if (FAILED(hr)) { @@ -622,7 +598,6 @@ Routine Description: // // Send Close. // - dwError = WINHTTP_HELPER::sm_pfnWinHttpWebSocketShutdown( _hWebSocketRequest, uStatus, @@ -635,7 +610,6 @@ Routine Description: // Call will complete asynchronously, return. // ignore error. // - DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO, "WEBSOCKET_HANDLER::DoWinhttpWebSocketSend IO_PENDING"); @@ -648,7 +622,6 @@ Routine Description: // // Call completed synchronously. // - DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO, "WEBSOCKET_HANDLER::DoWinhttpWebSocketSend Shutdown successful."); } @@ -810,7 +783,6 @@ Finished: // The handler object can be gone after this call. // do not reference it after this statement. // - DecrementOutstandingIo(); return hr; @@ -841,7 +813,6 @@ WEBSOCKET_HANDLER::OnWinHttpIoError( hr, pCompletionStatus->AsyncResult.dwResult); Cleanup(ServerDisconnect); - DecrementOutstandingIo(); return hr; diff --git a/src/AspNetCore/Inc/websockethandler.h b/src/RequestHandler/outofprocess/websockethandler.h similarity index 98% rename from src/AspNetCore/Inc/websockethandler.h rename to src/RequestHandler/outofprocess/websockethandler.h index 845452760d..f29c268658 100644 --- a/src/AspNetCore/Inc/websockethandler.h +++ b/src/RequestHandler/outofprocess/websockethandler.h @@ -3,6 +3,7 @@ #pragma once +extern IHttpServer * g_pHttpServer; class FORWARDING_HANDLER; class WEBSOCKET_HANDLER diff --git a/src/AspNetCore/Src/winhttphelper.cxx b/src/RequestHandler/outofprocess/winhttphelper.cxx similarity index 99% rename from src/AspNetCore/Src/winhttphelper.cxx rename to src/RequestHandler/outofprocess/winhttphelper.cxx index 6985c6aed1..ce4256a710 100644 --- a/src/AspNetCore/Src/winhttphelper.cxx +++ b/src/RequestHandler/outofprocess/winhttphelper.cxx @@ -1,7 +1,7 @@ // 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 "..\precomp.hxx" PFN_WINHTTP_WEBSOCKET_COMPLETE_UPGRADE WINHTTP_HELPER::sm_pfnWinHttpWebSocketCompleteUpgrade; diff --git a/src/AspNetCore/Inc/winhttphelper.h b/src/RequestHandler/outofprocess/winhttphelper.h similarity index 100% rename from src/AspNetCore/Inc/winhttphelper.h rename to src/RequestHandler/outofprocess/winhttphelper.h diff --git a/src/RequestHandler/precomp.hxx b/src/RequestHandler/precomp.hxx new file mode 100644 index 0000000000..a12c49cde9 --- /dev/null +++ b/src/RequestHandler/precomp.hxx @@ -0,0 +1,119 @@ +// 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +// 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 +#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 "aspnetcore_event.h" +#include "aspnetcore_msg.h" +#include "disconnectcontext.h" +#include "sttimer.h" +#include "resource.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 inline T max(T a, T b) +{ + return a > b ? a : b; +} +#endif + +#ifdef min +#undef min +template inline T min(T a, T b) +{ + return a < b ? a : b; +} +#endif + +#define ASPNETCORE_EVENT_PROVIDER L"IIS AspNetCore Module" +#define ASPNETCORE_IISEXPRESS_EVENT_PROVIDER L"IIS Express AspNetCore Module" + +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 DWORD g_dwActiveServerProcesses; +extern DWORD g_OptionalWinHttpFlags; +extern SRWLOCK g_srwLockRH; +extern HINTERNET g_hWinhttpSession; +extern DWORD g_dwTlsIndex; diff --git a/src/RequestHandler/resource.h b/src/RequestHandler/resource.h new file mode 100644 index 0000000000..a8f93c62fb --- /dev/null +++ b/src/RequestHandler/resource.h @@ -0,0 +1,24 @@ +// 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_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' processStatus code '%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_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 '%s' 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_MSG L"Application '%s' with physical root '%s' hit unexpected managed background thread exit, ErrorCode = '0x%x." diff --git a/src/AspNetCore/Inc/sttimer.h b/src/RequestHandler/sttimer.h similarity index 83% rename from src/AspNetCore/Inc/sttimer.h rename to src/RequestHandler/sttimer.h index ebed8510a1..1bd4b67543 100644 --- a/src/AspNetCore/Inc/sttimer.h +++ b/src/RequestHandler/sttimer.h @@ -1,6 +1,8 @@ // 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 @@ -111,6 +113,41 @@ public: 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 diff --git a/src/RequestHandler/version.h b/src/RequestHandler/version.h new file mode 100644 index 0000000000..cb2793c49a --- /dev/null +++ b/src/RequestHandler/version.h @@ -0,0 +1,8 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +#define FileVersion 7,1,1987,0 +#define FileVersionStr "7.1.1987.0\0" +#define ProductVersion 7,1,1987,0 +#define ProductVersionStr "7.1.1987.0\0" +#define PlatformToolset "v141\0" diff --git a/test/Directory.Build.props b/test/Directory.Build.props index 1a9321c4b3..3a74fe4d2a 100644 --- a/test/Directory.Build.props +++ b/test/Directory.Build.props @@ -1,7 +1,6 @@ -<<<<<<< HEAD netcoreapp2.1 $(DeveloperBuildTestTfms) @@ -13,9 +12,3 @@ -======= - - - -
->>>>>>> ANCM/dev diff --git a/version.props b/version.props index cc08cc8495..5c4a7c32d1 100644 --- a/version.props +++ b/version.props @@ -1,21 +1,10 @@ -<<<<<<< HEAD 2.1.0 preview1 -======= - 7 - 1 - 1987 - -RTM ->>>>>>> ANCM/dev $(VersionPrefix) $(VersionPrefix)-$(VersionSuffix)-final t000 $(VersionSuffix)-$(BuildNumber) -<<<<<<< HEAD -======= -
->>>>>>> ANCM/dev