merged
This commit is contained in:
commit
8949f49637
|
|
@ -25,6 +25,7 @@ project.lock.json
|
|||
*.ncrunchsolution
|
||||
*.*sdf
|
||||
*.ipch
|
||||
<<<<<<< HEAD
|
||||
*.vs/
|
||||
.vscode/
|
||||
.testPublish/
|
||||
|
|
@ -32,3 +33,31 @@ project.lock.json
|
|||
*.nuget.props
|
||||
*.nuget.targets
|
||||
global.json
|
||||
=======
|
||||
*.bin
|
||||
*.vs/
|
||||
.testPublish/
|
||||
|
||||
*.obj
|
||||
*.tlog
|
||||
*.CppClean.log
|
||||
|
||||
src/*/Debug/
|
||||
src/*/x64/Debug/
|
||||
src/*/Release/
|
||||
src/*/x64/Release/
|
||||
|
||||
*.aps
|
||||
*.pdb
|
||||
*.lib
|
||||
*.idb
|
||||
|
||||
src/AspNetCore/aspnetcore_msg.h
|
||||
src/AspNetCore/aspnetcore_msg.rc
|
||||
src/AspNetCore/version.h
|
||||
.build
|
||||
|
||||
*.VC.*db
|
||||
global.json
|
||||
|
||||
>>>>>>> ANCM/dev
|
||||
|
|
|
|||
|
|
@ -0,0 +1,93 @@
|
|||
|
||||
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
|
||||
|
|
@ -1,12 +1,17 @@
|
|||
<<<<<<< HEAD
|
||||
<Project>
|
||||
<Import
|
||||
Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), AspNetCoreSettings.props))\AspNetCoreSettings.props"
|
||||
Condition=" '$(CI)' != 'true' AND '$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), AspNetCoreSettings.props))' != '' " />
|
||||
|
||||
=======
|
||||
<Project>
|
||||
>>>>>>> ANCM/dev
|
||||
<Import Project="version.props" />
|
||||
<Import Project="build\dependencies.props" />
|
||||
<Import Project="build\sources.props" />
|
||||
|
||||
<<<<<<< HEAD
|
||||
<PropertyGroup>
|
||||
<Product>Microsoft ASP.NET Core</Product>
|
||||
<RepositoryUrl>https://github.com/aspnet/IISIntegration</RepositoryUrl>
|
||||
|
|
@ -23,4 +28,14 @@
|
|||
<PackageReference Include="Microsoft.NETCore.Compilers" Version="$(MicrosoftNETCoreCompilersPackageVersion)" PrivateAssets="All" />
|
||||
</ItemGroup>
|
||||
|
||||
=======
|
||||
<PropertyGroup>
|
||||
<Product>Microsoft ASP.NET Core</Product>
|
||||
<RepositoryUrl>https://github.com/aspnet/AspNetCoreModule</RepositoryUrl>
|
||||
<RepositoryType>git</RepositoryType>
|
||||
<AssemblyOriginatorKeyFile>$(MSBuildThisFileDirectory)build\Key.snk</AssemblyOriginatorKeyFile>
|
||||
<SignAssembly>true</SignAssembly>
|
||||
<PublicSign Condition="'$(OS)' != 'Windows_NT'">true</PublicSign>
|
||||
</PropertyGroup>
|
||||
>>>>>>> ANCM/dev
|
||||
</Project>
|
||||
|
|
|
|||
26
LICENSE.txt
26
LICENSE.txt
|
|
@ -1,3 +1,4 @@
|
|||
<<<<<<< HEAD
|
||||
Copyright (c) .NET Foundation and Contributors
|
||||
|
||||
All rights reserved.
|
||||
|
|
@ -12,3 +13,28 @@ Unless required by applicable law or agreed to in writing, software distributed
|
|||
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations under the License.
|
||||
=======
|
||||
ASP.NET Core Module
|
||||
|
||||
Copyright (c) .NET Foundation
|
||||
All rights reserved.
|
||||
|
||||
MIT License
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the ""Software""), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
>>>>>>> ANCM/dev
|
||||
|
|
|
|||
80
README.md
80
README.md
|
|
@ -1,6 +1,86 @@
|
|||
<<<<<<< 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
|
||||
|
||||
The ASP.NET Core Module is an IIS Module which is responsible for process
|
||||
management of ASP.NET Core http listeners and to proxy requests to the process
|
||||
that it manages.
|
||||
|
||||
## Installing the latest ASP.NET Core Module
|
||||
The ASP.NET Core Module for IIS can be installed on servers without installing the .NET Core runtime. You can download the [Windows (Server Hosting) installer](https://go.microsoft.com/fwlink/?linkid=832756) and run the following command from an Administrator command prompt:
|
||||
``DotNetCore.1.1.0.Preview1-WindowsHosting.exe OPT_INSTALL_LTS_REDIST=0 OPT_INSTALL_FTS_REDIST=0``
|
||||
|
||||
## Pre-requisites for building
|
||||
|
||||
### Windows 8.1+ or Windows Server 2012 R2+
|
||||
|
||||
### Visual C++ Build Tools
|
||||
|
||||
[Download](http://download.microsoft.com/download/D/2/3/D23F4D0F-BA2D-4600-8725-6CCECEA05196/vs_community_ENU.exe)
|
||||
and install Visual Studio 2015. In Visual Studio 2015 C++ tooling is no longer
|
||||
installed by default, you must chose "Custom" install and select Visual C++.
|
||||
|
||||

|
||||
|
||||
Optionally, if you don't want to install Visual Studio you can just install the
|
||||
[Visual C++ build tools](http://landinghub.visualstudio.com/visual-cpp-build-tools).
|
||||
|
||||
### MSBuild
|
||||
|
||||
If you have installed Visual Studio, you should already have MSBuild. If you
|
||||
installed the Visual C++ build tools, you will need to download and install
|
||||
[Microsoft Build Tools 2015](https://www.microsoft.com/en-us/download/details.aspx?id=48159)
|
||||
|
||||
Once you have installed MSBuild, you can add it your path. The default location
|
||||
for MSBuild is `%ProgramFiles(x86)%\MSBuild\14.0\Bin`
|
||||
|
||||
### Windows Software Development Kit for Windows 8.1
|
||||
|
||||
[Download](http://download.microsoft.com/download/B/0/C/B0C80BA3-8AD6-4958-810B-6882485230B5/standalonesdk/sdksetup.exe)
|
||||
and install the Windows SDK for Windows 8.1. From the Feature list presented,
|
||||
ensure you select *Windows Software Development Kit*.
|
||||
|
||||
If chose to install from the command prompt, you can run the following command.
|
||||
````
|
||||
.\sdksetup.exe /features OptionId.WindowsDesktopSoftwareDevelopmentKit
|
||||
````
|
||||
|
||||
## How to build
|
||||
|
||||
|
||||
```powershell
|
||||
|
||||
# Clean
|
||||
.\build.cmd /target:clean
|
||||
|
||||
# Build
|
||||
.\build.cmd
|
||||
|
||||
# Build 64-bit
|
||||
.\build.cmd /property:platform=x64
|
||||
|
||||
# Build in Release Configuration
|
||||
.\build.cmd /property:configuration=release
|
||||
```
|
||||
|
||||
## Contributions
|
||||
|
||||
Check out the [contributing](https://github.com/aspnet/Home/blob/dev/CONTRIBUTING.md)
|
||||
page to see the best places to log issues and start discussions.
|
||||
|
||||
This project has adopted the code of conduct defined by the [Contributor Covenant](http://contributor-covenant.org/)
|
||||
to clarify expected behavior in our community.
|
||||
For more information see the [.NET Foundation Code of Conduct](http://www.dotnetfoundation.org/code-of-conduct).
|
||||
|
||||
### .NET Foundation
|
||||
|
||||
This project is supported by the [.NET Foundation](http://www.dotnetfoundation.org).
|
||||
|
||||
|
||||
>>>>>>> ANCM/dev
|
||||
|
|
|
|||
|
|
@ -1,2 +1,6 @@
|
|||
@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
|
||||
|
|
|
|||
|
|
@ -0,0 +1,87 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">$(MSBuildThisFileDirectory)..\</SolutionDir>
|
||||
<Configuration Condition="'$(Configuration)'==''">Debug</Configuration>
|
||||
<Platform Condition="'$(Platform)' == ''">Win32</Platform>
|
||||
<PlatformToolset Condition=" '$(VisualStudioVersion)' == '12.0'">v120</PlatformToolset>
|
||||
<PlatformToolset Condition=" '$(VisualStudioVersion)' == '14.0'">v140</PlatformToolset>
|
||||
<PlatformToolset Condition=" '$(PlatformToolset)' == ''">v120</PlatformToolset>
|
||||
<OutputPath Condition="'$(OutputPath)' == ''">$(MSBuildProjectDirectory)\bin\$(Configuration)\$(Platform)\</OutputPath>
|
||||
<OutDir>$(OutputPath)</OutDir>
|
||||
<AspNetCoreModuleTargetName>aspnetcore</AspNetCoreModuleTargetName>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)' == 'Debug'">
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<WholeProgramOptimization>false</WholeProgramOptimization>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)' == 'Release'">
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<TreatWarningAsError Condition="'$(TreatWarningsAsErrors)' != ''">true</TreatWarningAsError>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<StringPooling>true</StringPooling>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<ProgramDatabaseFile>$(OutDir)$(TargetName).pdb</ProgramDatabaseFile>
|
||||
<StripPrivateSymbols>$(OutDir)$(TargetName).pub.pdb</StripPrivateSymbols>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<Profile>true</Profile>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)'=='Debug'">
|
||||
<ClCompile>
|
||||
<Optimization>Disabled</Optimization>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)'=='Release'">
|
||||
<ClCompile>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<PreprocessorDefinitions>_WIN64;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<PreprocessorDefinitions>_WIN64;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="12.0" DefaultTargets="Test" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildThisFileDirectory)\Build.Settings" />
|
||||
<ItemGroup>
|
||||
<Projects Include="$(SolutionDir)\src\AspNetCore\AspNetCore.vcxproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<Target Name="Build">
|
||||
<MSBuild Targets="$(BuildTargets)"
|
||||
Projects="@(Projects)"
|
||||
Properties="Configuration=$(Configuration);Platform=$(Platform);PlatformToolset=$(PlatformToolset)" />
|
||||
</Target>
|
||||
|
||||
<Target Name="Clean">
|
||||
<MSBuild Targets="Clean"
|
||||
Projects="@(Projects)" />
|
||||
</Target>
|
||||
|
||||
<Target Name="Rebuild">
|
||||
<MSBuild Targets="Clean;Build"
|
||||
Projects="$(MSBuildProjectFile)"
|
||||
Properties="BuildTargets=Rebuild;Configuration=$(Configuration);Platform=$(Platform);PlatformToolset=$(PlatformToolset)"/>
|
||||
</Target>
|
||||
|
||||
<Target Name="Test" DependsOnTargets="Build">
|
||||
<!-- once we have test project ready, we should add executions to run the test post build-->
|
||||
</Target>
|
||||
<Import Project="Config.Definitions.Props" />
|
||||
</Project>
|
||||
|
|
@ -4,6 +4,7 @@
|
|||
</PropertyGroup>
|
||||
<PropertyGroup Label="Package Versions">
|
||||
<InternalAspNetCoreSdkPackageVersion>2.1.0-preview1-15576</InternalAspNetCoreSdkPackageVersion>
|
||||
<MicrosoftAspNetCoreAllPackageVersion>2.0.0</MicrosoftAspNetCoreAllPackageVersion>
|
||||
<MicrosoftAspNetCoreAspNetCoreModulePackageVersion>1.0.0-pre-10202</MicrosoftAspNetCoreAspNetCoreModulePackageVersion>
|
||||
<MicrosoftAspNetCoreAuthenticationCorePackageVersion>2.1.0-preview1-27644</MicrosoftAspNetCoreAuthenticationCorePackageVersion>
|
||||
<MicrosoftAspNetCoreHostingAbstractionsPackageVersion>2.1.0-preview1-27644</MicrosoftAspNetCoreHostingAbstractionsPackageVersion>
|
||||
|
|
@ -15,6 +16,7 @@
|
|||
<MicrosoftAspNetCoreServerIntegrationTestingPackageVersion>0.5.0-preview1-27644</MicrosoftAspNetCoreServerIntegrationTestingPackageVersion>
|
||||
<MicrosoftAspNetCoreServerKestrelPackageVersion>2.1.0-preview1-27644</MicrosoftAspNetCoreServerKestrelPackageVersion>
|
||||
<MicrosoftAspNetCoreTestHostPackageVersion>2.1.0-preview1-27644</MicrosoftAspNetCoreTestHostPackageVersion>
|
||||
<MicrosoftAspNetCoreTestingPackageVersion>2.1.0-preview1-27644</MicrosoftAspNetCoreTestingPackageVersion>
|
||||
<MicrosoftAspNetCoreWebUtilitiesPackageVersion>2.1.0-preview1-27644</MicrosoftAspNetCoreWebUtilitiesPackageVersion>
|
||||
<MicrosoftExtensionsConfigurationEnvironmentVariablesPackageVersion>2.1.0-preview1-27644</MicrosoftExtensionsConfigurationEnvironmentVariablesPackageVersion>
|
||||
<MicrosoftExtensionsConfigurationJsonPackageVersion>2.1.0-preview1-27644</MicrosoftExtensionsConfigurationJsonPackageVersion>
|
||||
|
|
@ -24,6 +26,7 @@
|
|||
<MicrosoftExtensionsLoggingPackageVersion>2.1.0-preview1-27644</MicrosoftExtensionsLoggingPackageVersion>
|
||||
<MicrosoftExtensionsLoggingTestingPackageVersion>2.1.0-preview1-27644</MicrosoftExtensionsLoggingTestingPackageVersion>
|
||||
<MicrosoftExtensionsOptionsPackageVersion>2.1.0-preview1-27644</MicrosoftExtensionsOptionsPackageVersion>
|
||||
<MicrosoftExtensionsPlatformAbstractionsPackageVersion>1.1.0</MicrosoftExtensionsPlatformAbstractionsPackageVersion>
|
||||
<MicrosoftExtensionsSecurityHelperSourcesPackageVersion>2.1.0-preview1-27644</MicrosoftExtensionsSecurityHelperSourcesPackageVersion>
|
||||
<MicrosoftNETCoreApp20PackageVersion>2.0.0</MicrosoftNETCoreApp20PackageVersion>
|
||||
<MicrosoftNETCoreApp21PackageVersion>2.1.0-preview1-25907-02</MicrosoftNETCoreApp21PackageVersion>
|
||||
|
|
@ -31,6 +34,7 @@
|
|||
<MicrosoftNETTestSdkPackageVersion>15.3.0</MicrosoftNETTestSdkPackageVersion>
|
||||
<SystemBuffersPackageVersion>4.4.0</SystemBuffersPackageVersion>
|
||||
<SystemIOPipelinesPackageVersion>0.1.0-alpha-002</SystemIOPipelinesPackageVersion>
|
||||
<SystemManagementAutomationDllPackageVersion>10.0.10586</SystemManagementAutomationDllPackageVersion>
|
||||
<SystemMemoryPackageVersion>4.5.0-preview1-25902-08</SystemMemoryPackageVersion>
|
||||
<SystemNumericsVectorsPackageVersion>4.5.0-preview1-25902-08</SystemNumericsVectorsPackageVersion>
|
||||
<SystemRuntimeCompilerServicesUnsafePackageVersion>4.5.0-preview1-25902-08</SystemRuntimeCompilerServicesUnsafePackageVersion>
|
||||
|
|
@ -38,6 +42,10 @@
|
|||
<SystemTextEncodingsWebUtf8PackageVersion>0.1.0-alpha-002</SystemTextEncodingsWebUtf8PackageVersion>
|
||||
<XunitPackageVersion>2.3.0</XunitPackageVersion>
|
||||
<XunitRunnerVisualStudioPackageVersion>2.3.0</XunitRunnerVisualStudioPackageVersion>
|
||||
|
||||
<MicrosoftWebAdministrationPackageVersion>7.0.0</MicrosoftWebAdministrationPackageVersion>
|
||||
<MicrosoftNetHttpHeadersPackageVersion>2.0.0</MicrosoftNetHttpHeadersPackageVersion>
|
||||
|
||||
</PropertyGroup>
|
||||
<Import Project="$(DotNetPackageVersionPropsPath)" Condition=" '$(DotNetPackageVersionPropsPath)' != '' " />
|
||||
</Project>
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
<<<<<<< HEAD
|
||||
<Project>
|
||||
<Import Project="dependencies.props" />
|
||||
|
||||
|
|
@ -6,7 +7,15 @@
|
|||
<ExcludeFromTest Include="$(RepositoryRoot)test\IISTestSite\*.csproj" />
|
||||
<ExcludeFromTest Include="$(RepositoryRoot)test\IISIntegration.FunctionalTests\*.csproj" Condition="'$(OS)' != 'Windows_NT'" />
|
||||
<ExcludeFromTest Include="$(RepositoryRoot)test\IISIntegration.IISServerFunctionalTests\*.csproj" Condition="'$(OS)' != 'Windows_NT'" />
|
||||
<ExcludeFromTest Include="$(RepositoryRoot)test\AspNetCoreModule.TestSites.Standard\*.csproj" />
|
||||
<ExcludeFromTest Include="$(RepositoryRoot)test\WebSocketClientEXE\*.csproj" />
|
||||
<ExcludeFromTest Include="$(RepositoryRoot)test\AspNetCoreModule.Test\*.csproj" Condition="'$(OS)' != 'Windows_NT'" />
|
||||
</ItemGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<!-- These properties are use by the automation that updates dependencies.props -->
|
||||
<LineupPackageId>Internal.AspNetCore.Universe.Lineup</LineupPackageId>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,43 @@
|
|||
<Project>
|
||||
<PropertyGroup>
|
||||
<PublishFeed>https://dotnet.myget.org/F/aspnetcoremodule/api/v2/package</PublishFeed>
|
||||
<VerifyDependsOn>$(VerifyDependsOn);PublishPackage</VerifyDependsOn>
|
||||
</PropertyGroup>
|
||||
|
||||
<Target Name="BuildNativeAssets" DependsOnTargets="GetToolsets" BeforeTargets="Compile" >
|
||||
<ItemGroup>
|
||||
<BuildConfigurations Include="/p:Configuration=Release /p:platform=Win32" />
|
||||
<BuildConfigurations Include="/p:Configuration=Release /p:platform=x64" />
|
||||
</ItemGroup>
|
||||
|
||||
<Error
|
||||
Text="Could not find an installation of Visual Studio with the C++ development tools."
|
||||
Condition="'$(VisualStudioMSBuildx86Path)' == ''" />
|
||||
|
||||
<Exec Command=""$(VisualStudioMSBuildx86Path)" "$(RepositoryRoot)src\AspNetCore\AspNetCore.vcxproj" %(BuildConfigurations.Identity)"
|
||||
Condition="'$(VisualStudioMSBuildx86Path)' != ''" />
|
||||
</Target>
|
||||
|
||||
<Target Name="PackageProjects">
|
||||
<PropertyGroup>
|
||||
<PackageVersion>1.0.0-pre-$(BuildNumber)</PackageVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<MSBuild
|
||||
Projects="$(MSBuildThisFileDirectory)../nuget/AspNetCore.csproj"
|
||||
Targets="Restore;Pack"
|
||||
Properties="PackageVersion=$(PackageVersion);PackageOutputPath=$(BuildDir)" />
|
||||
</Target>
|
||||
|
||||
<Target Name="PublishPackage" Condition="'$(PublishPackage)'=='true'">
|
||||
<ItemGroup>
|
||||
<PackagesToPush Include="$(BuildDir)*.nupkg" />
|
||||
</ItemGroup>
|
||||
|
||||
<PushNuGetPackages
|
||||
Packages="@(PackagesToPush)"
|
||||
Feed="$(PublishFeed)"
|
||||
ApiKey="$(APIKey)" />
|
||||
</Target>
|
||||
|
||||
</Project>
|
||||
|
|
@ -1,4 +1,8 @@
|
|||
<<<<<<< HEAD
|
||||
<Project>
|
||||
=======
|
||||
<Project>
|
||||
>>>>>>> ANCM/dev
|
||||
<Import Project="$(DotNetRestoreSourcePropsPath)" Condition="'$(DotNetRestoreSourcePropsPath)' != ''"/>
|
||||
|
||||
<PropertyGroup Label="RestoreSources">
|
||||
|
|
|
|||
|
|
@ -1,2 +1,7 @@
|
|||
<<<<<<< HEAD
|
||||
version:2.1.0-preview1-15576
|
||||
commithash:2f3856d2ba4f659fcb9253215b83946a06794a27
|
||||
=======
|
||||
version:2.1.0-preview1-15620
|
||||
commithash:6432b49a2c00310416df39b6fe548ef4af9c6011
|
||||
>>>>>>> ANCM/dev
|
||||
|
|
|
|||
|
|
@ -1,4 +1,20 @@
|
|||
{
|
||||
<<<<<<< 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": {
|
||||
"visualstudio": {
|
||||
"required": ["Windows"],
|
||||
"includePrerelease": true,
|
||||
"minVersion": "15.0.26730.03",
|
||||
"requiredWorkloads": [
|
||||
"Microsoft.VisualStudio.Component.VC.Tools.x86.x64"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
>>>>>>> ANCM/dev
|
||||
|
|
|
|||
|
|
@ -0,0 +1,9 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard1.0</TargetFramework>
|
||||
<NuspecFile>$(MSBuildThisFileDirectory)AspNetCore.nuspec</NuspecFile>
|
||||
<NuspecProperties>version=$(PackageVersion)</NuspecProperties>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
<?xml version="1.0"?>
|
||||
<package xmlns="http://schemas.microsoft.com/packaging/2013/05/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>Microsoft.AspNetCore.AspNetCoreModule</id>
|
||||
<title>Microsoft ASP.NET Core Module</title>
|
||||
<version>$VERSION$</version>
|
||||
<authors>Microsoft</authors>
|
||||
<owners>Microsoft</owners>
|
||||
<licenseUrl>http://www.microsoft.com/web/webpi/eula/net_library_eula_ENU.htm</licenseUrl>
|
||||
<copyright>© .NET Foundation. All rights reserved.</copyright>
|
||||
<projectUrl>http://www.asp.net/</projectUrl>
|
||||
<requireLicenseAcceptance>true</requireLicenseAcceptance>
|
||||
<description>ASP.NET Core Module</description>
|
||||
<language>en-US</language>
|
||||
<tags>Microsoft.AspNetCore.AspNetCoreModule</tags>
|
||||
<contentFiles>
|
||||
<files include="any/any/*/*.dll" buildAction="None" copyToOutput="true" flatten="false" />
|
||||
</contentFiles>
|
||||
</metadata>
|
||||
<files>
|
||||
<file src="..\artifacts\build\AspNetCore\bin\Release\Win32\aspnetcore.dll" target="contentFiles\any\any\x86\aspnetcore.dll" />
|
||||
<file src="..\artifacts\build\AspNetCore\bin\Release\x64\aspnetcore.dll" target="contentFiles\any\any\x64\aspnetcore.dll" />
|
||||
<file src="..\artifacts\build\AspNetCore\bin\Release\x64\*.xml"/>
|
||||
<file src="..\tools\installancm.ps1"/>
|
||||
<file src="..\LICENSE.txt"/>
|
||||
<file src="Microsoft.AspNetCore.AspNetCoreModule.props" target="build\" />
|
||||
</files>
|
||||
</package>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<Project>
|
||||
|
||||
<PropertyGroup>
|
||||
<AspNetCoreModuleX64Location>$(MSBuildThisFileDirectory)..\contentFiles\any\any\x64\aspnetcore.dll</AspNetCoreModuleX64Location>
|
||||
<AspNetCoreModuleX86Location>$(MSBuildThisFileDirectory)..\contentFiles\any\any\x86\aspnetcore.dll</AspNetCoreModuleX86Location>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
4
run.cmd
4
run.cmd
|
|
@ -1,2 +1,6 @@
|
|||
@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
|
||||
|
|
|
|||
34
run.ps1
34
run.ps1
|
|
@ -29,9 +29,12 @@ 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
|
||||
|
||||
|
|
@ -54,7 +57,11 @@ 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')]
|
||||
|
|
@ -66,7 +73,10 @@ param(
|
|||
[Alias('u')]
|
||||
[switch]$Update,
|
||||
[string]$ConfigFile,
|
||||
<<<<<<< HEAD
|
||||
[string]$ToolsSourceSuffix,
|
||||
=======
|
||||
>>>>>>> ANCM/dev
|
||||
[Parameter(ValueFromRemainingArguments = $true)]
|
||||
[string[]]$Arguments
|
||||
)
|
||||
|
|
@ -83,7 +93,11 @@ 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
|
||||
|
|
@ -100,7 +114,11 @@ 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
|
||||
|
|
@ -128,7 +146,11 @@ 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
|
||||
|
|
@ -138,7 +160,11 @@ function Get-RemoteFile([string]$RemotePath, [string]$LocalPath, [string]$Remote
|
|||
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 {
|
||||
|
|
@ -165,8 +191,12 @@ 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]
|
||||
}
|
||||
|
|
@ -193,4 +223,8 @@ try {
|
|||
}
|
||||
finally {
|
||||
Remove-Module 'KoreBuild' -ErrorAction Ignore
|
||||
<<<<<<< HEAD
|
||||
}
|
||||
=======
|
||||
}
|
||||
>>>>>>> ANCM/dev
|
||||
|
|
|
|||
|
|
@ -0,0 +1,260 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="..\..\Build\Build.Settings" />
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{439824F9-1455-4CC4-BD79-B44FA0A16552}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>AspNetCoreModule</RootNamespace>
|
||||
<ProjectName>AspNetCore</ProjectName>
|
||||
<TargetName>aspnetcore</TargetName>
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<WindowsTargetPlatformVersion>10.0.15063.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<UseOfMfc>false</UseOfMfc>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)'=='Release'">
|
||||
<OutDir>$(SolutionDir)artifacts\build\$(ProjectName)\bin\$(Configuration)\$(Platform)</OutDir>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;ASPNETCOREMODULE_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PrecompiledHeaderFile>precomp.hxx</PrecompiledHeaderFile>
|
||||
<PrecompiledHeaderOutputFile>$(IntDir)$(TargetName).pch</PrecompiledHeaderOutputFile>
|
||||
<AdditionalIncludeDirectories>..\IISLib;.\Inc</AdditionalIncludeDirectories>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>kernel32.lib;user32.lib;advapi32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;ahadmin.lib;rpcrt4.lib;winhttp.lib;pdh.lib;ws2_32.lib;wbemuuid.lib;iphlpapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<ModuleDefinitionFile>Source.def</ModuleDefinitionFile>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;ASPNETCOREMODULE_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PrecompiledHeaderFile>precomp.hxx</PrecompiledHeaderFile>
|
||||
<PrecompiledHeaderOutputFile>$(IntDir)$(TargetName).pch</PrecompiledHeaderOutputFile>
|
||||
<AdditionalIncludeDirectories>..\IISLib;.\Inc</AdditionalIncludeDirectories>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>kernel32.lib;user32.lib;advapi32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;ahadmin.lib;rpcrt4.lib;winhttp.lib;pdh.lib;ws2_32.lib;wbemuuid.lib;iphlpapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<ModuleDefinitionFile>Source.def</ModuleDefinitionFile>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;ASPNETCOREMODULE_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>..\IISLib;inc</AdditionalIncludeDirectories>
|
||||
<PrecompiledHeaderFile>precomp.hxx</PrecompiledHeaderFile>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>false</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<ModuleDefinitionFile>Source.def</ModuleDefinitionFile>
|
||||
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;ahadmin.lib;winhttp.lib;odbc32.lib;ws2_32.lib;odbccp32.lib;wbemuuid.lib;iphlpapi.lib;pdh.lib;rpcrt4.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;ASPNETCOREMODULE_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PrecompiledHeaderFile>precomp.hxx</PrecompiledHeaderFile>
|
||||
<AdditionalIncludeDirectories>..\IISLib;inc</AdditionalIncludeDirectories>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>false</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<ModuleDefinitionFile>Source.def</ModuleDefinitionFile>
|
||||
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;ahadmin.lib;rpcrt4.lib;winhttp.lib;pdh.lib;ws2_32.lib;wbemuuid.lib;iphlpapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="Inc\aspnetcore_event.h" />
|
||||
<ClInclude Include="Inc\resource.h" />
|
||||
<ClInclude Include="Inc\application.h" />
|
||||
<ClInclude Include="Inc\applicationmanager.h" />
|
||||
<ClInclude Include="Inc\aspnetcoreconfig.h" />
|
||||
<ClInclude Include="Inc\environmentvariablehash.h" />
|
||||
<ClInclude Include="Inc\debugutil.h" />
|
||||
<ClInclude Include="Inc\filewatcher.h" />
|
||||
<ClInclude Include="Inc\forwarderconnection.h" />
|
||||
<ClInclude Include="Inc\forwardinghandler.h" />
|
||||
<ClInclude Include="Inc\path.h" />
|
||||
<ClInclude Include="Inc\processmanager.h" />
|
||||
<ClInclude Include="Inc\protocolconfig.h" />
|
||||
<ClInclude Include="Inc\proxymodule.h" />
|
||||
<ClInclude Include="Inc\responseheaderhash.h" />
|
||||
<ClInclude Include="Inc\serverprocess.h" />
|
||||
<ClInclude Include="Inc\sttimer.h" />
|
||||
<ClInclude Include="Inc\websockethandler.h" />
|
||||
<ClInclude Include="Inc\winhttphelper.h" />
|
||||
<ClInclude Include="Inc\fx_ver.h" />
|
||||
<ClInclude Include="Inc\inprocessapplication.h" />
|
||||
<ClInclude Include="Inc\outprocessapplication.h" />
|
||||
<ClInclude Include="Inc\inprocessstoredcontext.h" />
|
||||
<ClInclude Include="Src\precomp.hxx" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="Src\inprocessstoredcontext.cxx" />
|
||||
<ClCompile Include="Src\inprocessapplication.cxx" />
|
||||
<ClCompile Include="Src\managedexports.cxx" />
|
||||
<ClCompile Include="Src\outprocessapplication.cxx" />
|
||||
<ClCompile Include="Src\application.cxx" />
|
||||
<ClCompile Include="Src\applicationmanager.cxx" />
|
||||
<ClCompile Include="Src\aspnetcoreconfig.cxx" />
|
||||
<ClCompile Include="Src\dllmain.cpp" />
|
||||
<ClCompile Include="Src\filewatcher.cxx" />
|
||||
<ClCompile Include="Src\forwarderconnection.cxx" />
|
||||
<ClCompile Include="Src\forwardinghandler.cxx" />
|
||||
<ClCompile Include="Src\fx_ver.cxx" />
|
||||
<ClCompile Include="Src\path.cxx" />
|
||||
<ClCompile Include="Src\processmanager.cxx" />
|
||||
<ClCompile Include="Src\protocolconfig.cxx" />
|
||||
<ClCompile Include="Src\proxymodule.cxx" />
|
||||
<ClCompile Include="Src\responseheaderhash.cxx" />
|
||||
<ClCompile Include="Src\serverprocess.cxx" />
|
||||
<ClCompile Include="Src\websockethandler.cxx" />
|
||||
<ClCompile Include="Src\winhttphelper.cxx" />
|
||||
</ItemGroup>
|
||||
<Target Name="CreateVersionHeader" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<Revision>$(build_number)</Revision>
|
||||
<Revision Condition="'$(Revision)' == ''">0</Revision>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<VersionHeaderContents Include="// Copyright (c) .NET Foundation. All rights reserved." />
|
||||
<VersionHeaderContents Include="// Licensed under the MIT License. See LICENSE.txt in the project root for license information." />
|
||||
<VersionHeaderContents Include="%0a" />
|
||||
<VersionHeaderContents Include="// This file is auto-generated" />
|
||||
<VersionHeaderContents Include="%0a" />
|
||||
<VersionHeaderContents Include="#define FileVersion $(AspNetCoreModuleVersionMajor),$(AspNetCoreModuleVersionMinor),$(AspNetCoreModuleVersionPatch),$(Revision)" />
|
||||
<VersionHeaderContents Include="#define FileVersionStr "$(AspNetCoreModuleVersionMajor).$(AspNetCoreModuleVersionMinor).$(AspNetCoreModuleVersionPatch).$(Revision)\0"" />
|
||||
<VersionHeaderContents Include="#define ProductVersion $(AspNetCoreModuleVersionMajor),$(AspNetCoreModuleVersionMinor),$(AspNetCoreModuleVersionPatch),$(Revision)" />
|
||||
<VersionHeaderContents Include="#define ProductVersionStr "$(AspNetCoreModuleVersionMajor).$(AspNetCoreModuleVersionMinor).$(AspNetCoreModuleVersionPatch).$(Revision)\0"" />
|
||||
<VersionHeaderContents Include="#define PlatformToolset "$(PlatformToolset)\0"" />
|
||||
</ItemGroup>
|
||||
<WriteLinesToFile File="version.h" Lines="@(VersionHeaderContents)" OverWrite="true" />
|
||||
</Target>
|
||||
<ItemGroup>
|
||||
<CustomBuild Include="Src\aspnetcore_msg.mc">
|
||||
<FileType>Document</FileType>
|
||||
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">mc %(FullPath)</Command>
|
||||
<Message Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Compiling Event Messages ...</Message>
|
||||
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(Filename).rc;%(Filename).h;MSG0409.bin</Outputs>
|
||||
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">mc %(FullPath)</Command>
|
||||
<Message Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Compiling Event Messages ...</Message>
|
||||
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">%(Filename).rc;%(Filename).h;MSG0409.bin</Outputs>
|
||||
<Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">mc %(FullPath)</Command>
|
||||
<Message Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Compiling Event Messages ...</Message>
|
||||
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(Filename).rc;%(Filename).h;MSG0409.bin</Outputs>
|
||||
<Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">mc %(FullPath)</Command>
|
||||
<Message Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Compiling Event Messages ...</Message>
|
||||
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">%(Filename).rc;%(Filename).h;MSG0409.bin</Outputs>
|
||||
</CustomBuild>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="aspnetcoremodule.rc" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\IISLib\IISLib.vcxproj">
|
||||
<Project>{4787a64f-9a3e-4867-a55a-70cb4b2b2ffe}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="Source.def" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="aspnetcore_schema.xml">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,286 @@
|
|||
// 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<APPLICATION, APPLICATION_KEY *>
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
APPLICATION_HASH()
|
||||
{}
|
||||
|
||||
APPLICATION_KEY *
|
||||
ExtractKey(
|
||||
APPLICATION *pApplication
|
||||
)
|
||||
{
|
||||
return pApplication->QueryApplicationKey();
|
||||
}
|
||||
|
||||
DWORD
|
||||
CalcKeyHash(
|
||||
APPLICATION_KEY *key
|
||||
)
|
||||
{
|
||||
return key->CalcKeyHash();
|
||||
}
|
||||
|
||||
BOOL
|
||||
EqualKeys(
|
||||
APPLICATION_KEY *key1,
|
||||
APPLICATION_KEY *key2
|
||||
)
|
||||
{
|
||||
return key1->GetIsEqual(key2);
|
||||
}
|
||||
|
||||
VOID
|
||||
ReferenceRecord(
|
||||
APPLICATION *pApplication
|
||||
)
|
||||
{
|
||||
pApplication->ReferenceApplication();
|
||||
}
|
||||
|
||||
VOID
|
||||
DereferenceRecord(
|
||||
APPLICATION *pApplication
|
||||
)
|
||||
{
|
||||
pApplication->DereferenceApplication();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
APPLICATION_HASH(const APPLICATION_HASH &);
|
||||
void operator=(const APPLICATION_HASH &);
|
||||
};
|
||||
|
|
@ -0,0 +1,162 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
#define DEFAULT_HASH_BUCKETS 293
|
||||
|
||||
class APPLICATION_MANAGER
|
||||
{
|
||||
public:
|
||||
|
||||
static
|
||||
APPLICATION_MANAGER*
|
||||
GetInstance(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
if( sm_pApplicationManager == NULL )
|
||||
{
|
||||
sm_pApplicationManager = new APPLICATION_MANAGER();
|
||||
}
|
||||
|
||||
return sm_pApplicationManager;
|
||||
}
|
||||
|
||||
static
|
||||
VOID
|
||||
Cleanup(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
if(sm_pApplicationManager != NULL)
|
||||
{
|
||||
delete sm_pApplicationManager;
|
||||
sm_pApplicationManager = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT
|
||||
GetApplication(
|
||||
_In_ IHttpContext* pContext,
|
||||
_In_ ASPNETCORE_CONFIG* pConfig,
|
||||
_Out_ APPLICATION ** ppApplication
|
||||
);
|
||||
|
||||
HRESULT
|
||||
RecycleApplication(
|
||||
_In_ LPCWSTR pszApplication
|
||||
);
|
||||
|
||||
HRESULT
|
||||
Get502ErrorPage(
|
||||
_Out_ HTTP_DATA_CHUNK** ppErrorPage
|
||||
);
|
||||
|
||||
~APPLICATION_MANAGER()
|
||||
{
|
||||
if(m_pApplicationHash != NULL)
|
||||
{
|
||||
m_pApplicationHash->Clear();
|
||||
delete m_pApplicationHash;
|
||||
m_pApplicationHash = NULL;
|
||||
}
|
||||
|
||||
if( m_pFileWatcher!= NULL )
|
||||
{
|
||||
delete m_pFileWatcher;
|
||||
m_pFileWatcher = NULL;
|
||||
}
|
||||
|
||||
if(m_pHttp502ErrorPage != NULL)
|
||||
{
|
||||
delete m_pHttp502ErrorPage;
|
||||
m_pHttp502ErrorPage = NULL;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
FILE_WATCHER*
|
||||
GetFileWatcher()
|
||||
{
|
||||
return m_pFileWatcher;
|
||||
}
|
||||
|
||||
HRESULT Initialize()
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
if(m_pApplicationHash == NULL)
|
||||
{
|
||||
m_pApplicationHash = new APPLICATION_HASH();
|
||||
if(m_pApplicationHash == NULL)
|
||||
{
|
||||
hr = E_OUTOFMEMORY;
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
hr = m_pApplicationHash->Initialize(DEFAULT_HASH_BUCKETS);
|
||||
if(FAILED(hr))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
}
|
||||
|
||||
if( m_pFileWatcher == NULL )
|
||||
{
|
||||
m_pFileWatcher = new FILE_WATCHER;
|
||||
if(m_pFileWatcher == NULL)
|
||||
{
|
||||
hr = HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
m_pFileWatcher->Create();
|
||||
}
|
||||
|
||||
Finished:
|
||||
return hr;
|
||||
}
|
||||
|
||||
private:
|
||||
//
|
||||
// we currently limit the size of m_pstrErrorInfo to 5000, be careful if you want to change its payload
|
||||
//
|
||||
APPLICATION_MANAGER() : m_pApplicationHash(NULL), m_pFileWatcher(NULL),
|
||||
m_pHttp502ErrorPage(NULL), m_hostingModel(HOSTING_UNKNOWN),
|
||||
m_pstrErrorInfo(
|
||||
"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\"> \
|
||||
<html xmlns=\"http://www.w3.org/1999/xhtml\"> \
|
||||
<head> \
|
||||
<meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\" /> \
|
||||
<title> IIS 502.5 Error </title><style type=\"text/css\"></style></head> \
|
||||
<body> <div id = \"content\"> \
|
||||
<div class = \"content-container\"><h3> HTTP Error 502.5 - Process Failure </h3></div> \
|
||||
<div class = \"content-container\"> \
|
||||
<fieldset> <h4> Common causes of this issue: </h4> \
|
||||
<ul><li> The application process failed to start </li> \
|
||||
<li> The application process started but then stopped </li> \
|
||||
<li> The application process started but failed to listen on the configured port </li></ul></fieldset> \
|
||||
</div> \
|
||||
<div class = \"content-container\"> \
|
||||
<fieldset><h4> Troubleshooting steps: </h4> \
|
||||
<ul><li> Check the system event log for error messages </li> \
|
||||
<li> Enable logging the application process' stdout messages </li> \
|
||||
<li> Attach a debugger to the application process and inspect </li></ul></fieldset> \
|
||||
<fieldset><h4> For more information visit: \
|
||||
<a href=\"https://go.microsoft.com/fwlink/?linkid=808681\"> <cite> https://go.microsoft.com/fwlink/?LinkID=808681 </cite></a></h4> \
|
||||
</fieldset> \
|
||||
</div> \
|
||||
</div></body></html>")
|
||||
{
|
||||
InitializeSRWLock(&m_srwLock);
|
||||
}
|
||||
|
||||
FILE_WATCHER *m_pFileWatcher;
|
||||
APPLICATION_HASH *m_pApplicationHash;
|
||||
static APPLICATION_MANAGER *sm_pApplicationManager;
|
||||
SRWLOCK m_srwLock;
|
||||
HTTP_DATA_CHUNK *m_pHttp502ErrorPage;
|
||||
LPSTR m_pstrErrorInfo;
|
||||
APP_HOSTING_MODEL m_hostingModel;
|
||||
};
|
||||
|
|
@ -0,0 +1,550 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
#ifndef __ASPNETCOREEVENT_H__
|
||||
#define __ASPNETCOREEVENT_H__
|
||||
/*++
|
||||
|
||||
Module Name:
|
||||
|
||||
aspnetcore_event.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Header file has been generated from mof file containing
|
||||
IIS trace event descriptions
|
||||
|
||||
--*/
|
||||
|
||||
//
|
||||
// Start of the new provider class WWWServerTraceProvider,
|
||||
// GUID: {3a2a4e84-4c21-4981-ae10-3fda0d9b0f83}
|
||||
// Description: IIS: WWW Server
|
||||
//
|
||||
|
||||
class WWWServerTraceProvider
|
||||
{
|
||||
public:
|
||||
static
|
||||
LPCGUID
|
||||
GetProviderGuid( VOID )
|
||||
// return GUID for the current event class
|
||||
{
|
||||
static const GUID ProviderGuid =
|
||||
{0x3a2a4e84,0x4c21,0x4981,{0xae,0x10,0x3f,0xda,0x0d,0x9b,0x0f,0x83}};
|
||||
return &ProviderGuid;
|
||||
};
|
||||
enum enumAreaFlags
|
||||
{
|
||||
// AspNetCore module events
|
||||
ANCM = 0x10000
|
||||
};
|
||||
static
|
||||
LPCWSTR
|
||||
TranslateEnumAreaFlagsToString( enum enumAreaFlags EnumValue)
|
||||
{
|
||||
switch( (DWORD) EnumValue )
|
||||
{
|
||||
case 0x10000: return L"ANCM";
|
||||
}
|
||||
return NULL;
|
||||
};
|
||||
|
||||
static
|
||||
BOOL
|
||||
CheckTracingEnabled(
|
||||
IHttpTraceContext * pHttpTraceContext,
|
||||
enumAreaFlags AreaFlags,
|
||||
DWORD dwVerbosity )
|
||||
{
|
||||
HRESULT hr;
|
||||
HTTP_TRACE_CONFIGURATION TraceConfig;
|
||||
TraceConfig.pProviderGuid = GetProviderGuid();
|
||||
hr = pHttpTraceContext->GetTraceConfiguration( &TraceConfig );
|
||||
if ( FAILED( hr ) || !TraceConfig.fProviderEnabled )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
if ( TraceConfig.dwVerbosity >= dwVerbosity &&
|
||||
( TraceConfig.dwAreas == (DWORD) AreaFlags ||
|
||||
( TraceConfig.dwAreas & (DWORD)AreaFlags ) == (DWORD)AreaFlags ) )
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
};
|
||||
};
|
||||
|
||||
//
|
||||
// Start of the new event class ANCMEvents,
|
||||
// GUID: {82ADEAD7-12B2-4781-BDCA-5A4B6C757191}
|
||||
// Description: ANCM runtime events
|
||||
//
|
||||
|
||||
class ANCMEvents
|
||||
{
|
||||
public:
|
||||
static
|
||||
LPCGUID
|
||||
GetAreaGuid( VOID )
|
||||
// return GUID for the current event class
|
||||
{
|
||||
static const GUID AreaGuid =
|
||||
{0x82adead7,0x12b2,0x4781,{0xbd,0xca,0x5a,0x4b,0x6c,0x75,0x71,0x91}};
|
||||
return &AreaGuid;
|
||||
};
|
||||
|
||||
//
|
||||
// Event: mof class name ANCMAppStart,
|
||||
// Description: Start application success
|
||||
// EventTypeName: ANCM_START_APPLICATION_SUCCESS
|
||||
// EventType: 1
|
||||
// EventLevel: 4
|
||||
//
|
||||
|
||||
class ANCM_START_APPLICATION_SUCCESS
|
||||
{
|
||||
public:
|
||||
static
|
||||
HRESULT
|
||||
RaiseEvent(
|
||||
IHttpTraceContext * pHttpTraceContext,
|
||||
LPCGUID pContextId,
|
||||
LPCWSTR pAppDescription
|
||||
)
|
||||
//
|
||||
// Raise ANCM_START_APPLICATION_SUCCESS Event
|
||||
//
|
||||
{
|
||||
HTTP_TRACE_EVENT Event;
|
||||
Event.pProviderGuid = WWWServerTraceProvider::GetProviderGuid();
|
||||
Event.dwArea = WWWServerTraceProvider::ANCM;
|
||||
Event.pAreaGuid = ANCMEvents::GetAreaGuid();
|
||||
Event.dwEvent = 1;
|
||||
Event.pszEventName = L"ANCM_START_APPLICATION_SUCCESS";
|
||||
Event.dwEventVersion = 1;
|
||||
Event.dwVerbosity = 4;
|
||||
Event.cEventItems = 2;
|
||||
Event.pActivityGuid = NULL;
|
||||
Event.pRelatedActivityGuid = NULL;
|
||||
Event.dwTimeStamp = 0;
|
||||
Event.dwFlags = HTTP_TRACE_EVENT_FLAG_STATIC_DESCRIPTIVE_FIELDS;
|
||||
|
||||
// pActivityGuid, pRelatedActivityGuid, Timestamp to be filled in by IIS
|
||||
|
||||
HTTP_TRACE_EVENT_ITEM Items[ 2 ];
|
||||
Items[ 0 ].pszName = L"ContextId";
|
||||
Items[ 0 ].dwDataType = HTTP_TRACE_TYPE_LPCGUID; // mof type (object)
|
||||
Items[ 0 ].pbData = (PBYTE) pContextId;
|
||||
Items[ 0 ].cbData = 16;
|
||||
Items[ 0 ].pszDataDescription = NULL;
|
||||
Items[ 1 ].pszName = L"AppDescription";
|
||||
Items[ 1 ].dwDataType = HTTP_TRACE_TYPE_LPCWSTR; // mof type (string)
|
||||
Items[ 1 ].pbData = (PBYTE) pAppDescription;
|
||||
Items[ 1 ].cbData =
|
||||
( Items[ 1 ].pbData == NULL )? 0 : ( sizeof(WCHAR) * (1 + (DWORD) wcslen( (PWSTR) Items[ 1 ].pbData ) ) );
|
||||
Items[ 1 ].pszDataDescription = NULL;
|
||||
Event.pEventItems = Items;
|
||||
pHttpTraceContext->RaiseTraceEvent( &Event );
|
||||
return S_OK;
|
||||
};
|
||||
|
||||
static
|
||||
BOOL
|
||||
IsEnabled(
|
||||
IHttpTraceContext * pHttpTraceContext )
|
||||
// Check if tracing for this event is enabled
|
||||
{
|
||||
return WWWServerTraceProvider::CheckTracingEnabled(
|
||||
pHttpTraceContext,
|
||||
WWWServerTraceProvider::ANCM,
|
||||
4 ); //Verbosity
|
||||
};
|
||||
};
|
||||
//
|
||||
// Event: mof class name ANCMAppStartFail,
|
||||
// Description: Start application failed
|
||||
// EventTypeName: ANCM_START_APPLICATION_FAIL
|
||||
// EventType: 2
|
||||
// EventLevel: 2
|
||||
//
|
||||
|
||||
class ANCM_START_APPLICATION_FAIL
|
||||
{
|
||||
public:
|
||||
static
|
||||
HRESULT
|
||||
RaiseEvent(
|
||||
IHttpTraceContext * pHttpTraceContext,
|
||||
LPCGUID pContextId,
|
||||
LPCWSTR pFailureDescription
|
||||
)
|
||||
//
|
||||
// Raise ANCM_START_APPLICATION_FAIL Event
|
||||
//
|
||||
{
|
||||
HTTP_TRACE_EVENT Event;
|
||||
Event.pProviderGuid = WWWServerTraceProvider::GetProviderGuid();
|
||||
Event.dwArea = WWWServerTraceProvider::ANCM;
|
||||
Event.pAreaGuid = ANCMEvents::GetAreaGuid();
|
||||
Event.dwEvent = 2;
|
||||
Event.pszEventName = L"ANCM_START_APPLICATION_FAIL";
|
||||
Event.dwEventVersion = 1;
|
||||
Event.dwVerbosity = 2;
|
||||
Event.cEventItems = 2;
|
||||
Event.pActivityGuid = NULL;
|
||||
Event.pRelatedActivityGuid = NULL;
|
||||
Event.dwTimeStamp = 0;
|
||||
Event.dwFlags = HTTP_TRACE_EVENT_FLAG_STATIC_DESCRIPTIVE_FIELDS;
|
||||
|
||||
// pActivityGuid, pRelatedActivityGuid, Timestamp to be filled in by IIS
|
||||
|
||||
HTTP_TRACE_EVENT_ITEM Items[ 2 ];
|
||||
Items[ 0 ].pszName = L"ContextId";
|
||||
Items[ 0 ].dwDataType = HTTP_TRACE_TYPE_LPCGUID; // mof type (object)
|
||||
Items[ 0 ].pbData = (PBYTE) pContextId;
|
||||
Items[ 0 ].cbData = 16;
|
||||
Items[ 0 ].pszDataDescription = NULL;
|
||||
Items[ 1 ].pszName = L"FailureDescription";
|
||||
Items[ 1 ].dwDataType = HTTP_TRACE_TYPE_LPCWSTR; // mof type (string)
|
||||
Items[ 1 ].pbData = (PBYTE) pFailureDescription;
|
||||
Items[ 1 ].cbData =
|
||||
( Items[ 1 ].pbData == NULL )? 0 : ( sizeof(WCHAR) * (1 + (DWORD) wcslen( (PWSTR) Items[ 1 ].pbData ) ) );
|
||||
Items[ 1 ].pszDataDescription = NULL;
|
||||
Event.pEventItems = Items;
|
||||
pHttpTraceContext->RaiseTraceEvent( &Event );
|
||||
return S_OK;
|
||||
};
|
||||
|
||||
static
|
||||
BOOL
|
||||
IsEnabled(
|
||||
IHttpTraceContext * pHttpTraceContext )
|
||||
// Check if tracing for this event is enabled
|
||||
{
|
||||
return WWWServerTraceProvider::CheckTracingEnabled(
|
||||
pHttpTraceContext,
|
||||
WWWServerTraceProvider::ANCM,
|
||||
2 ); //Verbosity
|
||||
};
|
||||
};
|
||||
//
|
||||
// Event: mof class name ANCMForwardStart,
|
||||
// Description: Start fardwarding request
|
||||
// EventTypeName: ANCM_REQUEST_FORWARD_START
|
||||
// EventType: 3
|
||||
// EventLevel: 4
|
||||
//
|
||||
|
||||
class ANCM_REQUEST_FORWARD_START
|
||||
{
|
||||
public:
|
||||
static
|
||||
HRESULT
|
||||
RaiseEvent(
|
||||
IHttpTraceContext * pHttpTraceContext,
|
||||
LPCGUID pContextId
|
||||
)
|
||||
//
|
||||
// Raise ANCM_REQUEST_FORWARD_START Event
|
||||
//
|
||||
{
|
||||
HTTP_TRACE_EVENT Event;
|
||||
Event.pProviderGuid = WWWServerTraceProvider::GetProviderGuid();
|
||||
Event.dwArea = WWWServerTraceProvider::ANCM;
|
||||
Event.pAreaGuid = ANCMEvents::GetAreaGuid();
|
||||
Event.dwEvent = 3;
|
||||
Event.pszEventName = L"ANCM_REQUEST_FORWARD_START";
|
||||
Event.dwEventVersion = 1;
|
||||
Event.dwVerbosity = 4;
|
||||
Event.cEventItems = 1;
|
||||
Event.pActivityGuid = NULL;
|
||||
Event.pRelatedActivityGuid = NULL;
|
||||
Event.dwTimeStamp = 0;
|
||||
Event.dwFlags = HTTP_TRACE_EVENT_FLAG_STATIC_DESCRIPTIVE_FIELDS;
|
||||
|
||||
// pActivityGuid, pRelatedActivityGuid, Timestamp to be filled in by IIS
|
||||
|
||||
HTTP_TRACE_EVENT_ITEM Items[ 1 ];
|
||||
Items[ 0 ].pszName = L"ContextId";
|
||||
Items[ 0 ].dwDataType = HTTP_TRACE_TYPE_LPCGUID; // mof type (object)
|
||||
Items[ 0 ].pbData = (PBYTE) pContextId;
|
||||
Items[ 0 ].cbData = 16;
|
||||
Items[ 0 ].pszDataDescription = NULL;
|
||||
Event.pEventItems = Items;
|
||||
pHttpTraceContext->RaiseTraceEvent( &Event );
|
||||
return S_OK;
|
||||
};
|
||||
|
||||
static
|
||||
BOOL
|
||||
IsEnabled(
|
||||
IHttpTraceContext * pHttpTraceContext )
|
||||
// Check if tracing for this event is enabled
|
||||
{
|
||||
return WWWServerTraceProvider::CheckTracingEnabled(
|
||||
pHttpTraceContext,
|
||||
WWWServerTraceProvider::ANCM,
|
||||
4 ); //Verbosity
|
||||
};
|
||||
};
|
||||
//
|
||||
// Event: mof class name ANCMForwardEnd,
|
||||
// Description: Finish forwarding request
|
||||
// EventTypeName: ANCM_REQUEST_FORWARD_END
|
||||
// EventType: 4
|
||||
// EventLevel: 4
|
||||
//
|
||||
|
||||
class ANCM_REQUEST_FORWARD_END
|
||||
{
|
||||
public:
|
||||
static
|
||||
HRESULT
|
||||
RaiseEvent(
|
||||
IHttpTraceContext * pHttpTraceContext,
|
||||
LPCGUID pContextId
|
||||
)
|
||||
//
|
||||
// Raise ANCM_REQUEST_FORWARD_END Event
|
||||
//
|
||||
{
|
||||
HTTP_TRACE_EVENT Event;
|
||||
Event.pProviderGuid = WWWServerTraceProvider::GetProviderGuid();
|
||||
Event.dwArea = WWWServerTraceProvider::ANCM;
|
||||
Event.pAreaGuid = ANCMEvents::GetAreaGuid();
|
||||
Event.dwEvent = 4;
|
||||
Event.pszEventName = L"ANCM_REQUEST_FORWARD_END";
|
||||
Event.dwEventVersion = 1;
|
||||
Event.dwVerbosity = 4;
|
||||
Event.cEventItems = 1;
|
||||
Event.pActivityGuid = NULL;
|
||||
Event.pRelatedActivityGuid = NULL;
|
||||
Event.dwTimeStamp = 0;
|
||||
Event.dwFlags = HTTP_TRACE_EVENT_FLAG_STATIC_DESCRIPTIVE_FIELDS;
|
||||
|
||||
// pActivityGuid, pRelatedActivityGuid, Timestamp to be filled in by IIS
|
||||
|
||||
HTTP_TRACE_EVENT_ITEM Items[ 1 ];
|
||||
Items[ 0 ].pszName = L"ContextId";
|
||||
Items[ 0 ].dwDataType = HTTP_TRACE_TYPE_LPCGUID; // mof type (object)
|
||||
Items[ 0 ].pbData = (PBYTE) pContextId;
|
||||
Items[ 0 ].cbData = 16;
|
||||
Items[ 0 ].pszDataDescription = NULL;
|
||||
Event.pEventItems = Items;
|
||||
pHttpTraceContext->RaiseTraceEvent( &Event );
|
||||
return S_OK;
|
||||
};
|
||||
|
||||
static
|
||||
BOOL
|
||||
IsEnabled(
|
||||
IHttpTraceContext * pHttpTraceContext )
|
||||
// Check if tracing for this event is enabled
|
||||
{
|
||||
return WWWServerTraceProvider::CheckTracingEnabled(
|
||||
pHttpTraceContext,
|
||||
WWWServerTraceProvider::ANCM,
|
||||
4 ); //Verbosity
|
||||
};
|
||||
};
|
||||
//
|
||||
// Event: mof class name ANCMForwardFail,
|
||||
// Description: Forwarding request failure
|
||||
// EventTypeName: ANCM_REQUEST_FORWARD_FAIL
|
||||
// EventType: 5
|
||||
// EventLevel: 2
|
||||
//
|
||||
|
||||
class ANCM_REQUEST_FORWARD_FAIL
|
||||
{
|
||||
public:
|
||||
static
|
||||
HRESULT
|
||||
RaiseEvent(
|
||||
IHttpTraceContext * pHttpTraceContext,
|
||||
LPCGUID pContextId,
|
||||
ULONG ErrorCode
|
||||
)
|
||||
//
|
||||
// Raise ANCM_REQUEST_FORWARD_FAIL Event
|
||||
//
|
||||
{
|
||||
HTTP_TRACE_EVENT Event;
|
||||
Event.pProviderGuid = WWWServerTraceProvider::GetProviderGuid();
|
||||
Event.dwArea = WWWServerTraceProvider::ANCM;
|
||||
Event.pAreaGuid = ANCMEvents::GetAreaGuid();
|
||||
Event.dwEvent = 5;
|
||||
Event.pszEventName = L"ANCM_REQUEST_FORWARD_FAIL";
|
||||
Event.dwEventVersion = 1;
|
||||
Event.dwVerbosity = 2;
|
||||
Event.cEventItems = 2;
|
||||
Event.pActivityGuid = NULL;
|
||||
Event.pRelatedActivityGuid = NULL;
|
||||
Event.dwTimeStamp = 0;
|
||||
Event.dwFlags = HTTP_TRACE_EVENT_FLAG_STATIC_DESCRIPTIVE_FIELDS;
|
||||
|
||||
// pActivityGuid, pRelatedActivityGuid, Timestamp to be filled in by IIS
|
||||
|
||||
HTTP_TRACE_EVENT_ITEM Items[ 2 ];
|
||||
Items[ 0 ].pszName = L"ContextId";
|
||||
Items[ 0 ].dwDataType = HTTP_TRACE_TYPE_LPCGUID; // mof type (object)
|
||||
Items[ 0 ].pbData = (PBYTE) pContextId;
|
||||
Items[ 0 ].cbData = 16;
|
||||
Items[ 0 ].pszDataDescription = NULL;
|
||||
Items[ 1 ].pszName = L"ErrorCode";
|
||||
Items[ 1 ].dwDataType = HTTP_TRACE_TYPE_ULONG; // mof type (uint32)
|
||||
Items[ 1 ].pbData = (PBYTE) &ErrorCode;
|
||||
Items[ 1 ].cbData = 4;
|
||||
Items[ 1 ].pszDataDescription = NULL;
|
||||
Event.pEventItems = Items;
|
||||
pHttpTraceContext->RaiseTraceEvent( &Event );
|
||||
return S_OK;
|
||||
};
|
||||
|
||||
static
|
||||
BOOL
|
||||
IsEnabled(
|
||||
IHttpTraceContext * pHttpTraceContext )
|
||||
// Check if tracing for this event is enabled
|
||||
{
|
||||
return WWWServerTraceProvider::CheckTracingEnabled(
|
||||
pHttpTraceContext,
|
||||
WWWServerTraceProvider::ANCM,
|
||||
2 ); //Verbosity
|
||||
};
|
||||
};
|
||||
//
|
||||
// Event: mof class name ANCMWinHttpCallBack,
|
||||
// Description: Receiving callback from WinHttp
|
||||
// EventTypeName: ANCM_WINHTTP_CALLBACK
|
||||
// EventType: 6
|
||||
// EventLevel: 4
|
||||
//
|
||||
|
||||
class ANCM_WINHTTP_CALLBACK
|
||||
{
|
||||
public:
|
||||
static
|
||||
HRESULT
|
||||
RaiseEvent(
|
||||
IHttpTraceContext * pHttpTraceContext,
|
||||
LPCGUID pContextId,
|
||||
ULONG InternetStatus
|
||||
)
|
||||
//
|
||||
// Raise ANCM_WINHTTP_CALLBACK Event
|
||||
//
|
||||
{
|
||||
HTTP_TRACE_EVENT Event;
|
||||
Event.pProviderGuid = WWWServerTraceProvider::GetProviderGuid();
|
||||
Event.dwArea = WWWServerTraceProvider::ANCM;
|
||||
Event.pAreaGuid = ANCMEvents::GetAreaGuid();
|
||||
Event.dwEvent = 6;
|
||||
Event.pszEventName = L"ANCM_WINHTTP_CALLBACK";
|
||||
Event.dwEventVersion = 1;
|
||||
Event.dwVerbosity = 4;
|
||||
Event.cEventItems = 2;
|
||||
Event.pActivityGuid = NULL;
|
||||
Event.pRelatedActivityGuid = NULL;
|
||||
Event.dwTimeStamp = 0;
|
||||
Event.dwFlags = HTTP_TRACE_EVENT_FLAG_STATIC_DESCRIPTIVE_FIELDS;
|
||||
|
||||
// pActivityGuid, pRelatedActivityGuid, Timestamp to be filled in by IIS
|
||||
|
||||
HTTP_TRACE_EVENT_ITEM Items[ 2 ];
|
||||
Items[ 0 ].pszName = L"ContextId";
|
||||
Items[ 0 ].dwDataType = HTTP_TRACE_TYPE_LPCGUID; // mof type (object)
|
||||
Items[ 0 ].pbData = (PBYTE) pContextId;
|
||||
Items[ 0 ].cbData = 16;
|
||||
Items[ 0 ].pszDataDescription = NULL;
|
||||
Items[ 1 ].pszName = L"InternetStatus";
|
||||
Items[ 1 ].dwDataType = HTTP_TRACE_TYPE_ULONG; // mof type (uint32)
|
||||
Items[ 1 ].pbData = (PBYTE) &InternetStatus;
|
||||
Items[ 1 ].cbData = 4;
|
||||
Items[ 1 ].pszDataDescription = NULL;
|
||||
Event.pEventItems = Items;
|
||||
pHttpTraceContext->RaiseTraceEvent( &Event );
|
||||
return S_OK;
|
||||
};
|
||||
|
||||
static
|
||||
BOOL
|
||||
IsEnabled(
|
||||
IHttpTraceContext * pHttpTraceContext )
|
||||
// Check if tracing for this event is enabled
|
||||
{
|
||||
return WWWServerTraceProvider::CheckTracingEnabled(
|
||||
pHttpTraceContext,
|
||||
WWWServerTraceProvider::ANCM,
|
||||
4 ); //Verbosity
|
||||
};
|
||||
};
|
||||
//
|
||||
// Event: mof class name ANCMForwardEnd,
|
||||
// Description: Inprocess executing request failure
|
||||
// EventTypeName: ANCM_EXECUTE_REQUEST_FAIL
|
||||
// EventType: 7
|
||||
// EventLevel: 2
|
||||
//
|
||||
|
||||
class ANCM_EXECUTE_REQUEST_FAIL
|
||||
{
|
||||
public:
|
||||
static
|
||||
HRESULT
|
||||
RaiseEvent(
|
||||
IHttpTraceContext * pHttpTraceContext,
|
||||
LPCGUID pContextId,
|
||||
ULONG ErrorCode
|
||||
)
|
||||
//
|
||||
// Raise ANCM_EXECUTE_REQUEST_FAIL Event
|
||||
//
|
||||
{
|
||||
HTTP_TRACE_EVENT Event;
|
||||
Event.pProviderGuid = WWWServerTraceProvider::GetProviderGuid();
|
||||
Event.dwArea = WWWServerTraceProvider::ANCM;
|
||||
Event.pAreaGuid = ANCMEvents::GetAreaGuid();
|
||||
Event.dwEvent = 7;
|
||||
Event.pszEventName = L"ANCM_EXECUTE_REQUEST_FAIL";
|
||||
Event.dwEventVersion = 1;
|
||||
Event.dwVerbosity = 2;
|
||||
Event.cEventItems = 2;
|
||||
Event.pActivityGuid = NULL;
|
||||
Event.pRelatedActivityGuid = NULL;
|
||||
Event.dwTimeStamp = 0;
|
||||
Event.dwFlags = HTTP_TRACE_EVENT_FLAG_STATIC_DESCRIPTIVE_FIELDS;
|
||||
|
||||
// pActivityGuid, pRelatedActivityGuid, Timestamp to be filled in by IIS
|
||||
|
||||
HTTP_TRACE_EVENT_ITEM Items[ 2 ];
|
||||
Items[ 0 ].pszName = L"ContextId";
|
||||
Items[ 0 ].dwDataType = HTTP_TRACE_TYPE_LPCGUID; // mof type (object)
|
||||
Items[ 0 ].pbData = (PBYTE) pContextId;
|
||||
Items[ 0 ].cbData = 16;
|
||||
Items[ 0 ].pszDataDescription = NULL;
|
||||
Items[ 1 ].pszName = L"ErrorCode";
|
||||
Items[ 1 ].dwDataType = HTTP_TRACE_TYPE_ULONG; // mof type (uint32)
|
||||
Items[ 1 ].pbData = (PBYTE) &ErrorCode;
|
||||
Items[ 1 ].cbData = 4;
|
||||
Items[ 1 ].pszDataDescription = NULL;
|
||||
Event.pEventItems = Items;
|
||||
pHttpTraceContext->RaiseTraceEvent( &Event );
|
||||
return S_OK;
|
||||
};
|
||||
|
||||
static
|
||||
BOOL
|
||||
IsEnabled(
|
||||
IHttpTraceContext * pHttpTraceContext )
|
||||
// Check if tracing for this event is enabled
|
||||
{
|
||||
return WWWServerTraceProvider::CheckTracingEnabled(
|
||||
pHttpTraceContext,
|
||||
WWWServerTraceProvider::ANCM,
|
||||
2 ); //Verbosity
|
||||
};
|
||||
};
|
||||
};
|
||||
#endif
|
||||
|
|
@ -0,0 +1,253 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
#pragma once
|
||||
#define CS_ROOTWEB_CONFIG L"MACHINE/WEBROOT/APPHOST/"
|
||||
#define CS_ROOTWEB_CONFIG_LEN _countof(CS_ROOTWEB_CONFIG)-1
|
||||
#define CS_ASPNETCORE_SECTION L"system.webServer/aspNetCore"
|
||||
#define CS_WINDOWS_AUTHENTICATION_SECTION L"system.webServer/security/authentication/windowsAuthentication"
|
||||
#define CS_BASIC_AUTHENTICATION_SECTION L"system.webServer/security/authentication/basicAuthentication"
|
||||
#define CS_ANONYMOUS_AUTHENTICATION_SECTION L"system.webServer/security/authentication/anonymousAuthentication"
|
||||
#define CS_AUTHENTICATION_ENABLED L"enabled"
|
||||
#define CS_ASPNETCORE_PROCESS_EXE_PATH L"processPath"
|
||||
#define CS_ASPNETCORE_PROCESS_ARGUMENTS L"arguments"
|
||||
#define CS_ASPNETCORE_PROCESS_STARTUP_TIME_LIMIT L"startupTimeLimit"
|
||||
#define CS_ASPNETCORE_PROCESS_SHUTDOWN_TIME_LIMIT L"shutdownTimeLimit"
|
||||
#define CS_ASPNETCORE_WINHTTP_REQUEST_TIMEOUT L"requestTimeout"
|
||||
#define CS_ASPNETCORE_RAPID_FAILS_PER_MINUTE L"rapidFailsPerMinute"
|
||||
#define CS_ASPNETCORE_STDOUT_LOG_ENABLED L"stdoutLogEnabled"
|
||||
#define CS_ASPNETCORE_STDOUT_LOG_FILE L"stdoutLogFile"
|
||||
#define CS_ASPNETCORE_ENVIRONMENT_VARIABLES L"environmentVariables"
|
||||
#define CS_ASPNETCORE_ENVIRONMENT_VARIABLE L"environmentVariable"
|
||||
#define CS_ASPNETCORE_ENVIRONMENT_VARIABLE_NAME L"name"
|
||||
#define CS_ASPNETCORE_ENVIRONMENT_VARIABLE_VALUE L"value"
|
||||
#define CS_ASPNETCORE_PROCESSES_PER_APPLICATION L"processesPerApplication"
|
||||
#define CS_ASPNETCORE_FORWARD_WINDOWS_AUTH_TOKEN L"forwardWindowsAuthToken"
|
||||
#define CS_ASPNETCORE_DISABLE_START_UP_ERROR_PAGE L"disableStartUpErrorPage"
|
||||
#define CS_ASPNETCORE_RECYCLE_ON_FILE_CHANGE L"recycleOnFileChange"
|
||||
#define CS_ASPNETCORE_RECYCLE_ON_FILE_CHANGE_FILE L"file"
|
||||
#define CS_ASPNETCORE_RECYCLE_ON_FILE_CHANGE_FILE_PATH L"path"
|
||||
#define CS_ASPNETCORE_HOSTING_MODEL L"hostingModel"
|
||||
|
||||
#define MAX_RAPID_FAILS_PER_MINUTE 100
|
||||
#define MILLISECONDS_IN_ONE_SECOND 1000
|
||||
#define MIN_PORT 1025
|
||||
#define MAX_PORT 48000
|
||||
|
||||
#define HEX_TO_ASCII(c) ((CHAR)(((c) < 10) ? ((c) + '0') : ((c) + 'a' - 10)))
|
||||
|
||||
extern HTTP_MODULE_ID g_pModuleId;
|
||||
extern IHttpServer * g_pHttpServer;
|
||||
extern BOOL g_fRecycleProcessCalled;
|
||||
|
||||
enum APP_HOSTING_MODEL
|
||||
{
|
||||
HOSTING_UNKNOWN = 0,
|
||||
HOSTING_IN_PROCESS,
|
||||
HOSTING_OUT_PROCESS
|
||||
};
|
||||
|
||||
class ASPNETCORE_CONFIG : IHttpStoredContext
|
||||
{
|
||||
public:
|
||||
|
||||
virtual
|
||||
~ASPNETCORE_CONFIG();
|
||||
|
||||
VOID
|
||||
CleanupStoredContext()
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
|
||||
static
|
||||
HRESULT
|
||||
GetConfig(
|
||||
_In_ IHttpContext *pHttpContext,
|
||||
_Out_ ASPNETCORE_CONFIG **ppAspNetCoreConfig
|
||||
);
|
||||
|
||||
ENVIRONMENT_VAR_HASH*
|
||||
QueryEnvironmentVariables(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
return m_pEnvironmentVariables;
|
||||
}
|
||||
|
||||
DWORD
|
||||
QueryRapidFailsPerMinute(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
return m_dwRapidFailsPerMinute;
|
||||
}
|
||||
|
||||
DWORD
|
||||
QueryStartupTimeLimitInMS(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
return m_dwStartupTimeLimitInMS;
|
||||
}
|
||||
|
||||
DWORD
|
||||
QueryShutdownTimeLimitInMS(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
return m_dwShutdownTimeLimitInMS;
|
||||
}
|
||||
|
||||
DWORD
|
||||
QueryProcessesPerApplication(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
return m_dwProcessesPerApplication;
|
||||
}
|
||||
|
||||
DWORD
|
||||
QueryRequestTimeoutInMS(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
return m_dwRequestTimeoutInMS;
|
||||
}
|
||||
|
||||
STRU*
|
||||
QueryArguments(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
return &m_struArguments;
|
||||
}
|
||||
|
||||
STRU*
|
||||
QueryApplicationPath(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
return &m_struApplication;
|
||||
}
|
||||
|
||||
STRU*
|
||||
QueryApplicationFullPath(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
return &m_struApplicationFullPath;
|
||||
}
|
||||
|
||||
STRU*
|
||||
QueryApplicationVirtualPath(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
return &m_struApplicationVirtualPath;
|
||||
}
|
||||
|
||||
STRU*
|
||||
QueryProcessPath(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
return &m_struProcessPath;
|
||||
}
|
||||
|
||||
APP_HOSTING_MODEL
|
||||
QueryHostingModel(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
return m_hostingModel;
|
||||
}
|
||||
|
||||
STRU*
|
||||
QueryHostingModelStr(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
return &m_strHostingModel;
|
||||
}
|
||||
|
||||
BOOL
|
||||
QueryStdoutLogEnabled()
|
||||
{
|
||||
return m_fStdoutLogEnabled;
|
||||
}
|
||||
|
||||
BOOL
|
||||
QueryForwardWindowsAuthToken()
|
||||
{
|
||||
return m_fForwardWindowsAuthToken;
|
||||
}
|
||||
|
||||
BOOL
|
||||
QueryWindowsAuthEnabled()
|
||||
{
|
||||
return m_fWindowsAuthEnabled;
|
||||
}
|
||||
|
||||
BOOL
|
||||
QueryBasicAuthEnabled()
|
||||
{
|
||||
return m_fBasicAuthEnabled;
|
||||
}
|
||||
|
||||
BOOL
|
||||
QueryAnonymousAuthEnabled()
|
||||
{
|
||||
return m_fAnonymousAuthEnabled;
|
||||
}
|
||||
|
||||
BOOL
|
||||
QueryDisableStartUpErrorPage()
|
||||
{
|
||||
return m_fDisableStartUpErrorPage;
|
||||
}
|
||||
|
||||
STRU*
|
||||
QueryStdoutLogFile()
|
||||
{
|
||||
return &m_struStdoutLogFile;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
//
|
||||
// private constructor
|
||||
//
|
||||
ASPNETCORE_CONFIG():
|
||||
m_fStdoutLogEnabled( FALSE ),
|
||||
m_pEnvironmentVariables( NULL ),
|
||||
m_hostingModel( HOSTING_UNKNOWN )
|
||||
{
|
||||
}
|
||||
|
||||
HRESULT
|
||||
Populate(
|
||||
IHttpContext *pHttpContext
|
||||
);
|
||||
|
||||
DWORD m_dwRequestTimeoutInMS;
|
||||
DWORD m_dwStartupTimeLimitInMS;
|
||||
DWORD m_dwShutdownTimeLimitInMS;
|
||||
DWORD m_dwRapidFailsPerMinute;
|
||||
DWORD m_dwProcessesPerApplication;
|
||||
STRU m_struApplication;
|
||||
STRU m_struArguments;
|
||||
STRU m_struProcessPath;
|
||||
STRU m_struStdoutLogFile;
|
||||
STRU m_struApplicationFullPath;
|
||||
STRU m_strHostingModel;
|
||||
STRU m_struApplicationVirtualPath;
|
||||
BOOL m_fStdoutLogEnabled;
|
||||
BOOL m_fForwardWindowsAuthToken;
|
||||
BOOL m_fDisableStartUpErrorPage;
|
||||
BOOL m_fWindowsAuthEnabled;
|
||||
BOOL m_fBasicAuthEnabled;
|
||||
BOOL m_fAnonymousAuthEnabled;
|
||||
APP_HOSTING_MODEL m_hostingModel;
|
||||
ENVIRONMENT_VAR_HASH* m_pEnvironmentVariables;
|
||||
};
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
//
|
||||
// this file is automatically generated
|
||||
// by beaver.exe 1.11.2003.0
|
||||
//
|
||||
|
||||
//
|
||||
// if you want to use a private version file and customize this, see
|
||||
// file://samsndrop02/CoreXT-Latest/docs/corext/corext/version.htm
|
||||
//
|
||||
|
||||
#ifndef _BLDVER_H_
|
||||
#define _BLDVER_H_
|
||||
|
||||
#define BUILD_NUMBER "1965.0"
|
||||
#define BUILD_NUM 1965,0
|
||||
#define PRODUCT_NUMBER "7.1"
|
||||
#define PRODUCT_NUM 7,1
|
||||
#define INET_VERSION "7.1.1965.0"
|
||||
#define INET_VERSION_L L"7.1.1965.0"
|
||||
#define INET_VER 7,1,1965,0
|
||||
|
||||
#define PRODUCT_MAJOR 7
|
||||
#define PRODUCT_MAJOR_STRING "7"
|
||||
#define PRODUCT_MAJOR_NUMBER 7
|
||||
|
||||
#define PRODUCT_MINOR 1
|
||||
#define PRODUCT_MINOR_STRING "1"
|
||||
#define PRODUCT_MINOR_NUMBER 1
|
||||
|
||||
#define BUILD_MAJOR 1965
|
||||
#define BUILD_MAJOR_STRING "1965"
|
||||
#define BUILD_MAJOR_NUMBER 1965
|
||||
|
||||
#define BUILD_MINOR 0
|
||||
#define BUILD_MINOR_STRING "0"
|
||||
#define BUILD_MINOR_NUMBER 0
|
||||
|
||||
#define BUILD_PRIVATE "Built by panwang on IIS-OOB.\0"
|
||||
|
||||
// beaver.exe can't handle a pragma to disable redefinition
|
||||
#undef VER_PRODUCTVERSION
|
||||
#undef VER_PRODUCTVERSION_STR
|
||||
#undef VER_PRODUCTMAJORVERSION
|
||||
#undef VER_PRODUCTMINORVERSION
|
||||
#undef VER_PRODUCTBUILD
|
||||
#undef VER_PRODUCTBUILD_QFE
|
||||
#undef VER_PRODUCTNAME_STR
|
||||
#undef VER_COMPANYNAME_STR
|
||||
|
||||
#define VER_PRODUCTVERSION 7,1,1965,0
|
||||
#define VER_PRODUCTVERSION_STR 7.1.1965.0
|
||||
#define VER_PRODUCTMAJORVERSION 7
|
||||
#define VER_PRODUCTMINORVERSION 1
|
||||
#define VER_PRODUCTBUILD 1965
|
||||
#define VER_PRODUCTBUILD_QFE 0
|
||||
#define VER_PRODUCTNAME_STR "Microsoft Web Platform Extensions"
|
||||
#define VER_COMPANYNAME_STR "Microsoft Corporation"
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,82 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
#define ASPNETCORE_DEBUG_FLAG_INFO 0x00000001
|
||||
#define ASPNETCORE_DEBUG_FLAG_WARNING 0x00000002
|
||||
#define ASPNETCORE_DEBUG_FLAG_ERROR 0x00000004
|
||||
|
||||
extern DWORD g_dwAspNetCoreDebugFlags;
|
||||
|
||||
static
|
||||
BOOL
|
||||
IfDebug(
|
||||
DWORD dwFlag
|
||||
)
|
||||
{
|
||||
return ( dwFlag & g_dwAspNetCoreDebugFlags );
|
||||
}
|
||||
|
||||
static
|
||||
VOID
|
||||
DebugPrint(
|
||||
DWORD dwFlag,
|
||||
LPCSTR szString
|
||||
)
|
||||
{
|
||||
STACK_STRA (strOutput, 256);
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
if ( IfDebug( dwFlag ) )
|
||||
{
|
||||
hr = strOutput.SafeSnprintf(
|
||||
"[aspnetcore.dll] %s\r\n",
|
||||
szString );
|
||||
|
||||
if (FAILED (hr))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
OutputDebugStringA( strOutput.QueryStr() );
|
||||
}
|
||||
|
||||
Finished:
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static
|
||||
VOID
|
||||
DebugPrintf(
|
||||
DWORD dwFlag,
|
||||
LPCSTR szFormat,
|
||||
...
|
||||
)
|
||||
{
|
||||
STACK_STRA (strCooked,256);
|
||||
|
||||
va_list args;
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
if ( IfDebug( dwFlag ) )
|
||||
{
|
||||
va_start( args, szFormat );
|
||||
|
||||
hr = strCooked.SafeVsnprintf(szFormat, args );
|
||||
|
||||
va_end( args );
|
||||
|
||||
if (FAILED (hr))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
DebugPrint( dwFlag, strCooked.QueryStr() );
|
||||
}
|
||||
|
||||
Finished:
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,155 @@
|
|||
// 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 ENVIRONMENT_VAR_ENTRY
|
||||
{
|
||||
public:
|
||||
ENVIRONMENT_VAR_ENTRY():
|
||||
_cRefs(1)
|
||||
{
|
||||
}
|
||||
|
||||
HRESULT
|
||||
Initialize(
|
||||
PCWSTR pszName,
|
||||
PCWSTR pszValue
|
||||
)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
if (FAILED(hr = _strName.Copy(pszName)) ||
|
||||
FAILED(hr = _strValue.Copy(pszValue)))
|
||||
{
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
VOID
|
||||
Reference() const
|
||||
{
|
||||
InterlockedIncrement(&_cRefs);
|
||||
}
|
||||
|
||||
VOID
|
||||
Dereference() const
|
||||
{
|
||||
if (InterlockedDecrement(&_cRefs) == 0)
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
}
|
||||
|
||||
PWSTR const
|
||||
QueryName()
|
||||
{
|
||||
return _strName.QueryStr();
|
||||
}
|
||||
|
||||
PWSTR const
|
||||
QueryValue()
|
||||
{
|
||||
return _strValue.QueryStr();
|
||||
}
|
||||
|
||||
private:
|
||||
~ENVIRONMENT_VAR_ENTRY()
|
||||
{
|
||||
}
|
||||
|
||||
STRU _strName;
|
||||
STRU _strValue;
|
||||
mutable LONG _cRefs;
|
||||
};
|
||||
|
||||
class ENVIRONMENT_VAR_HASH : public HASH_TABLE<ENVIRONMENT_VAR_ENTRY, PWSTR>
|
||||
{
|
||||
public:
|
||||
ENVIRONMENT_VAR_HASH()
|
||||
{}
|
||||
|
||||
PWSTR
|
||||
ExtractKey(
|
||||
ENVIRONMENT_VAR_ENTRY * pEntry
|
||||
)
|
||||
{
|
||||
return pEntry->QueryName();
|
||||
}
|
||||
|
||||
DWORD
|
||||
CalcKeyHash(
|
||||
PWSTR pszName
|
||||
)
|
||||
{
|
||||
return HashStringNoCase(pszName);
|
||||
}
|
||||
|
||||
BOOL
|
||||
EqualKeys(
|
||||
PWSTR pszName1,
|
||||
PWSTR pszName2
|
||||
)
|
||||
{
|
||||
return (_wcsicmp(pszName1, pszName2) == 0);
|
||||
}
|
||||
|
||||
VOID
|
||||
ReferenceRecord(
|
||||
ENVIRONMENT_VAR_ENTRY * pEntry
|
||||
)
|
||||
{
|
||||
pEntry->Reference();
|
||||
}
|
||||
|
||||
VOID
|
||||
DereferenceRecord(
|
||||
ENVIRONMENT_VAR_ENTRY * pEntry
|
||||
)
|
||||
{
|
||||
pEntry->Dereference();
|
||||
}
|
||||
|
||||
static
|
||||
VOID
|
||||
CopyToMultiSz(
|
||||
ENVIRONMENT_VAR_ENTRY * pEntry,
|
||||
PVOID pvData
|
||||
)
|
||||
{
|
||||
STRU strTemp;
|
||||
MULTISZ *pMultiSz = static_cast<MULTISZ *>(pvData);
|
||||
DBG_ASSERT(pMultiSz);
|
||||
DBG_ASSERT(pEntry);
|
||||
strTemp.Copy(pEntry->QueryName());
|
||||
strTemp.Append(pEntry->QueryValue());
|
||||
pMultiSz->Append(strTemp.QueryStr());
|
||||
}
|
||||
|
||||
static
|
||||
VOID
|
||||
CopyToTable(
|
||||
ENVIRONMENT_VAR_ENTRY * pEntry,
|
||||
PVOID pvData
|
||||
)
|
||||
{
|
||||
// best effort copy, ignore the failure
|
||||
ENVIRONMENT_VAR_ENTRY * pNewEntry = new ENVIRONMENT_VAR_ENTRY();
|
||||
if (pNewEntry != NULL)
|
||||
{
|
||||
pNewEntry->Initialize(pEntry->QueryName(), pEntry->QueryValue());
|
||||
ENVIRONMENT_VAR_HASH *pHash = static_cast<ENVIRONMENT_VAR_HASH *>(pvData);
|
||||
DBG_ASSERT(pHash);
|
||||
pHash->InsertRecord(pNewEntry);
|
||||
// Need to dereference as InsertRecord references it now
|
||||
pNewEntry->Dereference();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
ENVIRONMENT_VAR_HASH(const ENVIRONMENT_VAR_HASH &);
|
||||
void operator=(const ENVIRONMENT_VAR_HASH &);
|
||||
};
|
||||
|
|
@ -0,0 +1,126 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
#define FILE_WATCHER_SHUTDOWN_KEY (ULONG_PTR)(-1)
|
||||
#define FILE_WATCHER_ENTRY_BUFFER_SIZE 4096
|
||||
#ifndef CONTAINING_RECORD
|
||||
//
|
||||
// Calculate the address of the base of the structure given its type, and an
|
||||
// address of a field within the structure.
|
||||
//
|
||||
|
||||
#define CONTAINING_RECORD(address, type, field) \
|
||||
((type *)((PCHAR)(address)-(ULONG_PTR)(&((type *)0)->field)))
|
||||
|
||||
#endif // !CONTAINING_RECORD
|
||||
#define FILE_NOTIFY_VALID_MASK 0x00000fff
|
||||
#define FILE_WATCHER_ENTRY_SIGNATURE ((DWORD) 'FWES')
|
||||
#define FILE_WATCHER_ENTRY_SIGNATURE_FREE ((DWORD) 'sewf')
|
||||
|
||||
class APPLICATION;
|
||||
|
||||
class FILE_WATCHER{
|
||||
public:
|
||||
|
||||
FILE_WATCHER();
|
||||
|
||||
~FILE_WATCHER();
|
||||
|
||||
HRESULT Create();
|
||||
|
||||
HANDLE
|
||||
QueryCompletionPort(
|
||||
VOID
|
||||
) const
|
||||
{
|
||||
return m_hCompletionPort;
|
||||
}
|
||||
|
||||
static
|
||||
DWORD
|
||||
WINAPI ChangeNotificationThread(LPVOID);
|
||||
|
||||
static
|
||||
void
|
||||
WINAPI FileWatcherCompletionRoutine
|
||||
(
|
||||
DWORD dwCompletionStatus,
|
||||
DWORD cbCompletion,
|
||||
OVERLAPPED * pOverlapped
|
||||
);
|
||||
|
||||
private:
|
||||
HANDLE m_hCompletionPort;
|
||||
HANDLE m_hChangeNotificationThread;
|
||||
};
|
||||
|
||||
class FILE_WATCHER_ENTRY
|
||||
{
|
||||
public:
|
||||
FILE_WATCHER_ENTRY(FILE_WATCHER * pFileMonitor);
|
||||
|
||||
OVERLAPPED _overlapped;
|
||||
|
||||
HRESULT
|
||||
Create(
|
||||
_In_ PCWSTR pszDirectoryToMonitor,
|
||||
_In_ PCWSTR pszFileNameToMonitor,
|
||||
_In_ APPLICATION* pApplication,
|
||||
_In_ HANDLE hImpersonationToken
|
||||
);
|
||||
|
||||
VOID
|
||||
ReferenceFileWatcherEntry() const
|
||||
{
|
||||
InterlockedIncrement(&_cRefs);
|
||||
}
|
||||
|
||||
VOID
|
||||
DereferenceFileWatcherEntry() const
|
||||
{
|
||||
if (InterlockedDecrement(&_cRefs) == 0)
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
}
|
||||
|
||||
BOOL
|
||||
QueryIsValid() const
|
||||
{
|
||||
return _fIsValid;
|
||||
}
|
||||
|
||||
VOID
|
||||
MarkEntryInValid()
|
||||
{
|
||||
_fIsValid = FALSE;
|
||||
}
|
||||
|
||||
HRESULT Monitor();
|
||||
|
||||
VOID StopMonitor();
|
||||
|
||||
HRESULT
|
||||
HandleChangeCompletion(
|
||||
_In_ DWORD dwCompletionStatus,
|
||||
_In_ DWORD cbCompletion
|
||||
);
|
||||
|
||||
private:
|
||||
virtual ~FILE_WATCHER_ENTRY();
|
||||
|
||||
DWORD _dwSignature;
|
||||
BUFFER _buffDirectoryChanges;
|
||||
HANDLE _hImpersonationToken;
|
||||
HANDLE _hDirectory;
|
||||
FILE_WATCHER* _pFileMonitor;
|
||||
APPLICATION* _pApplication;
|
||||
STRU _strFileName;
|
||||
STRU _strDirectoryName;
|
||||
LONG _lStopMonitorCalled;
|
||||
mutable LONG _cRefs;
|
||||
BOOL _fIsValid;
|
||||
SRWLOCK _srwLock;
|
||||
};
|
||||
|
|
@ -0,0 +1,157 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
//
|
||||
// The key used for hash-table lookups, consists of the port on which the http process is created.
|
||||
//
|
||||
class FORWARDER_CONNECTION_KEY
|
||||
{
|
||||
public:
|
||||
|
||||
FORWARDER_CONNECTION_KEY(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
}
|
||||
|
||||
HRESULT
|
||||
Initialize(
|
||||
_In_ DWORD dwPort
|
||||
)
|
||||
{
|
||||
m_dwPort = dwPort;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
BOOL
|
||||
GetIsEqual(
|
||||
const FORWARDER_CONNECTION_KEY * key2
|
||||
) const
|
||||
{
|
||||
return m_dwPort == key2->m_dwPort;
|
||||
}
|
||||
|
||||
DWORD CalcKeyHash() const
|
||||
{
|
||||
// TODO: Review hash distribution.
|
||||
return Hash(m_dwPort);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
DWORD m_dwPort;
|
||||
};
|
||||
|
||||
class FORWARDER_CONNECTION
|
||||
{
|
||||
public:
|
||||
|
||||
FORWARDER_CONNECTION(
|
||||
VOID
|
||||
);
|
||||
|
||||
HRESULT
|
||||
Initialize(
|
||||
DWORD dwPort
|
||||
);
|
||||
|
||||
HINTERNET
|
||||
QueryHandle() const
|
||||
{
|
||||
return m_hConnection;
|
||||
}
|
||||
|
||||
VOID
|
||||
ReferenceForwarderConnection() const
|
||||
{
|
||||
InterlockedIncrement(&m_cRefs);
|
||||
}
|
||||
|
||||
VOID
|
||||
DereferenceForwarderConnection() const
|
||||
{
|
||||
if (InterlockedDecrement(&m_cRefs) == 0)
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
}
|
||||
|
||||
FORWARDER_CONNECTION_KEY *
|
||||
QueryConnectionKey()
|
||||
{
|
||||
return &m_ConnectionKey;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
~FORWARDER_CONNECTION()
|
||||
{
|
||||
if (m_hConnection != NULL)
|
||||
{
|
||||
WinHttpCloseHandle(m_hConnection);
|
||||
m_hConnection = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
mutable LONG m_cRefs;
|
||||
FORWARDER_CONNECTION_KEY m_ConnectionKey;
|
||||
HINTERNET m_hConnection;
|
||||
};
|
||||
|
||||
class FORWARDER_CONNECTION_HASH :
|
||||
public HASH_TABLE<FORWARDER_CONNECTION, FORWARDER_CONNECTION_KEY *>
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
FORWARDER_CONNECTION_HASH()
|
||||
{}
|
||||
|
||||
FORWARDER_CONNECTION_KEY *
|
||||
ExtractKey(
|
||||
FORWARDER_CONNECTION *pConnection
|
||||
)
|
||||
{
|
||||
return pConnection->QueryConnectionKey();
|
||||
}
|
||||
|
||||
DWORD
|
||||
CalcKeyHash(
|
||||
FORWARDER_CONNECTION_KEY *key
|
||||
)
|
||||
{
|
||||
return key->CalcKeyHash();
|
||||
}
|
||||
|
||||
BOOL
|
||||
EqualKeys(
|
||||
FORWARDER_CONNECTION_KEY *key1,
|
||||
FORWARDER_CONNECTION_KEY *key2
|
||||
)
|
||||
{
|
||||
return key1->GetIsEqual(key2);
|
||||
}
|
||||
|
||||
VOID
|
||||
ReferenceRecord(
|
||||
FORWARDER_CONNECTION *pConnection
|
||||
)
|
||||
{
|
||||
pConnection->ReferenceForwarderConnection();
|
||||
}
|
||||
|
||||
VOID
|
||||
DereferenceRecord(
|
||||
FORWARDER_CONNECTION *pConnection
|
||||
)
|
||||
{
|
||||
pConnection->DereferenceForwarderConnection();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
FORWARDER_CONNECTION_HASH(const FORWARDER_CONNECTION_HASH &);
|
||||
void operator=(const FORWARDER_CONNECTION_HASH &);
|
||||
};
|
||||
|
|
@ -0,0 +1,446 @@
|
|||
// 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<FORWARDING_HANDLER *>(reinterpret_cast<PVOID>(dwContext));
|
||||
if (pThis == NULL)
|
||||
{
|
||||
//error happened, nothing can be done here
|
||||
return;
|
||||
}
|
||||
DBG_ASSERT(pThis->m_Signature == FORWARDING_HANDLER_SIGNATURE);
|
||||
pThis->OnWinHttpCompletionInternal(hRequest,
|
||||
dwInternetStatus,
|
||||
lpvStatusInformation,
|
||||
dwStatusInformationLength);
|
||||
}
|
||||
|
||||
static
|
||||
HRESULT
|
||||
StaticInitialize(
|
||||
BOOL fEnableReferenceCountTracing
|
||||
);
|
||||
|
||||
static
|
||||
VOID
|
||||
StaticTerminate();
|
||||
|
||||
static
|
||||
PCWSTR
|
||||
QueryErrorFormat()
|
||||
{
|
||||
return sm_strErrorFormat.QueryStr();
|
||||
}
|
||||
|
||||
static
|
||||
HANDLE
|
||||
QueryEventLog()
|
||||
{
|
||||
return sm_hEventLog;
|
||||
}
|
||||
|
||||
VOID
|
||||
TerminateRequest(
|
||||
bool fClientInitiated
|
||||
);
|
||||
|
||||
static HINTERNET sm_hSession;
|
||||
|
||||
HRESULT
|
||||
SetStatusAndHeaders(
|
||||
PCSTR pszHeaders,
|
||||
DWORD cchHeaders
|
||||
);
|
||||
|
||||
HRESULT
|
||||
OnSharedRequestEntity(
|
||||
ULONGLONG ulOffset,
|
||||
LPCBYTE pvBuffer,
|
||||
DWORD cbBuffer
|
||||
);
|
||||
|
||||
VOID
|
||||
SetStatus(
|
||||
FORWARDING_REQUEST_STATUS status
|
||||
)
|
||||
{
|
||||
m_RequestStatus = status;
|
||||
}
|
||||
|
||||
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<BYTE*,INLINE_ENTITY_BUFFERS> 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;
|
||||
};
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
#ifndef __FX_VER_H__
|
||||
#define __FX_VER_H__
|
||||
#include <string>
|
||||
|
||||
// Note: This is not SemVer (esp., in comparing pre-release part, fx_ver_t does not
|
||||
// compare multiple dot separated identifiers individually.) ex: 1.0.0-beta.2 vs. 1.0.0-beta.11
|
||||
struct fx_ver_t
|
||||
{
|
||||
fx_ver_t(int major, int minor, int patch);
|
||||
fx_ver_t(int major, int minor, int patch, const std::wstring& pre);
|
||||
fx_ver_t(int major, int minor, int patch, const std::wstring& pre, const std::wstring& build);
|
||||
|
||||
int get_major() const { return m_major; }
|
||||
int get_minor() const { return m_minor; }
|
||||
int get_patch() const { return m_patch; }
|
||||
|
||||
void set_major(int m) { m_major = m; }
|
||||
void set_minor(int m) { m_minor = m; }
|
||||
void set_patch(int p) { m_patch = p; }
|
||||
|
||||
bool is_prerelease() const { return !m_pre.empty(); }
|
||||
|
||||
std::wstring as_str() const;
|
||||
std::wstring prerelease_glob() const;
|
||||
std::wstring patch_glob() const;
|
||||
|
||||
bool operator ==(const fx_ver_t& b) const;
|
||||
bool operator !=(const fx_ver_t& b) const;
|
||||
bool operator <(const fx_ver_t& b) const;
|
||||
bool operator >(const fx_ver_t& b) const;
|
||||
bool operator <=(const fx_ver_t& b) const;
|
||||
bool operator >=(const fx_ver_t& b) const;
|
||||
|
||||
static bool parse(const std::wstring& ver, fx_ver_t* fx_ver, bool parse_only_production = false);
|
||||
|
||||
private:
|
||||
int m_major;
|
||||
int m_minor;
|
||||
int m_patch;
|
||||
std::wstring m_pre;
|
||||
std::wstring m_build;
|
||||
|
||||
static int compare(const fx_ver_t&a, const fx_ver_t& b);
|
||||
};
|
||||
|
||||
#endif // __FX_VER_H__
|
||||
|
|
@ -0,0 +1,135 @@
|
|||
// 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 void(*request_handler_cb) (int error, IHttpContext* pHttpContext, void* pvCompletionContext);
|
||||
typedef REQUEST_NOTIFICATION_STATUS(*PFN_REQUEST_HANDLER) (IHttpContext* pHttpContext, void* pvRequstHandlerContext);
|
||||
typedef BOOL(*PFN_SHUTDOWN_HANDLER) (void* pvShutdownHandlerContext);
|
||||
typedef REQUEST_NOTIFICATION_STATUS(*PFN_MANAGED_CONTEXT_HANDLER)(void *pvManagedHttpContext, HRESULT hrCompletionStatus, DWORD cbCompletion);
|
||||
|
||||
#include "application.h"
|
||||
|
||||
class IN_PROCESS_APPLICATION : public APPLICATION
|
||||
{
|
||||
public:
|
||||
IN_PROCESS_APPLICATION();
|
||||
|
||||
~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
|
||||
);
|
||||
|
||||
VOID
|
||||
SetCallbackHandles(
|
||||
_In_ PFN_REQUEST_HANDLER request_callback,
|
||||
_In_ PFN_SHUTDOWN_HANDLER shutdown_callback,
|
||||
_In_ PFN_MANAGED_CONTEXT_HANDLER managed_context_callback,
|
||||
_In_ VOID* pvRequstHandlerContext,
|
||||
_In_ VOID* pvShutdownHandlerContext
|
||||
);
|
||||
|
||||
// Executes the .NET Core process
|
||||
HRESULT
|
||||
ExecuteApplication(
|
||||
VOID
|
||||
);
|
||||
|
||||
HRESULT
|
||||
LoadManagedApplication(
|
||||
VOID
|
||||
);
|
||||
|
||||
REQUEST_NOTIFICATION_STATUS
|
||||
OnAsyncCompletion(
|
||||
IHttpContext* pHttpContext,
|
||||
DWORD cbCompletion,
|
||||
HRESULT hrCompletionStatus
|
||||
);
|
||||
|
||||
static
|
||||
IN_PROCESS_APPLICATION*
|
||||
GetInstance(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
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;
|
||||
|
||||
// The shutdown handler callback from managed code
|
||||
PFN_SHUTDOWN_HANDLER m_ShutdownHandler;
|
||||
VOID* m_ShutdownHandlerContext;
|
||||
|
||||
PFN_MANAGED_CONTEXT_HANDLER m_AsyncCompletionHandler;
|
||||
|
||||
// The event that gets triggered when managed initialization is complete
|
||||
HANDLE m_pInitalizeEvent;
|
||||
|
||||
// The exit code of the .NET Core process
|
||||
INT m_ProcessExitCode;
|
||||
|
||||
BOOL m_fManagedAppLoaded;
|
||||
BOOL m_fLoadManagedAppError;
|
||||
BOOL m_fInitialized;
|
||||
BOOL m_fIsWebSocketsConnection;
|
||||
|
||||
static IN_PROCESS_APPLICATION* s_Application;
|
||||
|
||||
static
|
||||
VOID
|
||||
FindDotNetFolders(
|
||||
_In_ PCWSTR pszPath,
|
||||
_Out_ std::vector<std::wstring> *pvFolders
|
||||
);
|
||||
|
||||
static
|
||||
HRESULT
|
||||
FindHighestDotNetVersion(
|
||||
_In_ std::vector<std::wstring> vFolders,
|
||||
_Out_ STRU *pstrResult
|
||||
);
|
||||
|
||||
static
|
||||
BOOL
|
||||
DirectoryExists(
|
||||
_In_ STRU *pstrPath //todo: this does not need to be stru, can be PCWSTR
|
||||
);
|
||||
|
||||
static BOOL
|
||||
GetEnv(
|
||||
_In_ PCWSTR pszEnvironmentVariable,
|
||||
_Out_ STRU *pstrResult
|
||||
);
|
||||
|
||||
static
|
||||
VOID
|
||||
ExecuteAspNetCoreProcess(
|
||||
_In_ LPVOID pContext
|
||||
);
|
||||
|
||||
};
|
||||
|
|
@ -0,0 +1,90 @@
|
|||
// 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;
|
||||
};
|
||||
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
// 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;
|
||||
};
|
||||
|
|
@ -0,0 +1,95 @@
|
|||
// 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 PATH
|
||||
{
|
||||
public:
|
||||
|
||||
static
|
||||
HRESULT
|
||||
SplitUrl(
|
||||
PCWSTR pszDestinationUrl,
|
||||
BOOL *pfSecure,
|
||||
STRU *pstrDestination,
|
||||
STRU *pstrUrl
|
||||
);
|
||||
|
||||
static
|
||||
HRESULT
|
||||
UnEscapeUrl(
|
||||
PCWSTR pszUrl,
|
||||
DWORD cchUrl,
|
||||
bool fCopyQuery,
|
||||
STRA * pstrResult
|
||||
);
|
||||
|
||||
static
|
||||
HRESULT
|
||||
UnEscapeUrl(
|
||||
PCWSTR pszUrl,
|
||||
DWORD cchUrl,
|
||||
STRU * pstrResult
|
||||
);
|
||||
|
||||
static HRESULT
|
||||
EscapeAbsPath(
|
||||
IHttpRequest * pRequest,
|
||||
STRU * strEscapedUrl
|
||||
);
|
||||
|
||||
static
|
||||
bool
|
||||
IsValidAttributeNameChar(
|
||||
WCHAR ch
|
||||
);
|
||||
|
||||
static
|
||||
bool
|
||||
IsValidQueryStringName(
|
||||
PCWSTR pszName
|
||||
);
|
||||
|
||||
static
|
||||
bool
|
||||
IsValidHeaderName(
|
||||
PCWSTR pszName
|
||||
);
|
||||
|
||||
static
|
||||
bool
|
||||
FindInMultiString(
|
||||
PCWSTR pszMultiString,
|
||||
PCWSTR pszStringToFind
|
||||
);
|
||||
|
||||
static
|
||||
HRESULT
|
||||
IsPathUnc(
|
||||
__in LPCWSTR pszPath,
|
||||
__out BOOL * pfIsUnc
|
||||
);
|
||||
|
||||
static
|
||||
HRESULT
|
||||
ConvertPathToFullPath(
|
||||
_In_ LPCWSTR pszPath,
|
||||
_In_ LPCWSTR pszRootPath,
|
||||
_Out_ STRU* pStrFullPath
|
||||
);
|
||||
|
||||
private:
|
||||
|
||||
PATH() {}
|
||||
~PATH() {}
|
||||
|
||||
static
|
||||
CHAR
|
||||
ToHexDigit(
|
||||
UINT nDigit
|
||||
)
|
||||
{
|
||||
return static_cast<CHAR>(nDigit > 9 ? nDigit - 10 + 'A' : nDigit + '0');
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,193 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
#define ONE_MINUTE_IN_MILLISECONDS 60000
|
||||
|
||||
class PROCESS_MANAGER
|
||||
{
|
||||
public:
|
||||
|
||||
virtual
|
||||
~PROCESS_MANAGER();
|
||||
|
||||
VOID
|
||||
ReferenceProcessManager() const
|
||||
{
|
||||
InterlockedIncrement(&m_cRefs);
|
||||
}
|
||||
|
||||
VOID
|
||||
DereferenceProcessManager() const
|
||||
{
|
||||
if (InterlockedDecrement(&m_cRefs) == 0)
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT
|
||||
GetProcess(
|
||||
_In_ IHttpContext *context,
|
||||
_In_ ASPNETCORE_CONFIG *pConfig,
|
||||
_Out_ SERVER_PROCESS **ppServerProcess
|
||||
);
|
||||
|
||||
HANDLE
|
||||
QueryNULHandle()
|
||||
{
|
||||
return m_hNULHandle;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
Initialize(
|
||||
VOID
|
||||
);
|
||||
|
||||
VOID
|
||||
SendShutdownSignal()
|
||||
{
|
||||
AcquireSRWLockExclusive( &m_srwLock );
|
||||
|
||||
for(DWORD i = 0; i < m_dwProcessesPerApplication; ++i )
|
||||
{
|
||||
if( m_ppServerProcessList != NULL &&
|
||||
m_ppServerProcessList[i] != NULL )
|
||||
{
|
||||
m_ppServerProcessList[i]->SendSignal();
|
||||
m_ppServerProcessList[i]->DereferenceServerProcess();
|
||||
m_ppServerProcessList[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
ReleaseSRWLockExclusive( &m_srwLock );
|
||||
}
|
||||
|
||||
VOID
|
||||
ShutdownProcess(
|
||||
SERVER_PROCESS* pServerProcess
|
||||
)
|
||||
{
|
||||
AcquireSRWLockExclusive( &m_srwLock );
|
||||
|
||||
ShutdownProcessNoLock( pServerProcess );
|
||||
|
||||
ReleaseSRWLockExclusive( &m_srwLock );
|
||||
}
|
||||
|
||||
VOID
|
||||
ShutdownAllProcesses(
|
||||
)
|
||||
{
|
||||
AcquireSRWLockExclusive( &m_srwLock );
|
||||
|
||||
ShutdownAllProcessesNoLock();
|
||||
|
||||
ReleaseSRWLockExclusive( &m_srwLock );
|
||||
}
|
||||
|
||||
VOID
|
||||
IncrementRapidFailCount(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
InterlockedIncrement(&m_cRapidFailCount);
|
||||
}
|
||||
|
||||
PROCESS_MANAGER() :
|
||||
m_ppServerProcessList( NULL ),
|
||||
m_hNULHandle( NULL ),
|
||||
m_cRapidFailCount( 0 ),
|
||||
m_dwProcessesPerApplication( 1 ),
|
||||
m_dwRouteToProcessIndex( 0 ),
|
||||
m_fServerProcessListReady(FALSE),
|
||||
m_cRefs( 1 )
|
||||
{
|
||||
InitializeSRWLock( &m_srwLock );
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
BOOL
|
||||
RapidFailsPerMinuteExceeded(
|
||||
LONG dwRapidFailsPerMinute
|
||||
)
|
||||
{
|
||||
DWORD dwCurrentTickCount = GetTickCount();
|
||||
|
||||
if( (dwCurrentTickCount - m_dwRapidFailTickStart)
|
||||
>= ONE_MINUTE_IN_MILLISECONDS )
|
||||
{
|
||||
//
|
||||
// reset counters every minute.
|
||||
//
|
||||
|
||||
InterlockedExchange(&m_cRapidFailCount, 0);
|
||||
m_dwRapidFailTickStart = dwCurrentTickCount;
|
||||
}
|
||||
|
||||
return m_cRapidFailCount > dwRapidFailsPerMinute;
|
||||
}
|
||||
|
||||
VOID
|
||||
ShutdownProcessNoLock(
|
||||
SERVER_PROCESS* pServerProcess
|
||||
)
|
||||
{
|
||||
for(DWORD i = 0; i < m_dwProcessesPerApplication; ++i )
|
||||
{
|
||||
if( m_ppServerProcessList != NULL &&
|
||||
m_ppServerProcessList[i] != NULL &&
|
||||
m_ppServerProcessList[i]->GetPort() == pServerProcess->GetPort() )
|
||||
{
|
||||
// shutdown pServerProcess if not already shutdown.
|
||||
m_ppServerProcessList[i]->StopProcess();
|
||||
m_ppServerProcessList[i]->DereferenceServerProcess();
|
||||
m_ppServerProcessList[i] = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VOID
|
||||
ShutdownAllProcessesNoLock(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
for(DWORD i = 0; i < m_dwProcessesPerApplication; ++i )
|
||||
{
|
||||
if( m_ppServerProcessList != NULL &&
|
||||
m_ppServerProcessList[i] != NULL )
|
||||
{
|
||||
// shutdown pServerProcess if not already shutdown.
|
||||
m_ppServerProcessList[i]->SendSignal();
|
||||
m_ppServerProcessList[i]->DereferenceServerProcess();
|
||||
m_ppServerProcessList[i] = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
volatile LONG m_cRapidFailCount;
|
||||
DWORD m_dwRapidFailTickStart;
|
||||
DWORD m_dwProcessesPerApplication;
|
||||
volatile DWORD m_dwRouteToProcessIndex;
|
||||
|
||||
SRWLOCK m_srwLock;
|
||||
SERVER_PROCESS **m_ppServerProcessList;
|
||||
|
||||
//
|
||||
// m_hNULHandle is used to redirect stdout/stderr to NUL.
|
||||
// If Createprocess is called to launch a batch file for example,
|
||||
// it tries to write to the console buffer by default. It fails to
|
||||
// start if the console buffer is owned by the parent process i.e
|
||||
// in our case w3wp.exe. So we have to redirect the stdout/stderr
|
||||
// of the child process to NUL or to a file (anything other than
|
||||
// the console buffer of the parent process).
|
||||
//
|
||||
|
||||
HANDLE m_hNULHandle;
|
||||
mutable LONG m_cRefs;
|
||||
|
||||
volatile static BOOL sm_fWSAStartupDone;
|
||||
volatile BOOL m_fServerProcessListReady;
|
||||
};
|
||||
|
|
@ -0,0 +1,105 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "aspnetcoreconfig.h"
|
||||
|
||||
class PROTOCOL_CONFIG
|
||||
{
|
||||
public:
|
||||
|
||||
PROTOCOL_CONFIG()
|
||||
{
|
||||
}
|
||||
|
||||
HRESULT
|
||||
Initialize();
|
||||
|
||||
VOID
|
||||
OverrideConfig(
|
||||
ASPNETCORE_CONFIG *pAspNetCoreConfig
|
||||
);
|
||||
|
||||
BOOL
|
||||
QueryDoKeepAlive() const
|
||||
{
|
||||
return m_fKeepAlive;
|
||||
}
|
||||
|
||||
DWORD
|
||||
QueryTimeout() const
|
||||
{
|
||||
return m_msTimeout;
|
||||
}
|
||||
|
||||
BOOL
|
||||
QueryPreserveHostHeader() const
|
||||
{
|
||||
return m_fPreserveHostHeader;
|
||||
}
|
||||
|
||||
BOOL
|
||||
QueryReverseRewriteHeaders() const
|
||||
{
|
||||
return m_fReverseRewriteHeaders;
|
||||
}
|
||||
|
||||
const STRA *
|
||||
QueryXForwardedForName() const
|
||||
{
|
||||
return &m_strXForwardedForName;
|
||||
}
|
||||
|
||||
BOOL
|
||||
QueryIncludePortInXForwardedFor() const
|
||||
{
|
||||
return m_fIncludePortInXForwardedFor;
|
||||
}
|
||||
|
||||
DWORD
|
||||
QueryMinResponseBuffer() const
|
||||
{
|
||||
return m_dwMinResponseBuffer;
|
||||
}
|
||||
|
||||
DWORD
|
||||
QueryResponseBufferLimit() const
|
||||
{
|
||||
return m_dwResponseBufferLimit;
|
||||
}
|
||||
|
||||
DWORD
|
||||
QueryMaxResponseHeaderSize() const
|
||||
{
|
||||
return m_dwMaxResponseHeaderSize;
|
||||
}
|
||||
|
||||
const STRA*
|
||||
QuerySslHeaderName() const
|
||||
{
|
||||
return &m_strSslHeaderName;
|
||||
}
|
||||
|
||||
const STRA *
|
||||
QueryClientCertName() const
|
||||
{
|
||||
return &m_strClientCertName;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
BOOL m_fKeepAlive;
|
||||
BOOL m_fPreserveHostHeader;
|
||||
BOOL m_fReverseRewriteHeaders;
|
||||
BOOL m_fIncludePortInXForwardedFor;
|
||||
|
||||
DWORD m_msTimeout;
|
||||
DWORD m_dwMinResponseBuffer;
|
||||
DWORD m_dwResponseBufferLimit;
|
||||
DWORD m_dwMaxResponseHeaderSize;
|
||||
|
||||
STRA m_strXForwardedForName;
|
||||
STRA m_strSslHeaderName;
|
||||
STRA m_strClientCertName;
|
||||
};
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
|
||||
// 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"
|
||||
|
||||
class CProxyModule : public CHttpModule
|
||||
{
|
||||
public:
|
||||
|
||||
CProxyModule();
|
||||
|
||||
~CProxyModule();
|
||||
|
||||
void * operator new(size_t size, IModuleAllocator * pPlacement)
|
||||
{
|
||||
return pPlacement->AllocateMemory(static_cast<DWORD>(size));
|
||||
}
|
||||
|
||||
VOID
|
||||
operator delete(
|
||||
void *
|
||||
)
|
||||
{}
|
||||
|
||||
__override
|
||||
REQUEST_NOTIFICATION_STATUS
|
||||
OnExecuteRequestHandler(
|
||||
IHttpContext * pHttpContext,
|
||||
IHttpEventProvider * pProvider
|
||||
);
|
||||
|
||||
__override
|
||||
REQUEST_NOTIFICATION_STATUS
|
||||
OnAsyncCompletion(
|
||||
IHttpContext * pHttpContext,
|
||||
DWORD dwNotification,
|
||||
BOOL fPostNotification,
|
||||
IHttpEventProvider * pProvider,
|
||||
IHttpCompletionInfo * pCompletionInfo
|
||||
);
|
||||
|
||||
private:
|
||||
|
||||
FORWARDING_HANDLER * m_pHandler;
|
||||
};
|
||||
|
||||
class CProxyModuleFactory : public IHttpModuleFactory
|
||||
{
|
||||
public:
|
||||
HRESULT
|
||||
GetHttpModule(
|
||||
CHttpModule ** ppModule,
|
||||
IModuleAllocator * pAllocator
|
||||
);
|
||||
|
||||
VOID
|
||||
Terminate();
|
||||
};
|
||||
|
|
@ -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 eixt, ErrorCode = '0x%x."
|
||||
|
|
@ -0,0 +1,110 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
//
|
||||
// *_HEADER_HASH maps strings to UlHeader* values
|
||||
//
|
||||
|
||||
#define UNKNOWN_INDEX (0xFFFFFFFF)
|
||||
|
||||
struct HEADER_RECORD
|
||||
{
|
||||
PCSTR _pszName;
|
||||
ULONG _ulHeaderIndex;
|
||||
};
|
||||
|
||||
class RESPONSE_HEADER_HASH: public HASH_TABLE<HEADER_RECORD, PCSTR>
|
||||
{
|
||||
public:
|
||||
RESPONSE_HEADER_HASH()
|
||||
{}
|
||||
|
||||
VOID
|
||||
ReferenceRecord(
|
||||
HEADER_RECORD *
|
||||
)
|
||||
{}
|
||||
|
||||
VOID
|
||||
DereferenceRecord(
|
||||
HEADER_RECORD *
|
||||
)
|
||||
{}
|
||||
|
||||
PCSTR
|
||||
ExtractKey(
|
||||
HEADER_RECORD * pRecord
|
||||
)
|
||||
{
|
||||
return pRecord->_pszName;
|
||||
}
|
||||
|
||||
DWORD
|
||||
CalcKeyHash(
|
||||
PCSTR key
|
||||
)
|
||||
{
|
||||
return HashStringNoCase(key);
|
||||
}
|
||||
|
||||
BOOL
|
||||
EqualKeys(
|
||||
PCSTR key1,
|
||||
PCSTR key2
|
||||
)
|
||||
{
|
||||
return (_stricmp(key1, key2) == 0);
|
||||
}
|
||||
|
||||
HRESULT
|
||||
Initialize(
|
||||
VOID
|
||||
);
|
||||
|
||||
VOID
|
||||
Terminate(
|
||||
VOID
|
||||
);
|
||||
|
||||
DWORD
|
||||
GetIndex(
|
||||
PCSTR pszName
|
||||
)
|
||||
{
|
||||
HEADER_RECORD * pRecord = NULL;
|
||||
|
||||
FindKey(pszName, &pRecord);
|
||||
if (pRecord != NULL)
|
||||
{
|
||||
return pRecord->_ulHeaderIndex;
|
||||
}
|
||||
|
||||
return UNKNOWN_INDEX;
|
||||
}
|
||||
|
||||
static
|
||||
PCSTR
|
||||
GetString(
|
||||
ULONG ulIndex
|
||||
)
|
||||
{
|
||||
if (ulIndex < HttpHeaderResponseMaximum)
|
||||
{
|
||||
DBG_ASSERT(sm_rgHeaders[ulIndex]._ulHeaderIndex == ulIndex);
|
||||
return sm_rgHeaders[ulIndex]._pszName;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
static HEADER_RECORD sm_rgHeaders[];
|
||||
|
||||
RESPONSE_HEADER_HASH(const RESPONSE_HEADER_HASH &);
|
||||
void operator=(const RESPONSE_HEADER_HASH &);
|
||||
};
|
||||
|
||||
extern RESPONSE_HEADER_HASH * g_pResponseHeaderHash;
|
||||
|
|
@ -0,0 +1,325 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
#define MIN_PORT 1025
|
||||
#define MAX_PORT 48000
|
||||
#define MAX_RETRY 10
|
||||
#define MAX_ACTIVE_CHILD_PROCESSES 16
|
||||
#define LOCALHOST "127.0.0.1"
|
||||
#define ASPNETCORE_PORT_STR L"ASPNETCORE_PORT"
|
||||
#define ASPNETCORE_PORT_ENV_STR L"ASPNETCORE_PORT="
|
||||
#define ASPNETCORE_APP_PATH_ENV_STR L"ASPNETCORE_APPL_PATH="
|
||||
#define ASPNETCORE_APP_TOKEN_ENV_STR L"ASPNETCORE_TOKEN="
|
||||
#define ASPNETCORE_APP_PATH_ENV_STR L"ASPNETCORE_APPL_PATH="
|
||||
#define HOSTING_STARTUP_ASSEMBLIES_ENV_STR L"ASPNETCORE_HOSTINGSTARTUPASSEMBLIES"
|
||||
#define HOSTING_STARTUP_ASSEMBLIES_NAME L"ASPNETCORE_HOSTINGSTARTUPASSEMBLIES="
|
||||
#define HOSTING_STARTUP_ASSEMBLIES_VALUE L"Microsoft.AspNetCore.Server.IISIntegration"
|
||||
#define ASPNETCORE_IIS_AUTH_ENV_STR L"ASPNETCORE_IIS_HTTPAUTH="
|
||||
#define ASPNETCORE_IIS_AUTH_WINDOWS L"windows;"
|
||||
#define ASPNETCORE_IIS_AUTH_BASIC L"basic;"
|
||||
#define ASPNETCORE_IIS_AUTH_ANONYMOUS L"anonymous;"
|
||||
#define ASPNETCORE_IIS_AUTH_NONE L"none"
|
||||
|
||||
class PROCESS_MANAGER;
|
||||
class FORWARDER_CONNECTION;
|
||||
|
||||
class SERVER_PROCESS
|
||||
{
|
||||
public:
|
||||
SERVER_PROCESS();
|
||||
|
||||
HRESULT
|
||||
Initialize(
|
||||
_In_ PROCESS_MANAGER *pProcessManager,
|
||||
_In_ STRU *pszProcessExePath,
|
||||
_In_ STRU *pszArguments,
|
||||
_In_ DWORD dwStartupTimeLimitInMS,
|
||||
_In_ DWORD dwShtudownTimeLimitInMS,
|
||||
_In_ BOOL fWindowsAuthEnabled,
|
||||
_In_ BOOL fBasicAuthEnabled,
|
||||
_In_ BOOL fAnonymousAuthEnabled,
|
||||
_In_ ENVIRONMENT_VAR_HASH* pEnvironmentVariables,
|
||||
_In_ BOOL fStdoutLogEnabled,
|
||||
_In_ STRU *pstruStdoutLogFile
|
||||
);
|
||||
|
||||
|
||||
HRESULT
|
||||
StartProcess(
|
||||
_In_ IHttpContext *context
|
||||
);
|
||||
|
||||
HRESULT
|
||||
SetWindowsAuthToken(
|
||||
_In_ HANDLE hToken,
|
||||
_Out_ LPHANDLE pTargeTokenHandle
|
||||
);
|
||||
|
||||
BOOL
|
||||
IsReady(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
return m_fReady;
|
||||
}
|
||||
|
||||
VOID
|
||||
StopProcess(
|
||||
VOID
|
||||
);
|
||||
|
||||
DWORD
|
||||
GetPort()
|
||||
{
|
||||
return m_dwPort;
|
||||
}
|
||||
|
||||
VOID
|
||||
ReferenceServerProcess(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
InterlockedIncrement(&m_cRefs);
|
||||
}
|
||||
|
||||
VOID
|
||||
DereferenceServerProcess(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
_ASSERT(m_cRefs != 0 );
|
||||
|
||||
if (InterlockedDecrement(&m_cRefs) == 0)
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
}
|
||||
|
||||
virtual
|
||||
~SERVER_PROCESS();
|
||||
|
||||
HRESULT
|
||||
HandleProcessExit(
|
||||
VOID
|
||||
);
|
||||
|
||||
FORWARDER_CONNECTION*
|
||||
QueryWinHttpConnection(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
return m_pForwarderConnection;
|
||||
}
|
||||
|
||||
static
|
||||
VOID
|
||||
CALLBACK
|
||||
TimerCallback(
|
||||
_In_ PTP_CALLBACK_INSTANCE Instance,
|
||||
_In_ PVOID Context,
|
||||
_In_ PTP_TIMER Timer
|
||||
);
|
||||
|
||||
LPCWSTR
|
||||
QueryPortStr()
|
||||
{
|
||||
return m_struPort.QueryStr();
|
||||
}
|
||||
|
||||
LPCWSTR
|
||||
QueryFullLogPath()
|
||||
{
|
||||
return m_struFullLogFile.QueryStr();
|
||||
}
|
||||
|
||||
LPCSTR
|
||||
QueryGuid()
|
||||
{
|
||||
return m_straGuid.QueryStr();
|
||||
}
|
||||
|
||||
DWORD
|
||||
QueryProcessGroupId()
|
||||
{
|
||||
return m_dwProcessId;
|
||||
}
|
||||
|
||||
VOID
|
||||
SendSignal(
|
||||
VOID
|
||||
);
|
||||
|
||||
private:
|
||||
|
||||
BOOL
|
||||
IsDebuggerIsAttached(
|
||||
VOID
|
||||
);
|
||||
|
||||
HRESULT
|
||||
StopAllProcessesInJobObject(
|
||||
VOID
|
||||
);
|
||||
|
||||
HRESULT
|
||||
SetupStdHandles(
|
||||
_In_ IHttpContext *context,
|
||||
_In_ LPSTARTUPINFOW pStartupInfo
|
||||
);
|
||||
|
||||
HRESULT
|
||||
CheckIfServerIsUp(
|
||||
_In_ DWORD dwPort,
|
||||
_Out_ DWORD * pdwProcessId,
|
||||
_Out_ BOOL * pfReady
|
||||
);
|
||||
|
||||
HRESULT
|
||||
RegisterProcessWait(
|
||||
_In_ PHANDLE phWaitHandle,
|
||||
_In_ HANDLE hProcessToWaitOn
|
||||
);
|
||||
|
||||
HRESULT
|
||||
GetChildProcessHandles(
|
||||
);
|
||||
|
||||
HRESULT
|
||||
SetupListenPort(
|
||||
ENVIRONMENT_VAR_HASH *pEnvironmentVarTable
|
||||
);
|
||||
|
||||
HRESULT
|
||||
SetupAppPath(
|
||||
IHttpContext* pContext,
|
||||
ENVIRONMENT_VAR_HASH* pEnvironmentVarTable
|
||||
);
|
||||
|
||||
HRESULT
|
||||
SetupAppToken(
|
||||
ENVIRONMENT_VAR_HASH* pEnvironmentVarTable
|
||||
);
|
||||
|
||||
HRESULT
|
||||
InitEnvironmentVariablesTable(
|
||||
ENVIRONMENT_VAR_HASH** pEnvironmentVarTable
|
||||
);
|
||||
|
||||
HRESULT
|
||||
OutputEnvironmentVariables(
|
||||
MULTISZ* pmszOutput,
|
||||
ENVIRONMENT_VAR_HASH* pEnvironmentVarTable
|
||||
);
|
||||
|
||||
HRESULT
|
||||
SetupCommandLine(
|
||||
STRU* pstrCommandLine
|
||||
);
|
||||
|
||||
HRESULT
|
||||
PostStartCheck(
|
||||
const STRU* const pStruCommandline,
|
||||
STRU* pStruErrorMessage
|
||||
);
|
||||
|
||||
HRESULT
|
||||
GetRandomPort(
|
||||
DWORD* pdwPickedPort,
|
||||
DWORD dwExcludedPort
|
||||
);
|
||||
|
||||
DWORD
|
||||
GetNumberOfDigits(
|
||||
_In_ DWORD dwNumber
|
||||
)
|
||||
{
|
||||
DWORD digits = 0;
|
||||
|
||||
if( dwNumber == 0 )
|
||||
{
|
||||
digits = 1;
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
while( dwNumber > 0)
|
||||
{
|
||||
dwNumber = dwNumber / 10;
|
||||
digits ++;
|
||||
}
|
||||
Finished:
|
||||
return digits;
|
||||
}
|
||||
|
||||
static
|
||||
VOID
|
||||
SendShutDownSignal(
|
||||
LPVOID lpParam
|
||||
);
|
||||
|
||||
VOID
|
||||
SendShutDownSignalInternal(
|
||||
VOID
|
||||
);
|
||||
|
||||
HRESULT
|
||||
SendShutdownHttpMessage(
|
||||
VOID
|
||||
);
|
||||
|
||||
VOID
|
||||
TerminateBackendProcess(
|
||||
VOID
|
||||
);
|
||||
|
||||
FORWARDER_CONNECTION *m_pForwarderConnection;
|
||||
BOOL m_fStdoutLogEnabled;
|
||||
BOOL m_fWindowsAuthEnabled;
|
||||
BOOL m_fBasicAuthEnabled;
|
||||
BOOL m_fAnonymousAuthEnabled;
|
||||
|
||||
STTIMER m_Timer;
|
||||
SOCKET m_socket;
|
||||
|
||||
STRU m_struLogFile;
|
||||
STRU m_struFullLogFile;
|
||||
STRU m_ProcessPath;
|
||||
STRU m_Arguments;
|
||||
STRU m_struAppPath;
|
||||
STRU m_struAppFullPath;
|
||||
STRU m_struPort;
|
||||
STRU m_pszRootApplicationPath;
|
||||
volatile LONG m_lStopping;
|
||||
volatile BOOL m_fReady;
|
||||
mutable LONG m_cRefs;
|
||||
|
||||
DWORD m_dwPort;
|
||||
DWORD m_dwStartupTimeLimitInMS;
|
||||
DWORD m_dwShutdownTimeLimitInMS;
|
||||
DWORD m_cChildProcess;
|
||||
DWORD m_dwChildProcessIds[MAX_ACTIVE_CHILD_PROCESSES];
|
||||
DWORD m_dwProcessId;
|
||||
DWORD m_dwListeningProcessId;
|
||||
|
||||
STRA m_straGuid;
|
||||
|
||||
HANDLE m_hJobObject;
|
||||
HANDLE m_hStdoutHandle;
|
||||
//
|
||||
// m_hProcessHandle is the handle to process this object creates.
|
||||
//
|
||||
HANDLE m_hProcessHandle;
|
||||
HANDLE m_hListeningProcessHandle;
|
||||
HANDLE m_hProcessWaitHandle;
|
||||
HANDLE m_hShutdownHandle;
|
||||
//
|
||||
// m_hChildProcessHandle is the handle to process created by
|
||||
// m_hProcessHandle process if it does.
|
||||
//
|
||||
HANDLE m_hChildProcessHandles[MAX_ACTIVE_CHILD_PROCESSES];
|
||||
HANDLE m_hChildProcessWaitHandles[MAX_ACTIVE_CHILD_PROCESSES];
|
||||
|
||||
PROCESS_MANAGER *m_pProcessManager;
|
||||
ENVIRONMENT_VAR_HASH *m_pEnvironmentVarTable ;
|
||||
};
|
||||
|
|
@ -0,0 +1,243 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
#ifndef _STTIMER_H
|
||||
#define _STTIMER_H
|
||||
|
||||
class STTIMER
|
||||
{
|
||||
public:
|
||||
|
||||
STTIMER()
|
||||
: _pTimer( NULL )
|
||||
{
|
||||
fInCanel = FALSE;
|
||||
}
|
||||
|
||||
virtual
|
||||
~STTIMER()
|
||||
{
|
||||
if ( _pTimer )
|
||||
{
|
||||
CancelTimer();
|
||||
|
||||
CloseThreadpoolTimer( _pTimer );
|
||||
|
||||
_pTimer = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT
|
||||
InitializeTimer(
|
||||
PTP_TIMER_CALLBACK pfnCallback,
|
||||
VOID * pContext,
|
||||
DWORD dwInitialWait = 0,
|
||||
DWORD dwPeriod = 0
|
||||
)
|
||||
{
|
||||
_pTimer = CreateThreadpoolTimer( pfnCallback,
|
||||
pContext,
|
||||
NULL );
|
||||
|
||||
if ( !_pTimer )
|
||||
{
|
||||
return HRESULT_FROM_WIN32( GetLastError() );
|
||||
}
|
||||
|
||||
if ( dwInitialWait )
|
||||
{
|
||||
SetTimer( dwInitialWait,
|
||||
dwPeriod );
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
VOID
|
||||
SetTimer(
|
||||
DWORD dwInitialWait,
|
||||
DWORD dwPeriod = 0
|
||||
)
|
||||
{
|
||||
FILETIME ftInitialWait;
|
||||
|
||||
if ( dwInitialWait == 0 && dwPeriod == 0 )
|
||||
{
|
||||
//
|
||||
// Special case. We are preventing new callbacks
|
||||
// from being queued. Any existing callbacks in the
|
||||
// queue will still run.
|
||||
//
|
||||
// This effectively disables the timer. It can be
|
||||
// re-enabled by setting non-zero initial wait or
|
||||
// period values.
|
||||
//
|
||||
if (_pTimer != NULL)
|
||||
{
|
||||
SetThreadpoolTimer(_pTimer, NULL, 0, 0);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
InitializeRelativeFileTime( &ftInitialWait, dwInitialWait );
|
||||
|
||||
SetThreadpoolTimer( _pTimer,
|
||||
&ftInitialWait,
|
||||
dwPeriod,
|
||||
0 );
|
||||
}
|
||||
|
||||
VOID
|
||||
CancelTimer()
|
||||
{
|
||||
//
|
||||
// Disable the timer
|
||||
//
|
||||
if (fInCanel)
|
||||
return;
|
||||
|
||||
fInCanel = TRUE;
|
||||
SetTimer( 0 );
|
||||
|
||||
//
|
||||
// Wait until any callbacks queued prior to disabling
|
||||
// have completed.
|
||||
//
|
||||
if (_pTimer != NULL)
|
||||
WaitForThreadpoolTimerCallbacks( _pTimer, TRUE );
|
||||
|
||||
_pTimer = NULL;
|
||||
fInCanel = FALSE;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
VOID
|
||||
InitializeRelativeFileTime(
|
||||
FILETIME * pft,
|
||||
DWORD dwMilliseconds
|
||||
)
|
||||
{
|
||||
LARGE_INTEGER li;
|
||||
|
||||
//
|
||||
// The pftDueTime parameter expects the time to be
|
||||
// expressed as the number of 100 nanosecond intervals
|
||||
// times -1.
|
||||
//
|
||||
// To convert from milliseconds, we'll multiply by
|
||||
// -10000
|
||||
//
|
||||
|
||||
li.QuadPart = (LONGLONG)dwMilliseconds * -10000;
|
||||
|
||||
pft->dwHighDateTime = li.HighPart;
|
||||
pft->dwLowDateTime = li.LowPart;
|
||||
};
|
||||
|
||||
TP_TIMER * _pTimer;
|
||||
BOOL fInCanel;
|
||||
};
|
||||
|
||||
class STELAPSED
|
||||
{
|
||||
public:
|
||||
|
||||
STELAPSED()
|
||||
: _dwInitTime( 0 ),
|
||||
_dwInitTickCount( 0 ),
|
||||
_dwPerfCountsPerMillisecond( 0 ),
|
||||
_fUsingHighResolution( FALSE )
|
||||
{
|
||||
LARGE_INTEGER li;
|
||||
BOOL fResult;
|
||||
|
||||
_dwInitTickCount = GetTickCount64();
|
||||
|
||||
fResult = QueryPerformanceFrequency( &li );
|
||||
|
||||
if ( !fResult )
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
_dwPerfCountsPerMillisecond = li.QuadPart / 1000;
|
||||
|
||||
fResult = QueryPerformanceCounter( &li );
|
||||
|
||||
if ( !fResult )
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
_dwInitTime = li.QuadPart / _dwPerfCountsPerMillisecond;
|
||||
|
||||
_fUsingHighResolution = TRUE;
|
||||
|
||||
Finished:
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
virtual
|
||||
~STELAPSED()
|
||||
{
|
||||
}
|
||||
|
||||
LONGLONG
|
||||
QueryElapsedTime()
|
||||
{
|
||||
LARGE_INTEGER li;
|
||||
|
||||
if ( _fUsingHighResolution && QueryPerformanceCounter( &li ) )
|
||||
{
|
||||
DWORD64 dwCurrentTime = li.QuadPart / _dwPerfCountsPerMillisecond;
|
||||
|
||||
if ( dwCurrentTime < _dwInitTime )
|
||||
{
|
||||
//
|
||||
// It's theoretically possible that QueryPerformanceCounter
|
||||
// may return slightly different values on different CPUs.
|
||||
// In this case, we don't want to return an unexpected value
|
||||
// so we'll return zero. This is acceptable because
|
||||
// presumably such a case would only happen for a very short
|
||||
// time window.
|
||||
//
|
||||
// It would be possible to prevent this by ensuring processor
|
||||
// affinity for all calls to QueryPerformanceCounter, but that
|
||||
// would be undesirable in the general case because it could
|
||||
// introduce unnecessary context switches and potentially a
|
||||
// CPU bottleneck.
|
||||
//
|
||||
// Note that this issue also applies to callers doing rapid
|
||||
// calls to this function. If a caller wants to mitigate
|
||||
// that, they could enforce the affinitization, or they
|
||||
// could implement a similar sanity check when comparing
|
||||
// returned values from this function.
|
||||
//
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return dwCurrentTime - _dwInitTime;
|
||||
}
|
||||
|
||||
return GetTickCount64() - _dwInitTickCount;
|
||||
}
|
||||
|
||||
BOOL
|
||||
QueryUsingHighResolution()
|
||||
{
|
||||
return _fUsingHighResolution;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
DWORD64 _dwInitTime;
|
||||
DWORD64 _dwInitTickCount;
|
||||
DWORD64 _dwPerfCountsPerMillisecond;
|
||||
BOOL _fUsingHighResolution;
|
||||
};
|
||||
|
||||
#endif // _STTIMER_H
|
||||
|
|
@ -0,0 +1,220 @@
|
|||
// 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 FORWARDING_HANDLER;
|
||||
|
||||
class WEBSOCKET_HANDLER
|
||||
{
|
||||
public:
|
||||
WEBSOCKET_HANDLER();
|
||||
|
||||
static
|
||||
HRESULT
|
||||
StaticInitialize(
|
||||
BOOL fEnableReferenceTraceLogging
|
||||
);
|
||||
|
||||
static
|
||||
VOID
|
||||
StaticTerminate(
|
||||
VOID
|
||||
);
|
||||
|
||||
VOID
|
||||
Terminate(
|
||||
VOID
|
||||
);
|
||||
|
||||
VOID
|
||||
TerminateRequest(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
Cleanup(ServerStateUnavailable);
|
||||
}
|
||||
|
||||
HRESULT
|
||||
ProcessRequest(
|
||||
FORWARDING_HANDLER *pHandler,
|
||||
IHttpContext * pHttpContext,
|
||||
HINTERNET hRequest
|
||||
);
|
||||
|
||||
REQUEST_NOTIFICATION_STATUS
|
||||
OnAsyncCompletion(
|
||||
VOID
|
||||
);
|
||||
|
||||
HRESULT
|
||||
OnWinHttpSendComplete(
|
||||
WINHTTP_WEB_SOCKET_STATUS * pCompletionStatus
|
||||
);
|
||||
|
||||
HRESULT
|
||||
OnWinHttpShutdownComplete(
|
||||
VOID
|
||||
);
|
||||
|
||||
HRESULT
|
||||
OnWinHttpReceiveComplete(
|
||||
WINHTTP_WEB_SOCKET_STATUS * pCompletionStatus
|
||||
);
|
||||
|
||||
HRESULT
|
||||
OnWinHttpIoError(
|
||||
WINHTTP_WEB_SOCKET_ASYNC_RESULT *pCompletionStatus
|
||||
);
|
||||
|
||||
|
||||
private:
|
||||
enum CleanupReason
|
||||
{
|
||||
CleanupReasonUnknown = 0,
|
||||
IdleTimeout = 1,
|
||||
ConnectFailed = 2,
|
||||
ClientDisconnect = 3,
|
||||
ServerDisconnect = 4,
|
||||
ServerStateUnavailable = 5
|
||||
};
|
||||
|
||||
virtual
|
||||
~WEBSOCKET_HANDLER()
|
||||
{
|
||||
}
|
||||
|
||||
WEBSOCKET_HANDLER(const WEBSOCKET_HANDLER &);
|
||||
void operator=(const WEBSOCKET_HANDLER &);
|
||||
|
||||
VOID
|
||||
InsertRequest(
|
||||
VOID
|
||||
);
|
||||
|
||||
VOID
|
||||
RemoveRequest(
|
||||
VOID
|
||||
);
|
||||
|
||||
static
|
||||
VOID
|
||||
WINAPI
|
||||
OnReadIoCompletion(
|
||||
HRESULT hrError,
|
||||
VOID * pvCompletionContext,
|
||||
DWORD cbIO,
|
||||
BOOL fUTF8Encoded,
|
||||
BOOL fFinalFragment,
|
||||
BOOL fClose
|
||||
);
|
||||
|
||||
static
|
||||
VOID
|
||||
WINAPI
|
||||
OnWriteIoCompletion(
|
||||
HRESULT hrError,
|
||||
VOID * pvCompletionContext,
|
||||
DWORD cbIO,
|
||||
BOOL fUTF8Encoded,
|
||||
BOOL fFinalFragment,
|
||||
BOOL fClose
|
||||
);
|
||||
|
||||
VOID
|
||||
Cleanup(
|
||||
CleanupReason reason
|
||||
);
|
||||
|
||||
HRESULT
|
||||
DoIisWebSocketReceive(
|
||||
VOID
|
||||
);
|
||||
|
||||
HRESULT
|
||||
DoWinHttpWebSocketReceive(
|
||||
VOID
|
||||
);
|
||||
|
||||
HRESULT
|
||||
DoIisWebSocketSend(
|
||||
DWORD cbData,
|
||||
WINHTTP_WEB_SOCKET_BUFFER_TYPE eBufferType
|
||||
);
|
||||
|
||||
HRESULT
|
||||
DoWinHttpWebSocketSend(
|
||||
DWORD cbData,
|
||||
WINHTTP_WEB_SOCKET_BUFFER_TYPE eBufferType
|
||||
);
|
||||
|
||||
HRESULT
|
||||
OnIisSendComplete(
|
||||
HRESULT hrError,
|
||||
DWORD cbIO
|
||||
);
|
||||
|
||||
HRESULT
|
||||
OnIisReceiveComplete(
|
||||
HRESULT hrError,
|
||||
DWORD cbIO,
|
||||
BOOL fUTF8Encoded,
|
||||
BOOL fFinalFragment,
|
||||
BOOL fClose
|
||||
);
|
||||
|
||||
VOID
|
||||
IncrementOutstandingIo(
|
||||
VOID
|
||||
);
|
||||
|
||||
VOID
|
||||
DecrementOutstandingIo(
|
||||
VOID
|
||||
);
|
||||
|
||||
VOID
|
||||
IndicateCompletionToIIS(
|
||||
VOID
|
||||
);
|
||||
|
||||
private:
|
||||
static const
|
||||
DWORD RECEIVE_BUFFER_SIZE = 4*1024;
|
||||
|
||||
LIST_ENTRY _listEntry;
|
||||
|
||||
IHttpContext3 * _pHttpContext;
|
||||
|
||||
IWebSocketContext * _pWebSocketContext;
|
||||
|
||||
FORWARDING_HANDLER *_pHandler;
|
||||
|
||||
HINTERNET _hWebSocketRequest;
|
||||
|
||||
BYTE _WinHttpReceiveBuffer[RECEIVE_BUFFER_SIZE];
|
||||
|
||||
BYTE _IisReceiveBuffer[RECEIVE_BUFFER_SIZE];
|
||||
|
||||
CRITICAL_SECTION _RequestLock;
|
||||
|
||||
LONG _dwOutstandingIo;
|
||||
|
||||
volatile
|
||||
BOOL _fCleanupInProgress;
|
||||
|
||||
volatile
|
||||
BOOL _fIndicateCompletionToIis;
|
||||
|
||||
volatile
|
||||
BOOL _fReceivedCloseMsg;
|
||||
|
||||
static
|
||||
LIST_ENTRY sm_RequestsListHead;
|
||||
|
||||
static
|
||||
SRWLOCK sm_RequestsListLock;
|
||||
|
||||
static
|
||||
TRACE_LOG * sm_pTraceLog;
|
||||
};
|
||||
|
|
@ -0,0 +1,91 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
typedef
|
||||
HINTERNET
|
||||
(WINAPI * PFN_WINHTTP_WEBSOCKET_COMPLETE_UPGRADE)(
|
||||
_In_ HINTERNET hRequest,
|
||||
_In_opt_ DWORD_PTR pContext
|
||||
);
|
||||
|
||||
|
||||
typedef
|
||||
DWORD
|
||||
(WINAPI * PFN_WINHTTP_WEBSOCKET_SEND)(
|
||||
_In_ HINTERNET hWebSocket,
|
||||
_In_ WINHTTP_WEB_SOCKET_BUFFER_TYPE eBufferType,
|
||||
_In_reads_opt_(dwBufferLength) PVOID pvBuffer,
|
||||
_In_ DWORD dwBufferLength
|
||||
);
|
||||
|
||||
typedef
|
||||
DWORD
|
||||
(WINAPI * PFN_WINHTTP_WEBSOCKET_RECEIVE)(
|
||||
_In_ HINTERNET hWebSocket,
|
||||
_Out_writes_bytes_to_(dwBufferLength, *pdwBytesRead) PVOID pvBuffer,
|
||||
_In_ DWORD dwBufferLength,
|
||||
_Out_range_(0, dwBufferLength) DWORD *pdwBytesRead,
|
||||
_Out_ WINHTTP_WEB_SOCKET_BUFFER_TYPE *peBufferType
|
||||
);
|
||||
|
||||
typedef
|
||||
DWORD
|
||||
(WINAPI * PFN_WINHTTP_WEBSOCKET_SHUTDOWN)(
|
||||
_In_ HINTERNET hWebSocket,
|
||||
_In_ USHORT usStatus,
|
||||
_In_reads_bytes_opt_(dwReasonLength) PVOID pvReason,
|
||||
_In_range_(0, WINHTTP_WEB_SOCKET_MAX_CLOSE_REASON_LENGTH) DWORD dwReasonLength
|
||||
);
|
||||
|
||||
typedef
|
||||
DWORD
|
||||
(WINAPI * PFN_WINHTTP_WEBSOCKET_QUERY_CLOSE_STATUS)(
|
||||
_In_ HINTERNET hWebSocket,
|
||||
_Out_ USHORT *pusStatus,
|
||||
_Out_writes_bytes_to_opt_(dwReasonLength, *pdwReasonLengthConsumed) PVOID pvReason,
|
||||
_In_range_(0, WINHTTP_WEB_SOCKET_MAX_CLOSE_REASON_LENGTH) DWORD dwReasonLength,
|
||||
_Out_range_(0, WINHTTP_WEB_SOCKET_MAX_CLOSE_REASON_LENGTH) DWORD *pdwReasonLengthConsumed
|
||||
);
|
||||
|
||||
class WINHTTP_HELPER
|
||||
{
|
||||
public:
|
||||
static
|
||||
HRESULT
|
||||
StaticInitialize();
|
||||
|
||||
static
|
||||
VOID
|
||||
GetFlagsFromBufferType(
|
||||
__in WINHTTP_WEB_SOCKET_BUFFER_TYPE BufferType,
|
||||
__out BOOL * pfUtf8Encoded,
|
||||
__out BOOL * pfFinalFragment,
|
||||
__out BOOL * pfClose
|
||||
);
|
||||
|
||||
static
|
||||
VOID
|
||||
GetBufferTypeFromFlags(
|
||||
__in BOOL fUtf8Encoded,
|
||||
__in BOOL fFinalFragment,
|
||||
__in BOOL fClose,
|
||||
__out WINHTTP_WEB_SOCKET_BUFFER_TYPE* pBufferType
|
||||
);
|
||||
|
||||
static
|
||||
PFN_WINHTTP_WEBSOCKET_COMPLETE_UPGRADE sm_pfnWinHttpWebSocketCompleteUpgrade;
|
||||
|
||||
static
|
||||
PFN_WINHTTP_WEBSOCKET_SEND sm_pfnWinHttpWebSocketSend;
|
||||
|
||||
static
|
||||
PFN_WINHTTP_WEBSOCKET_RECEIVE sm_pfnWinHttpWebSocketReceive;
|
||||
|
||||
static
|
||||
PFN_WINHTTP_WEBSOCKET_SHUTDOWN sm_pfnWinHttpWebSocketShutdown;
|
||||
|
||||
static
|
||||
PFN_WINHTTP_WEBSOCKET_QUERY_CLOSE_STATUS sm_pfnWinHttpWebSocketQueryCloseStatus;
|
||||
};
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
LIBRARY aspnetcore
|
||||
|
||||
EXPORTS
|
||||
RegisterModule
|
||||
|
|
@ -0,0 +1,78 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
#include "precomp.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();
|
||||
}
|
||||
}
|
||||
|
|
@ -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"
|
||||
|
||||
APPLICATION_MANAGER* APPLICATION_MANAGER::sm_pApplicationManager = NULL;
|
||||
|
||||
HRESULT
|
||||
APPLICATION_MANAGER::GetApplication(
|
||||
_In_ IHttpContext* pContext,
|
||||
_In_ ASPNETCORE_CONFIG* pConfig,
|
||||
_Out_ APPLICATION ** ppApplication
|
||||
)
|
||||
{
|
||||
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];
|
||||
STACK_STRU ( strEventMsg, 256 );
|
||||
|
||||
*ppApplication = NULL;
|
||||
|
||||
DBG_ASSERT(pContext != NULL);
|
||||
DBG_ASSERT(pContext->GetApplication() != NULL);
|
||||
|
||||
pszApplicationId = pContext->GetApplication()->GetApplicationId();
|
||||
|
||||
hr = key.Initialize(pszApplicationId);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
m_pApplicationHash->FindKey(&key, ppApplication);
|
||||
|
||||
if (*ppApplication == NULL)
|
||||
{
|
||||
switch (pConfig->QueryHostingModel())
|
||||
{
|
||||
case HOSTING_IN_PROCESS:
|
||||
if (m_pApplicationHash->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)
|
||||
{
|
||||
hr = E_OUTOFMEMORY;
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
AcquireSRWLockExclusive(&m_srwLock);
|
||||
fExclusiveLock = TRUE;
|
||||
m_pApplicationHash->FindKey(&key, ppApplication);
|
||||
|
||||
if (*ppApplication != NULL)
|
||||
{
|
||||
// someone else created the application
|
||||
delete pApplication;
|
||||
pApplication = NULL;
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
// hosting model check. We do not allow mixed scenario for now
|
||||
// could be changed in the future
|
||||
if (m_hostingModel != HOSTING_UNKNOWN)
|
||||
{
|
||||
if (m_hostingModel != pConfig->QueryHostingModel())
|
||||
{
|
||||
// hosting model does not match, error out
|
||||
fMixedHostingModelError = TRUE;
|
||||
hr = HRESULT_FROM_WIN32(ERROR_APP_INIT_FAILURE);
|
||||
goto Finished;
|
||||
}
|
||||
}
|
||||
|
||||
hr = pApplication->Initialize(this, pConfig);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
hr = m_pApplicationHash->InsertRecord( pApplication );
|
||||
if (FAILED(hr))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
//
|
||||
// first application will decide which hosting model allowed by this process
|
||||
//
|
||||
if (m_hostingModel == HOSTING_UNKNOWN)
|
||||
{
|
||||
m_hostingModel = pConfig->QueryHostingModel();
|
||||
}
|
||||
|
||||
ReleaseSRWLockExclusive(&m_srwLock);
|
||||
fExclusiveLock = FALSE;
|
||||
|
||||
pApplication->StartMonitoringAppOffline();
|
||||
|
||||
*ppApplication = pApplication;
|
||||
pApplication = NULL;
|
||||
}
|
||||
|
||||
Finished:
|
||||
|
||||
if (fExclusiveLock)
|
||||
{
|
||||
ReleaseSRWLockExclusive(&m_srwLock);
|
||||
}
|
||||
|
||||
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();
|
||||
if (FORWARDING_HANDLER::QueryEventLog() != NULL)
|
||||
{
|
||||
ReportEventW(FORWARDING_HANDLER::QueryEventLog(),
|
||||
EVENTLOG_ERROR_TYPE,
|
||||
0,
|
||||
ASPNETCORE_EVENT_DUPLICATED_INPROCESS_APP,
|
||||
NULL,
|
||||
1,
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (SUCCEEDED(strEventMsg.SafeSnwprintf(
|
||||
ASPNETCORE_EVENT_ADD_APPLICATION_ERROR_MSG,
|
||||
pszApplicationId,
|
||||
hr)))
|
||||
{
|
||||
apsz[0] = strEventMsg.QueryStr();
|
||||
if (FORWARDING_HANDLER::QueryEventLog() != NULL)
|
||||
{
|
||||
ReportEventW(FORWARDING_HANDLER::QueryEventLog(),
|
||||
EVENTLOG_ERROR_TYPE,
|
||||
0,
|
||||
ASPNETCORE_EVENT_ADD_APPLICATION_ERROR,
|
||||
NULL,
|
||||
1,
|
||||
0,
|
||||
apsz,
|
||||
NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
APPLICATION_MANAGER::RecycleApplication(
|
||||
_In_ LPCWSTR pszApplication
|
||||
)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
APPLICATION_KEY key;
|
||||
|
||||
hr = key.Initialize(pszApplication);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
AcquireSRWLockExclusive(&m_srwLock);
|
||||
m_pApplicationHash->DeleteKey(&key);
|
||||
if (m_pApplicationHash->Count() == 0)
|
||||
{
|
||||
m_hostingModel = HOSTING_UNKNOWN;
|
||||
}
|
||||
ReleaseSRWLockExclusive(&m_srwLock);
|
||||
|
||||
Finished:
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
APPLICATION_MANAGER::Get502ErrorPage(
|
||||
_Out_ HTTP_DATA_CHUNK** ppErrorPage
|
||||
)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
BOOL fExclusiveLock = FALSE;
|
||||
HTTP_DATA_CHUNK *pHttp502ErrorPage = NULL;
|
||||
|
||||
DBG_ASSERT(ppErrorPage != NULL);
|
||||
|
||||
//on-demand create the error page
|
||||
if (m_pHttp502ErrorPage != NULL)
|
||||
{
|
||||
*ppErrorPage = m_pHttp502ErrorPage;
|
||||
}
|
||||
else
|
||||
{
|
||||
AcquireSRWLockExclusive(&m_srwLock);
|
||||
fExclusiveLock = TRUE;
|
||||
if (m_pHttp502ErrorPage != NULL)
|
||||
{
|
||||
*ppErrorPage = m_pHttp502ErrorPage;
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t maxsize = 5000;
|
||||
pHttp502ErrorPage = new HTTP_DATA_CHUNK();
|
||||
if (pHttp502ErrorPage == NULL)
|
||||
{
|
||||
hr = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
|
||||
goto Finished;
|
||||
}
|
||||
pHttp502ErrorPage->DataChunkType = HttpDataChunkFromMemory;
|
||||
pHttp502ErrorPage->FromMemory.pBuffer = (PVOID)m_pstrErrorInfo;
|
||||
|
||||
pHttp502ErrorPage->FromMemory.BufferLength = (ULONG)strnlen(m_pstrErrorInfo, maxsize); //(ULONG)(wcslen(m_pstrErrorInfo)); // *sizeof(WCHAR);
|
||||
if(m_pHttp502ErrorPage != NULL)
|
||||
{
|
||||
delete m_pHttp502ErrorPage;
|
||||
}
|
||||
m_pHttp502ErrorPage = pHttp502ErrorPage;
|
||||
*ppErrorPage = m_pHttp502ErrorPage;
|
||||
}
|
||||
}
|
||||
|
||||
Finished:
|
||||
if (fExclusiveLock)
|
||||
{
|
||||
ReleaseSRWLockExclusive(&m_srwLock);
|
||||
}
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
if (pHttp502ErrorPage != NULL)
|
||||
{
|
||||
delete pHttp502ErrorPage;
|
||||
}
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
|
@ -0,0 +1,103 @@
|
|||
;/*++
|
||||
;
|
||||
; Copyright (c) .NET Foundation. All rights reserved.
|
||||
; Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
;
|
||||
;Module Name:
|
||||
;
|
||||
; aspnetcore_msg.mc
|
||||
;
|
||||
;Abstract:
|
||||
;
|
||||
; Asp.Net Core Module localizable messages.
|
||||
;
|
||||
;--*/
|
||||
;
|
||||
;
|
||||
;#ifndef _ASPNETCORE_MSG_H_
|
||||
;#define _ASPNETCORE_MSG_H_
|
||||
;
|
||||
|
||||
SeverityNames=(Success=0x0
|
||||
Informational=0x1
|
||||
Warning=0x2
|
||||
Error=0x3
|
||||
)
|
||||
|
||||
MessageIdTypedef=DWORD
|
||||
|
||||
Messageid=1000
|
||||
SymbolicName=ASPNETCORE_EVENT_PROCESS_START_ERROR
|
||||
Language=English
|
||||
%1
|
||||
.
|
||||
|
||||
Messageid=1001
|
||||
SymbolicName=ASPNETCORE_EVENT_PROCESS_START_SUCCESS
|
||||
Language=English
|
||||
%1
|
||||
.
|
||||
|
||||
Messageid=1002
|
||||
SymbolicName=ASPNETCORE_EVENT_PROCESS_CRASH
|
||||
Language=English
|
||||
%1
|
||||
.
|
||||
|
||||
Messageid=1003
|
||||
SymbolicName=ASPNETCORE_EVENT_RAPID_FAIL_COUNT_EXCEEDED
|
||||
Language=English
|
||||
%1
|
||||
.
|
||||
|
||||
Messageid=1004
|
||||
SymbolicName=ASPNETCORE_EVENT_CONFIG_ERROR
|
||||
Language=English
|
||||
%1
|
||||
.
|
||||
|
||||
Messageid=1005
|
||||
SymbolicName=ASPNETCORE_EVENT_GRACEFUL_SHUTDOWN_FAILURE
|
||||
Language=English
|
||||
%1
|
||||
.
|
||||
|
||||
Messageid=1006
|
||||
SymbolicName=ASPNETCORE_EVENT_SENT_SHUTDOWN_HTTP_REQUEST
|
||||
Language=English
|
||||
%1
|
||||
.
|
||||
|
||||
Messageid=1007
|
||||
SymbolicName=ASPNETCORE_EVENT_LOAD_CLR_FALIURE
|
||||
Language=English
|
||||
%1
|
||||
.
|
||||
|
||||
Messageid=1008
|
||||
SymbolicName=ASPNETCORE_EVENT_DUPLICATED_INPROCESS_APP
|
||||
Language=English
|
||||
%1
|
||||
.
|
||||
|
||||
Messageid=1009
|
||||
SymbolicName=ASPNETCORE_EVENT_MIXED_HOSTING_MODEL_ERROR
|
||||
Language=English
|
||||
%1
|
||||
.
|
||||
|
||||
Messageid=1010
|
||||
SymbolicName=ASPNETCORE_EVENT_ADD_APPLICATION_ERROR
|
||||
Language=English
|
||||
%1
|
||||
.
|
||||
|
||||
Messageid=1011
|
||||
SymbolicName=ASPNETCORE_EVENT_INPROCESS_THREAD_EXIT
|
||||
Language=English
|
||||
%1
|
||||
.
|
||||
|
||||
;
|
||||
;#endif // _ASPNETCORE_MODULE_MSG_H_
|
||||
;
|
||||
|
|
@ -0,0 +1,503 @@
|
|||
// 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"
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
if (QueryHostingModel() == HOSTING_IN_PROCESS &&
|
||||
g_pHttpServer->IsCommandLineLaunch())
|
||||
{
|
||||
// IISExpress scenario, only option is to call exit in case configuration change
|
||||
// as CLR or application may change
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT
|
||||
ASPNETCORE_CONFIG::GetConfig(
|
||||
_In_ IHttpContext *pHttpContext,
|
||||
_Out_ ASPNETCORE_CONFIG **ppAspNetCoreConfig
|
||||
)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
IHttpApplication *pHttpApplication = pHttpContext->GetApplication();
|
||||
ASPNETCORE_CONFIG *pAspNetCoreConfig = NULL;
|
||||
|
||||
if (ppAspNetCoreConfig == NULL)
|
||||
{
|
||||
hr = E_INVALIDARG;
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
*ppAspNetCoreConfig = NULL;
|
||||
|
||||
// potential bug if user sepcific config at virtual dir level
|
||||
pAspNetCoreConfig = (ASPNETCORE_CONFIG*)
|
||||
pHttpApplication->GetModuleContextContainer()->GetModuleContext(g_pModuleId);
|
||||
|
||||
if (pAspNetCoreConfig != NULL)
|
||||
{
|
||||
*ppAspNetCoreConfig = pAspNetCoreConfig;
|
||||
pAspNetCoreConfig = NULL;
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
pAspNetCoreConfig = new ASPNETCORE_CONFIG;
|
||||
if (pAspNetCoreConfig == NULL)
|
||||
{
|
||||
hr = E_OUTOFMEMORY;
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
hr = pAspNetCoreConfig->Populate(pHttpContext);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
hr = pHttpApplication->GetModuleContextContainer()->
|
||||
SetModuleContext(pAspNetCoreConfig, g_pModuleId);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
if (hr == HRESULT_FROM_WIN32(ERROR_ALREADY_ASSIGNED))
|
||||
{
|
||||
delete pAspNetCoreConfig;
|
||||
|
||||
pAspNetCoreConfig = (ASPNETCORE_CONFIG*)pHttpApplication->
|
||||
GetModuleContextContainer()->
|
||||
GetModuleContext(g_pModuleId);
|
||||
|
||||
_ASSERT(pAspNetCoreConfig != NULL);
|
||||
|
||||
hr = S_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// set appliction info here instead of inside Populate()
|
||||
// as the destructor will delete the backend process
|
||||
hr = pAspNetCoreConfig->QueryApplicationPath()->Copy(pHttpApplication->GetApplicationId());
|
||||
if (FAILED(hr))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
}
|
||||
|
||||
*ppAspNetCoreConfig = pAspNetCoreConfig;
|
||||
pAspNetCoreConfig = NULL;
|
||||
|
||||
Finished:
|
||||
|
||||
if (pAspNetCoreConfig != NULL)
|
||||
{
|
||||
delete pAspNetCoreConfig;
|
||||
pAspNetCoreConfig = NULL;
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
ASPNETCORE_CONFIG::Populate(
|
||||
IHttpContext *pHttpContext
|
||||
)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
STACK_STRU(strSiteConfigPath, 256);
|
||||
STRU strEnvName;
|
||||
STRU strEnvValue;
|
||||
STRU strExpandedEnvValue;
|
||||
STRU strApplicationFullPath;
|
||||
IAppHostAdminManager *pAdminManager = NULL;
|
||||
IAppHostElement *pAspNetCoreElement = NULL;
|
||||
IAppHostElement *pWindowsAuthenticationElement = NULL;
|
||||
IAppHostElement *pBasicAuthenticationElement = NULL;
|
||||
IAppHostElement *pAnonymousAuthenticationElement = NULL;
|
||||
IAppHostElement *pEnvVarList = NULL;
|
||||
IAppHostElement *pEnvVar = NULL;
|
||||
IAppHostElementCollection *pEnvVarCollection = NULL;
|
||||
ULONGLONG ullRawTimeSpan = 0;
|
||||
ENUM_INDEX index;
|
||||
ENVIRONMENT_VAR_ENTRY* pEntry = NULL;
|
||||
DWORD dwCounter = 0;
|
||||
DWORD dwPosition = 0;
|
||||
WCHAR* pszPath = NULL;
|
||||
|
||||
m_pEnvironmentVariables = new ENVIRONMENT_VAR_HASH();
|
||||
if (m_pEnvironmentVariables == NULL)
|
||||
{
|
||||
hr = E_OUTOFMEMORY;
|
||||
goto Finished;
|
||||
}
|
||||
if (FAILED(hr = m_pEnvironmentVariables->Initialize(37 /*prime*/)))
|
||||
{
|
||||
delete m_pEnvironmentVariables;
|
||||
m_pEnvironmentVariables = NULL;
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
pAdminManager = g_pHttpServer->GetAdminManager();
|
||||
hr = strSiteConfigPath.Copy(pHttpContext->GetApplication()->GetAppConfigPath());
|
||||
if (FAILED(hr))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
hr = m_struApplicationFullPath.Copy(pHttpContext->GetApplication()->GetApplicationPhysicalPath());
|
||||
if (FAILED(hr))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
pszPath = strSiteConfigPath.QueryStr();
|
||||
while (pszPath[dwPosition] != NULL)
|
||||
{
|
||||
if (pszPath[dwPosition] == '/')
|
||||
{
|
||||
dwCounter++;
|
||||
if (dwCounter == 4)
|
||||
break;
|
||||
}
|
||||
dwPosition++;
|
||||
}
|
||||
|
||||
if (dwCounter == 4)
|
||||
{
|
||||
hr = m_struApplicationVirtualPath.Copy(pszPath + dwPosition);
|
||||
}
|
||||
else
|
||||
{
|
||||
hr = m_struApplicationVirtualPath.Copy(L"/");
|
||||
}
|
||||
|
||||
// Will setup the application virtual path.
|
||||
if (FAILED(hr))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
hr = pAdminManager->GetAdminSection(CS_WINDOWS_AUTHENTICATION_SECTION,
|
||||
strSiteConfigPath.QueryStr(),
|
||||
&pWindowsAuthenticationElement);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
// assume the corresponding authen was not enabled
|
||||
// as the section may get deleted by user in some HWC case
|
||||
// ToDo: log a warning to event log
|
||||
m_fWindowsAuthEnabled = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
hr = GetElementBoolProperty(pWindowsAuthenticationElement,
|
||||
CS_AUTHENTICATION_ENABLED,
|
||||
&m_fWindowsAuthEnabled);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
}
|
||||
|
||||
hr = pAdminManager->GetAdminSection(CS_BASIC_AUTHENTICATION_SECTION,
|
||||
strSiteConfigPath.QueryStr(),
|
||||
&pBasicAuthenticationElement);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
m_fBasicAuthEnabled = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
hr = GetElementBoolProperty(pBasicAuthenticationElement,
|
||||
CS_AUTHENTICATION_ENABLED,
|
||||
&m_fBasicAuthEnabled);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
}
|
||||
|
||||
hr = pAdminManager->GetAdminSection(CS_ANONYMOUS_AUTHENTICATION_SECTION,
|
||||
strSiteConfigPath.QueryStr(),
|
||||
&pAnonymousAuthenticationElement);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
m_fAnonymousAuthEnabled = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
hr = GetElementBoolProperty(pAnonymousAuthenticationElement,
|
||||
CS_AUTHENTICATION_ENABLED,
|
||||
&m_fAnonymousAuthEnabled);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
}
|
||||
|
||||
hr = pAdminManager->GetAdminSection(CS_ASPNETCORE_SECTION,
|
||||
strSiteConfigPath.QueryStr(),
|
||||
&pAspNetCoreElement);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
hr = GetElementStringProperty(pAspNetCoreElement,
|
||||
CS_ASPNETCORE_PROCESS_EXE_PATH,
|
||||
&m_struProcessPath);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
hr = GetElementStringProperty(pAspNetCoreElement,
|
||||
CS_ASPNETCORE_HOSTING_MODEL,
|
||||
&m_strHostingModel);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
// Swallow this error for backward compatability
|
||||
// Use default behavior for empty string
|
||||
hr = S_OK;
|
||||
}
|
||||
|
||||
if (m_strHostingModel.IsEmpty() || m_strHostingModel.Equals(L"outofprocess", TRUE))
|
||||
{
|
||||
m_hostingModel = HOSTING_OUT_PROCESS;
|
||||
}
|
||||
else if (m_strHostingModel.Equals(L"inprocess", TRUE))
|
||||
{
|
||||
m_hostingModel = HOSTING_IN_PROCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
// block unknown hosting value
|
||||
hr = HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
hr = GetElementStringProperty(pAspNetCoreElement,
|
||||
CS_ASPNETCORE_PROCESS_ARGUMENTS,
|
||||
&m_struArguments);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
hr = GetElementDWORDProperty(pAspNetCoreElement,
|
||||
CS_ASPNETCORE_RAPID_FAILS_PER_MINUTE,
|
||||
&m_dwRapidFailsPerMinute);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
//
|
||||
// rapidFailsPerMinute cannot be greater than 100.
|
||||
//
|
||||
if (m_dwRapidFailsPerMinute > MAX_RAPID_FAILS_PER_MINUTE)
|
||||
{
|
||||
m_dwRapidFailsPerMinute = MAX_RAPID_FAILS_PER_MINUTE;
|
||||
}
|
||||
|
||||
hr = GetElementDWORDProperty(pAspNetCoreElement,
|
||||
CS_ASPNETCORE_PROCESSES_PER_APPLICATION,
|
||||
&m_dwProcessesPerApplication);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
hr = GetElementDWORDProperty(
|
||||
pAspNetCoreElement,
|
||||
CS_ASPNETCORE_PROCESS_STARTUP_TIME_LIMIT,
|
||||
&m_dwStartupTimeLimitInMS
|
||||
);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
m_dwStartupTimeLimitInMS *= MILLISECONDS_IN_ONE_SECOND;
|
||||
|
||||
hr = GetElementDWORDProperty(
|
||||
pAspNetCoreElement,
|
||||
CS_ASPNETCORE_PROCESS_SHUTDOWN_TIME_LIMIT,
|
||||
&m_dwShutdownTimeLimitInMS
|
||||
);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
m_dwShutdownTimeLimitInMS *= MILLISECONDS_IN_ONE_SECOND;
|
||||
|
||||
hr = GetElementBoolProperty(pAspNetCoreElement,
|
||||
CS_ASPNETCORE_FORWARD_WINDOWS_AUTH_TOKEN,
|
||||
&m_fForwardWindowsAuthToken);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
hr = GetElementBoolProperty(pAspNetCoreElement,
|
||||
CS_ASPNETCORE_DISABLE_START_UP_ERROR_PAGE,
|
||||
&m_fDisableStartUpErrorPage);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
hr = GetElementRawTimeSpanProperty(
|
||||
pAspNetCoreElement,
|
||||
CS_ASPNETCORE_WINHTTP_REQUEST_TIMEOUT,
|
||||
&ullRawTimeSpan
|
||||
);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
m_dwRequestTimeoutInMS = (DWORD)TIMESPAN_IN_MILLISECONDS(ullRawTimeSpan);
|
||||
|
||||
hr = GetElementBoolProperty(pAspNetCoreElement,
|
||||
CS_ASPNETCORE_STDOUT_LOG_ENABLED,
|
||||
&m_fStdoutLogEnabled);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
hr = GetElementStringProperty(pAspNetCoreElement,
|
||||
CS_ASPNETCORE_STDOUT_LOG_FILE,
|
||||
&m_struStdoutLogFile);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
hr = GetElementChildByName(pAspNetCoreElement,
|
||||
CS_ASPNETCORE_ENVIRONMENT_VARIABLES,
|
||||
&pEnvVarList);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
hr = pEnvVarList->get_Collection(&pEnvVarCollection);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
for (hr = FindFirstElement(pEnvVarCollection, &index, &pEnvVar);
|
||||
SUCCEEDED(hr);
|
||||
hr = FindNextElement(pEnvVarCollection, &index, &pEnvVar))
|
||||
{
|
||||
if (hr == S_FALSE)
|
||||
{
|
||||
hr = S_OK;
|
||||
break;
|
||||
}
|
||||
|
||||
if (FAILED(hr = GetElementStringProperty(pEnvVar,
|
||||
CS_ASPNETCORE_ENVIRONMENT_VARIABLE_NAME,
|
||||
&strEnvName)) ||
|
||||
FAILED(hr = GetElementStringProperty(pEnvVar,
|
||||
CS_ASPNETCORE_ENVIRONMENT_VARIABLE_VALUE,
|
||||
&strEnvValue)) ||
|
||||
FAILED(hr = strEnvName.Append(L"=")) ||
|
||||
FAILED(hr = STRU::ExpandEnvironmentVariables(strEnvValue.QueryStr(), &strExpandedEnvValue)))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
pEntry = new ENVIRONMENT_VAR_ENTRY();
|
||||
if (pEntry == NULL)
|
||||
{
|
||||
hr = E_OUTOFMEMORY;
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
if (FAILED(hr = pEntry->Initialize(strEnvName.QueryStr(), strExpandedEnvValue.QueryStr())) ||
|
||||
FAILED(hr = m_pEnvironmentVariables->InsertRecord(pEntry)))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
strEnvName.Reset();
|
||||
strEnvValue.Reset();
|
||||
strExpandedEnvValue.Reset();
|
||||
pEnvVar->Release();
|
||||
pEnvVar = NULL;
|
||||
pEntry->Dereference();
|
||||
pEntry = NULL;
|
||||
}
|
||||
|
||||
Finished:
|
||||
|
||||
if (pAspNetCoreElement != NULL)
|
||||
{
|
||||
pAspNetCoreElement->Release();
|
||||
pAspNetCoreElement = NULL;
|
||||
}
|
||||
|
||||
if (pEnvVarList != NULL)
|
||||
{
|
||||
pEnvVarList->Release();
|
||||
pEnvVarList = NULL;
|
||||
}
|
||||
|
||||
if (pEnvVar != NULL)
|
||||
{
|
||||
pEnvVar->Release();
|
||||
pEnvVar = NULL;
|
||||
}
|
||||
|
||||
if (pEnvVarCollection != NULL)
|
||||
{
|
||||
pEnvVarCollection->Release();
|
||||
pEnvVarCollection = NULL;
|
||||
}
|
||||
|
||||
if (pEntry != NULL)
|
||||
{
|
||||
pEntry->Dereference();
|
||||
pEntry = NULL;
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
|
@ -0,0 +1,267 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
#include "precomp.hxx"
|
||||
#include <IPHlpApi.h>
|
||||
|
||||
HTTP_MODULE_ID g_pModuleId = NULL;
|
||||
IHttpServer * g_pHttpServer = NULL;
|
||||
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;
|
||||
DWORD g_dwAspNetCoreDebugFlags = 0;
|
||||
BOOL g_fNsiApiNotSupported = FALSE;
|
||||
DWORD g_dwActiveServerProcesses = 0;
|
||||
DWORD g_OptionalWinHttpFlags = 0; //specify additional WinHTTP options when using WinHttpOpenRequest API.
|
||||
|
||||
DWORD g_dwDebugFlags = 0;
|
||||
PCSTR g_szDebugLabel = "ASPNET_CORE_MODULE";
|
||||
|
||||
BOOL WINAPI DllMain(HMODULE hModule,
|
||||
DWORD ul_reason_for_call,
|
||||
LPVOID lpReserved
|
||||
)
|
||||
{
|
||||
switch (ul_reason_for_call)
|
||||
{
|
||||
case DLL_PROCESS_ATTACH:
|
||||
g_hModule = hModule;
|
||||
DisableThreadLibraryCalls(hModule);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
VOID
|
||||
LoadGlobalConfiguration(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
HKEY hKey;
|
||||
|
||||
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
||||
L"SOFTWARE\\Microsoft\\IIS Extensions\\IIS AspNetCore Module\\Parameters",
|
||||
0,
|
||||
KEY_READ,
|
||||
&hKey) == NO_ERROR)
|
||||
{
|
||||
DWORD dwType;
|
||||
DWORD dwData;
|
||||
DWORD cbData;
|
||||
|
||||
cbData = sizeof(dwData);
|
||||
if ((RegQueryValueEx(hKey,
|
||||
L"OptionalWinHttpFlags",
|
||||
NULL,
|
||||
&dwType,
|
||||
(LPBYTE)&dwData,
|
||||
&cbData) == NO_ERROR) &&
|
||||
(dwType == REG_DWORD))
|
||||
{
|
||||
g_OptionalWinHttpFlags = dwData;
|
||||
}
|
||||
|
||||
cbData = sizeof(dwData);
|
||||
if ((RegQueryValueEx(hKey,
|
||||
L"EnableReferenceCountTracing",
|
||||
NULL,
|
||||
&dwType,
|
||||
(LPBYTE)&dwData,
|
||||
&cbData) == NO_ERROR) &&
|
||||
(dwType == REG_DWORD) && (dwData == 1 || dwData == 0))
|
||||
{
|
||||
g_fEnableReferenceCountTracing = !!dwData;
|
||||
}
|
||||
|
||||
cbData = sizeof(dwData);
|
||||
if ((RegQueryValueEx(hKey,
|
||||
L"DebugFlags",
|
||||
NULL,
|
||||
&dwType,
|
||||
(LPBYTE)&dwData,
|
||||
&cbData) == NO_ERROR) &&
|
||||
(dwType == REG_DWORD))
|
||||
{
|
||||
g_dwAspNetCoreDebugFlags = dwData;
|
||||
}
|
||||
|
||||
RegCloseKey(hKey);
|
||||
}
|
||||
|
||||
DWORD dwSize = 0;
|
||||
DWORD dwResult = GetExtendedTcpTable(NULL,
|
||||
&dwSize,
|
||||
FALSE,
|
||||
AF_INET,
|
||||
TCP_TABLE_OWNER_PID_LISTENER,
|
||||
0);
|
||||
if (dwResult != NO_ERROR && dwResult != ERROR_INSUFFICIENT_BUFFER)
|
||||
{
|
||||
g_fNsiApiNotSupported = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT
|
||||
__stdcall
|
||||
RegisterModule(
|
||||
DWORD dwServerVersion,
|
||||
IHttpModuleRegistrationInfo * pModuleInfo,
|
||||
IHttpServer * pHttpServer
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine description:
|
||||
|
||||
Function called by IIS immediately after loading the module, used to let
|
||||
IIS know what notifications the module is interested in
|
||||
|
||||
Arguments:
|
||||
|
||||
dwServerVersion - IIS version the module is being loaded on
|
||||
pModuleInfo - info regarding this module
|
||||
pHttpServer - callback functions which can be used by the module at
|
||||
any point
|
||||
|
||||
Return value:
|
||||
|
||||
HRESULT
|
||||
|
||||
--*/
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
CProxyModuleFactory * pFactory = NULL;
|
||||
|
||||
#ifdef DEBUG
|
||||
CREATE_DEBUG_PRINT_OBJECT("Asp.Net Core Module");
|
||||
g_dwDebugFlags = DEBUG_FLAGS_ANY;
|
||||
#endif // DEBUG
|
||||
|
||||
CREATE_DEBUG_PRINT_OBJECT;
|
||||
|
||||
LoadGlobalConfiguration();
|
||||
|
||||
//
|
||||
// 7.0 is 0,7
|
||||
//
|
||||
if (dwServerVersion > MAKELONG(0, 7))
|
||||
{
|
||||
g_fAsyncDisconnectAvailable = TRUE;
|
||||
}
|
||||
|
||||
//
|
||||
// 8.0 is 0,8
|
||||
//
|
||||
if (dwServerVersion >= MAKELONG(0, 8))
|
||||
{
|
||||
// IISOOB:36641 Enable back WINHTTP_OPTION_ASSURED_NON_BLOCKING_CALLBACKS for Win8.
|
||||
// g_fWinHttpNonBlockingCallbackAvailable = TRUE;
|
||||
g_fWebSocketSupported = TRUE;
|
||||
}
|
||||
|
||||
hr = WINHTTP_HELPER::StaticInitialize();
|
||||
if (FAILED(hr))
|
||||
{
|
||||
if (hr == HRESULT_FROM_WIN32(ERROR_PROC_NOT_FOUND))
|
||||
{
|
||||
g_fWebSocketSupported = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
}
|
||||
|
||||
g_pModuleId = pModuleInfo->GetId();
|
||||
g_pszModuleName = pModuleInfo->GetName();
|
||||
g_pHttpServer = pHttpServer;
|
||||
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));
|
||||
|
||||
//
|
||||
// Create the factory before any static initialization.
|
||||
// The CProxyModuleFactory::Terminate method will clean any
|
||||
// static object initialized.
|
||||
//
|
||||
pFactory = new CProxyModuleFactory;
|
||||
|
||||
if (pFactory == NULL)
|
||||
{
|
||||
hr = E_OUTOFMEMORY;
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
hr = pModuleInfo->SetRequestNotifications(
|
||||
pFactory,
|
||||
RQ_EXECUTE_REQUEST_HANDLER,
|
||||
0);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
pFactory = NULL;
|
||||
|
||||
g_pResponseHeaderHash = new RESPONSE_HEADER_HASH;
|
||||
if (g_pResponseHeaderHash == NULL)
|
||||
{
|
||||
hr = E_OUTOFMEMORY;
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
hr = g_pResponseHeaderHash->Initialize();
|
||||
if (FAILED(hr))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
hr = ALLOC_CACHE_HANDLER::StaticInitialize();
|
||||
if (FAILED(hr))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
hr = FORWARDING_HANDLER::StaticInitialize(g_fEnableReferenceCountTracing);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
hr = WEBSOCKET_HANDLER::StaticInitialize(g_fEnableReferenceCountTracing);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
Finished:
|
||||
|
||||
if (pFactory != NULL)
|
||||
{
|
||||
pFactory->Terminate();
|
||||
pFactory = NULL;
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,456 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
#include "precomp.hxx"
|
||||
|
||||
FILE_WATCHER::FILE_WATCHER() :
|
||||
m_hCompletionPort(NULL),
|
||||
m_hChangeNotificationThread(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
FILE_WATCHER::~FILE_WATCHER()
|
||||
{
|
||||
if (m_hChangeNotificationThread != NULL)
|
||||
{
|
||||
CloseHandle(m_hChangeNotificationThread);
|
||||
m_hChangeNotificationThread = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT
|
||||
FILE_WATCHER::Create(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
m_hCompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE,
|
||||
NULL,
|
||||
0,
|
||||
0);
|
||||
|
||||
if (m_hCompletionPort == NULL)
|
||||
{
|
||||
hr = HRESULT_FROM_WIN32(GetLastError());
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
m_hChangeNotificationThread = CreateThread(NULL,
|
||||
0,
|
||||
ChangeNotificationThread,
|
||||
this,
|
||||
0,
|
||||
NULL);
|
||||
|
||||
if (m_hChangeNotificationThread == NULL)
|
||||
{
|
||||
hr = HRESULT_FROM_WIN32(GetLastError());
|
||||
|
||||
CloseHandle(m_hCompletionPort);
|
||||
m_hCompletionPort = NULL;
|
||||
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
Finished:
|
||||
return hr;
|
||||
}
|
||||
|
||||
DWORD
|
||||
WINAPI
|
||||
FILE_WATCHER::ChangeNotificationThread(
|
||||
LPVOID pvArg
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
IO completion thread
|
||||
|
||||
Arguments:
|
||||
|
||||
None
|
||||
|
||||
Return Value:
|
||||
|
||||
Win32 error
|
||||
|
||||
--*/
|
||||
{
|
||||
FILE_WATCHER * pFileMonitor;
|
||||
BOOL fSuccess = FALSE;
|
||||
DWORD cbCompletion = 0;
|
||||
OVERLAPPED * pOverlapped = NULL;
|
||||
DWORD dwErrorStatus;
|
||||
ULONG_PTR completionKey;
|
||||
|
||||
pFileMonitor = (FILE_WATCHER*)pvArg;
|
||||
DBG_ASSERT(pFileMonitor != NULL);
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
fSuccess = GetQueuedCompletionStatus(
|
||||
pFileMonitor->m_hCompletionPort,
|
||||
&cbCompletion,
|
||||
&completionKey,
|
||||
&pOverlapped,
|
||||
INFINITE);
|
||||
|
||||
DBG_ASSERT(fSuccess);
|
||||
DebugPrint(1, "FILE_WATCHER::ChangeNotificationThread");
|
||||
dwErrorStatus = fSuccess ? ERROR_SUCCESS : GetLastError();
|
||||
|
||||
if (completionKey == FILE_WATCHER_SHUTDOWN_KEY)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
DBG_ASSERT(pOverlapped != NULL);
|
||||
if (pOverlapped != NULL)
|
||||
{
|
||||
FileWatcherCompletionRoutine(
|
||||
dwErrorStatus,
|
||||
cbCompletion,
|
||||
pOverlapped);
|
||||
}
|
||||
pOverlapped = NULL;
|
||||
cbCompletion = 0;
|
||||
}
|
||||
}
|
||||
|
||||
VOID
|
||||
WINAPI
|
||||
FILE_WATCHER::FileWatcherCompletionRoutine(
|
||||
DWORD dwCompletionStatus,
|
||||
DWORD cbCompletion,
|
||||
OVERLAPPED * pOverlapped
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Called when ReadDirectoryChangesW() completes
|
||||
|
||||
Arguments:
|
||||
|
||||
dwCompletionStatus - Error of completion
|
||||
cbCompletion - Bytes of completion
|
||||
pOverlapped - State of completion
|
||||
|
||||
Return Value:
|
||||
|
||||
None
|
||||
|
||||
--*/
|
||||
{
|
||||
FILE_WATCHER_ENTRY * pMonitorEntry;
|
||||
pMonitorEntry = CONTAINING_RECORD(pOverlapped, FILE_WATCHER_ENTRY, _overlapped);
|
||||
pMonitorEntry->DereferenceFileWatcherEntry();
|
||||
DBG_ASSERT(pMonitorEntry != NULL);
|
||||
|
||||
pMonitorEntry->HandleChangeCompletion(dwCompletionStatus, cbCompletion);
|
||||
|
||||
if (pMonitorEntry->QueryIsValid())
|
||||
{
|
||||
//
|
||||
// Continue monitoring
|
||||
//
|
||||
pMonitorEntry->Monitor();
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
// Marked by application distructor
|
||||
// Deference the entry to delete it
|
||||
//
|
||||
pMonitorEntry->DereferenceFileWatcherEntry();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FILE_WATCHER_ENTRY::FILE_WATCHER_ENTRY(FILE_WATCHER * pFileMonitor) :
|
||||
_pFileMonitor(pFileMonitor),
|
||||
_hDirectory(INVALID_HANDLE_VALUE),
|
||||
_hImpersonationToken(NULL),
|
||||
_pApplication(NULL),
|
||||
_lStopMonitorCalled(0),
|
||||
_cRefs(1),
|
||||
_fIsValid(TRUE)
|
||||
{
|
||||
_dwSignature = FILE_WATCHER_ENTRY_SIGNATURE;
|
||||
InitializeSRWLock(&_srwLock);
|
||||
}
|
||||
|
||||
FILE_WATCHER_ENTRY::~FILE_WATCHER_ENTRY()
|
||||
{
|
||||
_dwSignature = FILE_WATCHER_ENTRY_SIGNATURE_FREE;
|
||||
|
||||
if (_hDirectory != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
CloseHandle(_hDirectory);
|
||||
_hDirectory = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
if (_hImpersonationToken != NULL)
|
||||
{
|
||||
CloseHandle(_hImpersonationToken);
|
||||
_hImpersonationToken = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma warning(disable:4100)
|
||||
|
||||
HRESULT
|
||||
FILE_WATCHER_ENTRY::HandleChangeCompletion(
|
||||
_In_ DWORD dwCompletionStatus,
|
||||
_In_ DWORD cbCompletion
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Handle change notification (see if any of associated config files
|
||||
need to be flushed)
|
||||
|
||||
Arguments:
|
||||
|
||||
dwCompletionStatus - Completion status
|
||||
cbCompletion - Bytes of completion
|
||||
|
||||
Return Value:
|
||||
|
||||
HRESULT
|
||||
|
||||
--*/
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
FILE_NOTIFY_INFORMATION * pNotificationInfo;
|
||||
BOOL fFileChanged = FALSE;
|
||||
|
||||
AcquireSRWLockExclusive(&_srwLock);
|
||||
if (!_fIsValid)
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
// When directory handle is closed then HandleChangeCompletion
|
||||
// happens with cbCompletion = 0 and dwCompletionStatus = 0
|
||||
// From documentation it is not clear if that combination
|
||||
// of return values is specific to closing handles or whether
|
||||
// it could also mean an error condition. Hence we will maintain
|
||||
// explicit flag that will help us determine if entry
|
||||
// is being shutdown (StopMonitor() called)
|
||||
//
|
||||
if (_lStopMonitorCalled)
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
//
|
||||
// There could be a FCN overflow
|
||||
// Let assume the file got changed instead of checking files
|
||||
// Othersie we have to cache the file info
|
||||
//
|
||||
if (cbCompletion == 0)
|
||||
{
|
||||
fFileChanged = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
pNotificationInfo = (FILE_NOTIFY_INFORMATION*)_buffDirectoryChanges.QueryPtr();
|
||||
DBG_ASSERT(pNotificationInfo != NULL);
|
||||
|
||||
while (pNotificationInfo != NULL)
|
||||
{
|
||||
//
|
||||
// check whether the monitored file got changed
|
||||
//
|
||||
if (_wcsnicmp(pNotificationInfo->FileName,
|
||||
_strFileName.QueryStr(),
|
||||
pNotificationInfo->FileNameLength/sizeof(WCHAR)) == 0)
|
||||
{
|
||||
fFileChanged = TRUE;
|
||||
break;
|
||||
}
|
||||
//
|
||||
// Advance to next notification
|
||||
//
|
||||
if (pNotificationInfo->NextEntryOffset == 0)
|
||||
{
|
||||
pNotificationInfo = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
pNotificationInfo = (FILE_NOTIFY_INFORMATION*)
|
||||
((PBYTE)pNotificationInfo +
|
||||
pNotificationInfo->NextEntryOffset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (fFileChanged)
|
||||
{
|
||||
//
|
||||
// so far we only monitoring app_offline
|
||||
//
|
||||
_pApplication->UpdateAppOfflineFileHandle();
|
||||
}
|
||||
|
||||
Finished:
|
||||
ReleaseSRWLockExclusive(&_srwLock);
|
||||
return hr;
|
||||
}
|
||||
|
||||
#pragma warning( error : 4100 )
|
||||
|
||||
HRESULT
|
||||
FILE_WATCHER_ENTRY::Monitor(VOID)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
DWORD cbRead;
|
||||
|
||||
AcquireSRWLockExclusive(&_srwLock);
|
||||
ReferenceFileWatcherEntry();
|
||||
ZeroMemory(&_overlapped, sizeof(_overlapped));
|
||||
|
||||
if(!ReadDirectoryChangesW(_hDirectory,
|
||||
_buffDirectoryChanges.QueryPtr(),
|
||||
_buffDirectoryChanges.QuerySize(),
|
||||
FALSE, // Watching sub dirs. Set to False now as only monitoring app_offline
|
||||
FILE_NOTIFY_VALID_MASK & ~FILE_NOTIFY_CHANGE_LAST_ACCESS,
|
||||
&cbRead,
|
||||
&_overlapped,
|
||||
NULL))
|
||||
{
|
||||
hr = HRESULT_FROM_WIN32(GetLastError());
|
||||
}
|
||||
|
||||
ReleaseSRWLockExclusive(&_srwLock);
|
||||
return hr;
|
||||
}
|
||||
|
||||
VOID
|
||||
FILE_WATCHER_ENTRY::StopMonitor(VOID)
|
||||
{
|
||||
//
|
||||
// Flag that monitoring is being stopped so that
|
||||
// we know that HandleChangeCompletion() call
|
||||
// can be ignored
|
||||
//
|
||||
InterlockedExchange(&_lStopMonitorCalled, 1);
|
||||
|
||||
AcquireSRWLockExclusive(&_srwLock);
|
||||
|
||||
if (_hDirectory != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
CloseHandle(_hDirectory);
|
||||
_hDirectory = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
ReleaseSRWLockExclusive(&_srwLock);
|
||||
}
|
||||
|
||||
HRESULT
|
||||
FILE_WATCHER_ENTRY::Create(
|
||||
_In_ PCWSTR pszDirectoryToMonitor,
|
||||
_In_ PCWSTR pszFileNameToMonitor,
|
||||
_In_ APPLICATION* pApplication,
|
||||
_In_ HANDLE hImpersonationToken
|
||||
)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
BOOL fRet = FALSE;
|
||||
|
||||
if (pszDirectoryToMonitor == NULL ||
|
||||
pszFileNameToMonitor == NULL ||
|
||||
pApplication == NULL)
|
||||
{
|
||||
DBG_ASSERT(FALSE);
|
||||
hr = HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
//
|
||||
//remember the application
|
||||
//
|
||||
_pApplication = pApplication;
|
||||
|
||||
if (FAILED(hr = _strFileName.Copy(pszFileNameToMonitor)))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
if (FAILED(hr = _strDirectoryName.Copy(pszDirectoryToMonitor)))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
//
|
||||
// Resize change buffer to something "reasonable"
|
||||
//
|
||||
if (!_buffDirectoryChanges.Resize(FILE_WATCHER_ENTRY_BUFFER_SIZE))
|
||||
{
|
||||
hr = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
if (hImpersonationToken != NULL)
|
||||
{
|
||||
fRet = DuplicateHandle(GetCurrentProcess(),
|
||||
hImpersonationToken,
|
||||
GetCurrentProcess(),
|
||||
&_hImpersonationToken,
|
||||
0,
|
||||
FALSE,
|
||||
DUPLICATE_SAME_ACCESS);
|
||||
|
||||
if (!fRet)
|
||||
{
|
||||
hr = HRESULT_FROM_WIN32(GetLastError());
|
||||
goto Finished;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_hImpersonationToken != NULL)
|
||||
{
|
||||
CloseHandle(_hImpersonationToken);
|
||||
_hImpersonationToken = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
_hDirectory = CreateFileW(
|
||||
_strDirectoryName.QueryStr(),
|
||||
FILE_LIST_DIRECTORY,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED,
|
||||
NULL);
|
||||
|
||||
if (_hDirectory == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
hr = HRESULT_FROM_WIN32(GetLastError());
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
if (CreateIoCompletionPort(
|
||||
_hDirectory,
|
||||
_pFileMonitor->QueryCompletionPort(),
|
||||
NULL,
|
||||
0) == NULL)
|
||||
{
|
||||
hr = HRESULT_FROM_WIN32(GetLastError());
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
//
|
||||
// Start monitoring
|
||||
//
|
||||
hr = Monitor();
|
||||
|
||||
Finished:
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
#include "precomp.hxx"
|
||||
|
||||
FORWARDER_CONNECTION::FORWARDER_CONNECTION(
|
||||
VOID
|
||||
) : m_cRefs (1),
|
||||
m_hConnection (NULL)
|
||||
{
|
||||
}
|
||||
|
||||
HRESULT
|
||||
FORWARDER_CONNECTION::Initialize(
|
||||
DWORD dwPort
|
||||
)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
hr = m_ConnectionKey.Initialize( dwPort );
|
||||
if ( FAILED( hr ) )
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
m_hConnection = WinHttpConnect(FORWARDING_HANDLER::sm_hSession,
|
||||
L"127.0.0.1",
|
||||
(USHORT) dwPort,
|
||||
0);
|
||||
if (m_hConnection == NULL)
|
||||
{
|
||||
hr = HRESULT_FROM_WIN32(GetLastError());
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
//
|
||||
// Since WinHttp will not emit WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING
|
||||
// when closing WebSocket handle on Win8. Register callback at Connect level as a workaround
|
||||
//
|
||||
if (WinHttpSetStatusCallback(m_hConnection,
|
||||
FORWARDING_HANDLER::OnWinHttpCompletion,
|
||||
WINHTTP_CALLBACK_FLAG_HANDLES,
|
||||
NULL) == WINHTTP_INVALID_STATUS_CALLBACK)
|
||||
{
|
||||
hr = HRESULT_FROM_WIN32(GetLastError());
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
Finished:
|
||||
|
||||
return hr;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,195 @@
|
|||
// 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 <cassert>
|
||||
#include <sstream>
|
||||
#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;
|
||||
}
|
||||
|
|
@ -0,0 +1,686 @@
|
|||
// 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 <algorithm>
|
||||
|
||||
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<std::wstring> *pvFolders
|
||||
)
|
||||
{
|
||||
HANDLE handle = NULL;
|
||||
WIN32_FIND_DATAW data = { 0 };
|
||||
|
||||
handle = FindFirstFileExW(pszPath, FindExInfoStandard, &data, FindExSearchNameMatch, NULL, 0);
|
||||
if (handle == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
std::wstring folder(data.cFileName);
|
||||
pvFolders->push_back(folder);
|
||||
} while (FindNextFileW(handle, &data));
|
||||
|
||||
FindClose(handle);
|
||||
}
|
||||
|
||||
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<std::wstring> 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<std::wstring> vFolders,
|
||||
_Out_ STRU *pstrResult
|
||||
)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
fx_ver_t max_ver(-1, -1, -1);
|
||||
for (const auto& dir : vFolders)
|
||||
{
|
||||
fx_ver_t fx_ver(-1, -1, -1);
|
||||
if (fx_ver_t::parse(dir, &fx_ver, false))
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
|
@ -0,0 +1,113 @@
|
|||
// 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
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1,415 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
#include "precomp.hxx"
|
||||
|
||||
//
|
||||
// Initialization export
|
||||
//
|
||||
EXTERN_C __MIDL_DECLSPEC_DLLEXPORT
|
||||
VOID
|
||||
register_callbacks(
|
||||
_In_ PFN_REQUEST_HANDLER request_handler,
|
||||
_In_ PFN_SHUTDOWN_HANDLER shutdown_handler,
|
||||
_In_ PFN_MANAGED_CONTEXT_HANDLER async_completion_handler,
|
||||
_In_ VOID* pvRequstHandlerContext,
|
||||
_In_ VOID* pvShutdownHandlerContext
|
||||
)
|
||||
{
|
||||
IN_PROCESS_APPLICATION::GetInstance()->SetCallbackHandles(
|
||||
request_handler,
|
||||
shutdown_handler,
|
||||
async_completion_handler,
|
||||
pvRequstHandlerContext,
|
||||
pvShutdownHandlerContext
|
||||
);
|
||||
}
|
||||
|
||||
EXTERN_C __MIDL_DECLSPEC_DLLEXPORT
|
||||
HTTP_REQUEST*
|
||||
http_get_raw_request(
|
||||
_In_ IHttpContext* pHttpContext
|
||||
)
|
||||
{
|
||||
return pHttpContext->GetRequest()->GetRawHttpRequest();
|
||||
}
|
||||
|
||||
EXTERN_C __MIDL_DECLSPEC_DLLEXPORT
|
||||
HTTP_RESPONSE*
|
||||
http_get_raw_response(
|
||||
_In_ IHttpContext* pHttpContext
|
||||
)
|
||||
{
|
||||
return pHttpContext->GetResponse()->GetRawHttpResponse();
|
||||
}
|
||||
|
||||
EXTERN_C __MIDL_DECLSPEC_DLLEXPORT VOID http_set_response_status_code(
|
||||
_In_ IHttpContext* pHttpContext,
|
||||
_In_ USHORT statusCode,
|
||||
_In_ PCSTR pszReason
|
||||
)
|
||||
{
|
||||
pHttpContext->GetResponse()->SetStatus(statusCode, pszReason);
|
||||
}
|
||||
|
||||
EXTERN_C __MIDL_DECLSPEC_DLLEXPORT
|
||||
HRESULT
|
||||
http_post_completion(
|
||||
_In_ IHttpContext* pHttpContext,
|
||||
DWORD cbBytes
|
||||
)
|
||||
{
|
||||
return pHttpContext->PostCompletion(cbBytes);
|
||||
}
|
||||
|
||||
EXTERN_C __MIDL_DECLSPEC_DLLEXPORT
|
||||
HRESULT
|
||||
http_set_completion_status(
|
||||
_In_ IHttpContext* pHttpContext,
|
||||
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);
|
||||
return hr;
|
||||
}
|
||||
|
||||
EXTERN_C __MIDL_DECLSPEC_DLLEXPORT
|
||||
HRESULT
|
||||
http_set_managed_context(
|
||||
_In_ IHttpContext* pHttpContext,
|
||||
_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;
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
EXTERN_C __MIDL_DECLSPEC_DLLEXPORT
|
||||
VOID
|
||||
http_indicate_completion(
|
||||
_In_ IHttpContext* pHttpContext,
|
||||
_In_ REQUEST_NOTIFICATION_STATUS notificationStatus
|
||||
)
|
||||
{
|
||||
pHttpContext->IndicateCompletion(notificationStatus);
|
||||
}
|
||||
|
||||
EXTERN_C __MIDL_DECLSPEC_DLLEXPORT
|
||||
VOID
|
||||
http_get_completion_info(
|
||||
_In_ IHttpCompletionInfo2* info,
|
||||
_Out_ DWORD* cbBytes,
|
||||
_Out_ HRESULT* hr
|
||||
)
|
||||
{
|
||||
*cbBytes = info->GetCompletionBytes();
|
||||
*hr = info->GetCompletionStatus();
|
||||
}
|
||||
|
||||
//
|
||||
// todo: we should not rely on IN_PROCESS_APPLICATION::GetInstance()
|
||||
// the signature should be changed. application's based address should be passed in
|
||||
//
|
||||
|
||||
struct IISConfigurationData
|
||||
{
|
||||
BSTR pwzFullApplicationPath;
|
||||
BSTR pwzVirtualApplicationPath;
|
||||
BOOL fWindowsAuthEnabled;
|
||||
BOOL fBasicAuthEnabled;
|
||||
BOOL fAnonymousAuthEnable;
|
||||
};
|
||||
|
||||
EXTERN_C __MIDL_DECLSPEC_DLLEXPORT
|
||||
HRESULT // TODO probably should make this a wide string
|
||||
http_get_application_properties(
|
||||
_In_ IISConfigurationData* pIISCofigurationData
|
||||
)
|
||||
{
|
||||
ASPNETCORE_CONFIG* pConfiguration = NULL;
|
||||
IN_PROCESS_APPLICATION* pApplication = IN_PROCESS_APPLICATION::GetInstance();
|
||||
|
||||
if (pApplication == NULL)
|
||||
{
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
pConfiguration = pApplication->QueryConfig();
|
||||
|
||||
pIISCofigurationData->pwzFullApplicationPath = SysAllocString(pConfiguration->QueryApplicationFullPath()->QueryStr());
|
||||
pIISCofigurationData->pwzVirtualApplicationPath = SysAllocString(pConfiguration->QueryApplicationVirtualPath()->QueryStr());
|
||||
pIISCofigurationData->fWindowsAuthEnabled = pConfiguration->QueryWindowsAuthEnabled();
|
||||
pIISCofigurationData->fBasicAuthEnabled = pConfiguration->QueryBasicAuthEnabled();
|
||||
pIISCofigurationData->fAnonymousAuthEnable = pConfiguration->QueryAnonymousAuthEnabled();
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
EXTERN_C __MIDL_DECLSPEC_DLLEXPORT
|
||||
HRESULT
|
||||
http_read_request_bytes(
|
||||
_In_ IHttpContext* pHttpContext,
|
||||
_Out_ CHAR* pvBuffer,
|
||||
_In_ DWORD dwCbBuffer,
|
||||
_Out_ DWORD* pdwBytesReceived,
|
||||
_Out_ BOOL* pfCompletionPending
|
||||
)
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
if (pHttpContext == NULL)
|
||||
{
|
||||
return E_FAIL;
|
||||
}
|
||||
if (dwCbBuffer == 0)
|
||||
{
|
||||
return E_FAIL;
|
||||
}
|
||||
IHttpRequest *pHttpRequest = (IHttpRequest*)pHttpContext->GetRequest();
|
||||
|
||||
BOOL fAsync = TRUE;
|
||||
|
||||
hr = pHttpRequest->ReadEntityBody(
|
||||
pvBuffer,
|
||||
dwCbBuffer,
|
||||
fAsync,
|
||||
pdwBytesReceived,
|
||||
pfCompletionPending);
|
||||
|
||||
if (hr == HRESULT_FROM_WIN32(ERROR_HANDLE_EOF))
|
||||
{
|
||||
// We reached the end of the data
|
||||
hr = S_OK;
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
EXTERN_C __MIDL_DECLSPEC_DLLEXPORT
|
||||
HRESULT
|
||||
http_write_response_bytes(
|
||||
_In_ IHttpContext* pHttpContext,
|
||||
_In_ HTTP_DATA_CHUNK* pDataChunks,
|
||||
_In_ DWORD dwChunks,
|
||||
_In_ BOOL* pfCompletionExpected
|
||||
)
|
||||
{
|
||||
IHttpResponse *pHttpResponse = (IHttpResponse*)pHttpContext->GetResponse();
|
||||
BOOL fAsync = TRUE;
|
||||
BOOL fMoreData = TRUE;
|
||||
DWORD dwBytesSent = 0;
|
||||
|
||||
HRESULT hr = pHttpResponse->WriteEntityChunks(
|
||||
pDataChunks,
|
||||
dwChunks,
|
||||
fAsync,
|
||||
fMoreData,
|
||||
&dwBytesSent,
|
||||
pfCompletionExpected);
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
EXTERN_C __MIDL_DECLSPEC_DLLEXPORT
|
||||
HRESULT
|
||||
http_flush_response_bytes(
|
||||
_In_ IHttpContext* pHttpContext,
|
||||
_Out_ BOOL* pfCompletionExpected
|
||||
)
|
||||
{
|
||||
IHttpResponse *pHttpResponse = (IHttpResponse*)pHttpContext->GetResponse();
|
||||
|
||||
BOOL fAsync = TRUE;
|
||||
BOOL fMoreData = TRUE;
|
||||
DWORD dwBytesSent = 0;
|
||||
|
||||
HRESULT hr = pHttpResponse->Flush(
|
||||
fAsync,
|
||||
fMoreData,
|
||||
&dwBytesSent,
|
||||
pfCompletionExpected);
|
||||
return hr;
|
||||
}
|
||||
|
||||
EXTERN_C __MIDL_DECLSPEC_DLLEXPORT
|
||||
HRESULT
|
||||
http_websockets_read_bytes(
|
||||
_In_ IHttpContext* pHttpContext,
|
||||
_In_ CHAR* pvBuffer,
|
||||
_In_ DWORD cbBuffer,
|
||||
_In_ PFN_ASYNC_COMPLETION pfnCompletionCallback,
|
||||
_In_ VOID* pvCompletionContext,
|
||||
_In_ DWORD* pDwBytesReceived,
|
||||
_In_ BOOL* pfCompletionPending
|
||||
)
|
||||
{
|
||||
IHttpRequest3 *pHttpRequest = (IHttpRequest3*)pHttpContext->GetRequest();
|
||||
|
||||
BOOL fAsync = TRUE;
|
||||
|
||||
HRESULT hr = pHttpRequest->ReadEntityBody(
|
||||
pvBuffer,
|
||||
cbBuffer,
|
||||
fAsync,
|
||||
pfnCompletionCallback,
|
||||
pvCompletionContext,
|
||||
pDwBytesReceived,
|
||||
pfCompletionPending);
|
||||
|
||||
if (hr == HRESULT_FROM_WIN32(ERROR_HANDLE_EOF))
|
||||
{
|
||||
// We reached the end of the data
|
||||
hr = S_OK;
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
EXTERN_C __MIDL_DECLSPEC_DLLEXPORT
|
||||
HRESULT
|
||||
http_websockets_write_bytes(
|
||||
_In_ IHttpContext* pHttpContext,
|
||||
_In_ HTTP_DATA_CHUNK* pDataChunks,
|
||||
_In_ DWORD dwChunks,
|
||||
_In_ PFN_ASYNC_COMPLETION pfnCompletionCallback,
|
||||
_In_ VOID* pvCompletionContext,
|
||||
_In_ BOOL* pfCompletionExpected
|
||||
)
|
||||
{
|
||||
IHttpResponse2 *pHttpResponse = (IHttpResponse2*)pHttpContext->GetResponse();
|
||||
|
||||
BOOL fAsync = TRUE;
|
||||
BOOL fMoreData = TRUE;
|
||||
DWORD dwBytesSent;
|
||||
|
||||
HRESULT hr = pHttpResponse->WriteEntityChunks(
|
||||
pDataChunks,
|
||||
dwChunks,
|
||||
fAsync,
|
||||
fMoreData,
|
||||
pfnCompletionCallback,
|
||||
pvCompletionContext,
|
||||
&dwBytesSent,
|
||||
pfCompletionExpected);
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
EXTERN_C __MIDL_DECLSPEC_DLLEXPORT
|
||||
HRESULT
|
||||
http_websockets_flush_bytes(
|
||||
_In_ IHttpContext* pHttpContext,
|
||||
_In_ PFN_ASYNC_COMPLETION pfnCompletionCallback,
|
||||
_In_ VOID* pvCompletionContext,
|
||||
_In_ BOOL* pfCompletionExpected
|
||||
)
|
||||
{
|
||||
IHttpResponse2 *pHttpResponse = (IHttpResponse2*)pHttpContext->GetResponse();
|
||||
|
||||
BOOL fAsync = TRUE;
|
||||
BOOL fMoreData = TRUE;
|
||||
DWORD dwBytesSent;
|
||||
|
||||
HRESULT hr = pHttpResponse->Flush(
|
||||
fAsync,
|
||||
fMoreData,
|
||||
pfnCompletionCallback,
|
||||
pvCompletionContext,
|
||||
&dwBytesSent,
|
||||
pfCompletionExpected);
|
||||
return hr;
|
||||
}
|
||||
|
||||
EXTERN_C __MIDL_DECLSPEC_DLLEXPORT
|
||||
HRESULT
|
||||
http_enable_websockets(
|
||||
_In_ IHttpContext* pHttpContext
|
||||
)
|
||||
{
|
||||
if (!g_fWebSocketSupported)
|
||||
{
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
((IHttpContext3*)pHttpContext)->EnableFullDuplex();
|
||||
((IHttpResponse2*)pHttpContext->GetResponse())->DisableBuffering();
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
EXTERN_C __MIDL_DECLSPEC_DLLEXPORT
|
||||
HRESULT
|
||||
http_cancel_io(
|
||||
_In_ IHttpContext* pHttpContext
|
||||
)
|
||||
{
|
||||
return pHttpContext->CancelIo();
|
||||
}
|
||||
|
||||
EXTERN_C __MIDL_DECLSPEC_DLLEXPORT
|
||||
HRESULT
|
||||
http_response_set_unknown_header(
|
||||
_In_ IHttpContext* pHttpContext,
|
||||
_In_ PCSTR pszHeaderName,
|
||||
_In_ PCSTR pszHeaderValue,
|
||||
_In_ USHORT usHeaderValueLength,
|
||||
_In_ BOOL fReplace
|
||||
)
|
||||
{
|
||||
return pHttpContext->GetResponse()->SetHeader( pszHeaderName, pszHeaderValue, usHeaderValueLength, fReplace );
|
||||
}
|
||||
|
||||
EXTERN_C __MIDL_DECLSPEC_DLLEXPORT
|
||||
HRESULT
|
||||
http_response_set_known_header(
|
||||
_In_ IHttpContext* pHttpContext,
|
||||
_In_ HTTP_HEADER_ID dwHeaderId,
|
||||
_In_ PCSTR pszHeaderValue,
|
||||
_In_ USHORT usHeaderValueLength,
|
||||
_In_ BOOL fReplace
|
||||
)
|
||||
{
|
||||
return pHttpContext->GetResponse()->SetHeader( dwHeaderId, pszHeaderValue, usHeaderValueLength, fReplace );
|
||||
}
|
||||
|
||||
EXTERN_C __MIDL_DECLSPEC_DLLEXPORT
|
||||
HRESULT
|
||||
http_get_authentication_information(
|
||||
_In_ IHttpContext* pHttpContext,
|
||||
_Out_ BSTR* pstrAuthType,
|
||||
_Out_ VOID** pvToken
|
||||
)
|
||||
{
|
||||
*pstrAuthType = SysAllocString(pHttpContext->GetUser()->GetAuthenticationType());
|
||||
*pvToken = pHttpContext->GetUser()->GetPrimaryToken();
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
// End of export
|
||||
|
|
@ -0,0 +1,121 @@
|
|||
// 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;
|
||||
}
|
||||
|
|
@ -0,0 +1,442 @@
|
|||
// 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"
|
||||
|
||||
// static
|
||||
HRESULT
|
||||
PATH::SplitUrl(
|
||||
PCWSTR pszDestinationUrl,
|
||||
BOOL *pfSecure,
|
||||
STRU *pstrDestination,
|
||||
STRU *pstrUrl
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Split the URL specified for forwarding into its specific components
|
||||
The format of the URL looks like
|
||||
http[s]://destination[:port]/path
|
||||
when port is omitted, the default port for that specific protocol is used
|
||||
when host is omitted, it gets the same value as the destination
|
||||
|
||||
Arguments:
|
||||
|
||||
pszDestinationUrl - the url to be split up
|
||||
pfSecure - SSL to be used in forwarding?
|
||||
pstrDestination - destination
|
||||
pDestinationPort - port
|
||||
pstrUrl - URL
|
||||
|
||||
Return Value:
|
||||
|
||||
HRESULT
|
||||
|
||||
--*/
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
//
|
||||
// First determine if the target is secure
|
||||
//
|
||||
if (_wcsnicmp(pszDestinationUrl, L"http://", 7) == 0)
|
||||
{
|
||||
*pfSecure = FALSE;
|
||||
pszDestinationUrl += 7;
|
||||
}
|
||||
else if (_wcsnicmp(pszDestinationUrl, L"https://", 8) == 0)
|
||||
{
|
||||
*pfSecure = TRUE;
|
||||
pszDestinationUrl += 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
return HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
|
||||
}
|
||||
|
||||
if (*pszDestinationUrl == L'\0')
|
||||
{
|
||||
return HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
|
||||
}
|
||||
|
||||
//
|
||||
// Find the 3rd slash corresponding to the url
|
||||
//
|
||||
LPCWSTR pszSlash = wcschr(pszDestinationUrl, L'/');
|
||||
if (pszSlash == NULL)
|
||||
{
|
||||
if (FAILED(hr = pstrUrl->Copy(L"/", 1)) ||
|
||||
FAILED(hr = pstrDestination->Copy(pszDestinationUrl)))
|
||||
{
|
||||
return hr;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (FAILED(hr = pstrUrl->Copy(pszSlash)) ||
|
||||
FAILED(hr = pstrDestination->Copy(pszDestinationUrl,
|
||||
(DWORD)(pszSlash - pszDestinationUrl))))
|
||||
{
|
||||
return hr;
|
||||
}
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
// Change a hexadecimal digit to its numerical equivalent
|
||||
#define TOHEX( ch ) \
|
||||
((ch) > L'9' ? \
|
||||
(ch) >= L'a' ? \
|
||||
(ch) - L'a' + 10 : \
|
||||
(ch) - L'A' + 10 \
|
||||
: (ch) - L'0')
|
||||
|
||||
// static
|
||||
HRESULT
|
||||
PATH::UnEscapeUrl(
|
||||
PCWSTR pszUrl,
|
||||
DWORD cchUrl,
|
||||
bool fCopyQuery,
|
||||
STRA * pstrResult
|
||||
)
|
||||
{
|
||||
HRESULT hr;
|
||||
CHAR pch[2];
|
||||
pch[1] = '\0';
|
||||
DWORD cchStart = 0;
|
||||
DWORD index = 0;
|
||||
|
||||
while (index < cchUrl &&
|
||||
(fCopyQuery || pszUrl[index] != L'?'))
|
||||
{
|
||||
switch (pszUrl[index])
|
||||
{
|
||||
case L'%':
|
||||
if (iswxdigit(pszUrl[index+1]) && iswxdigit(pszUrl[index+2]))
|
||||
{
|
||||
if (index > cchStart &&
|
||||
FAILED(hr = pstrResult->AppendW(pszUrl + cchStart,
|
||||
index - cchStart)))
|
||||
{
|
||||
return hr;
|
||||
}
|
||||
cchStart = index+3;
|
||||
|
||||
pch[0] = static_cast<CHAR>(TOHEX(pszUrl[index+1]) * 16 +
|
||||
TOHEX(pszUrl[index+2]));
|
||||
if (FAILED(hr = pstrResult->Append(pch, 1)))
|
||||
{
|
||||
return hr;
|
||||
}
|
||||
index += 3;
|
||||
break;
|
||||
}
|
||||
|
||||
__fallthrough;
|
||||
default:
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
if (index > cchStart)
|
||||
{
|
||||
return pstrResult->AppendW(pszUrl + cchStart,
|
||||
index - cchStart);
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
// static
|
||||
HRESULT
|
||||
PATH::UnEscapeUrl(
|
||||
PCWSTR pszUrl,
|
||||
DWORD cchUrl,
|
||||
STRU * pstrResult
|
||||
)
|
||||
{
|
||||
HRESULT hr;
|
||||
WCHAR pch[2];
|
||||
pch[1] = L'\0';
|
||||
DWORD cchStart = 0;
|
||||
DWORD index = 0;
|
||||
bool fInQuery = FALSE;
|
||||
|
||||
while (index < cchUrl)
|
||||
{
|
||||
switch (pszUrl[index])
|
||||
{
|
||||
case L'%':
|
||||
if (iswxdigit(pszUrl[index+1]) && iswxdigit(pszUrl[index+2]))
|
||||
{
|
||||
if (index > cchStart &&
|
||||
FAILED(hr = pstrResult->Append(pszUrl + cchStart,
|
||||
index - cchStart)))
|
||||
{
|
||||
return hr;
|
||||
}
|
||||
cchStart = index+3;
|
||||
|
||||
pch[0] = static_cast<WCHAR>(TOHEX(pszUrl[index+1]) * 16 +
|
||||
TOHEX(pszUrl[index+2]));
|
||||
if (FAILED(hr = pstrResult->Append(pch, 1)))
|
||||
{
|
||||
return hr;
|
||||
}
|
||||
index += 3;
|
||||
if (pch[0] == L'?')
|
||||
{
|
||||
fInQuery = TRUE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
index++;
|
||||
break;
|
||||
|
||||
case L'/':
|
||||
if (fInQuery)
|
||||
{
|
||||
if (index > cchStart &&
|
||||
FAILED(hr = pstrResult->Append(pszUrl + cchStart,
|
||||
index - cchStart)))
|
||||
{
|
||||
return hr;
|
||||
}
|
||||
cchStart = index+1;
|
||||
|
||||
if (FAILED(hr = pstrResult->Append(L"\\", 1)))
|
||||
{
|
||||
return hr;
|
||||
}
|
||||
index += 1;
|
||||
break;
|
||||
}
|
||||
|
||||
__fallthrough;
|
||||
default:
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
if (index > cchStart)
|
||||
{
|
||||
return pstrResult->Append(pszUrl + cchStart,
|
||||
index - cchStart);
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
PATH::EscapeAbsPath(
|
||||
IHttpRequest * pRequest,
|
||||
STRU * strEscapedUrl
|
||||
)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
STRU strAbsPath;
|
||||
LPCWSTR pszAbsPath = NULL;
|
||||
LPCWSTR pszFindStr = NULL;
|
||||
|
||||
hr = strAbsPath.Copy( pRequest->GetRawHttpRequest()->CookedUrl.pAbsPath,
|
||||
pRequest->GetRawHttpRequest()->CookedUrl.AbsPathLength / sizeof(WCHAR) );
|
||||
if(FAILED(hr))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
pszAbsPath = strAbsPath.QueryStr();
|
||||
pszFindStr = wcschr(pszAbsPath, L'?');
|
||||
|
||||
while(pszFindStr != NULL)
|
||||
{
|
||||
strEscapedUrl->Append( pszAbsPath, pszFindStr - pszAbsPath);
|
||||
strEscapedUrl->Append(L"%3F");
|
||||
pszAbsPath = pszFindStr + 1;
|
||||
pszFindStr = wcschr(pszAbsPath, L'?');
|
||||
}
|
||||
|
||||
strEscapedUrl->Append(pszAbsPath);
|
||||
strEscapedUrl->Append(pRequest->GetRawHttpRequest()->CookedUrl.pQueryString,
|
||||
pRequest->GetRawHttpRequest()->CookedUrl.QueryStringLength / sizeof(WCHAR));
|
||||
|
||||
Finished:
|
||||
return hr;
|
||||
}
|
||||
|
||||
// static
|
||||
bool
|
||||
PATH::IsValidAttributeNameChar(
|
||||
WCHAR ch
|
||||
)
|
||||
{
|
||||
//
|
||||
// Values based on ASP.NET rendering for cookie names. RFC 2965 is not clear
|
||||
// what the non-special characters are.
|
||||
//
|
||||
return ch == L'\t' || (ch > 31 && ch < 127);
|
||||
}
|
||||
|
||||
// static
|
||||
bool
|
||||
PATH::FindInMultiString(
|
||||
PCWSTR pszMultiString,
|
||||
PCWSTR pszStringToFind
|
||||
)
|
||||
{
|
||||
while (*pszMultiString != L'\0')
|
||||
{
|
||||
if (wcscmp(pszMultiString, pszStringToFind) == 0)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
pszMultiString += wcslen(pszMultiString) + 1;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// static
|
||||
bool
|
||||
PATH::IsValidQueryStringName(
|
||||
PCWSTR pszName
|
||||
)
|
||||
{
|
||||
while (*pszName != L'\0')
|
||||
{
|
||||
WCHAR c = *pszName;
|
||||
if (c != L'-' && c != L'_' && c != L'+' &&
|
||||
c != L'.' && c != L'*' && c != L'$' && c != L'%' && c != L',' &&
|
||||
!iswalnum(c))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
pszName++;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// static
|
||||
bool
|
||||
PATH::IsValidHeaderName(
|
||||
PCWSTR pszName
|
||||
)
|
||||
{
|
||||
while (*pszName != L'\0')
|
||||
{
|
||||
WCHAR c = *pszName;
|
||||
if (c != L'-' && c != L'_' && c != L'+' &&
|
||||
c != L'.' && c != L'*' && c != L'$' && c != L'%'
|
||||
&& !iswalnum(c))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
pszName++;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
PATH::IsPathUnc(
|
||||
__in LPCWSTR pszPath,
|
||||
__out BOOL * pfIsUnc
|
||||
)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
STRU strTempPath;
|
||||
|
||||
if ( pszPath == NULL || pfIsUnc == NULL )
|
||||
{
|
||||
hr = E_INVALIDARG;
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
hr = MakePathCanonicalizationProof( (LPWSTR) pszPath, &strTempPath );
|
||||
if ( FAILED(hr) )
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
//
|
||||
// MakePathCanonicalizationProof will map \\?\UNC, \\.\UNC and \\ to \\?\UNC
|
||||
//
|
||||
(*pfIsUnc) = ( _wcsnicmp( strTempPath.QueryStr(), L"\\\\?\\UNC\\", 8 /* sizeof \\?\UNC\ */) == 0 );
|
||||
|
||||
Finished:
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
PATH::ConvertPathToFullPath(
|
||||
_In_ LPCWSTR pszPath,
|
||||
_In_ LPCWSTR pszRootPath,
|
||||
_Out_ STRU* pStruFullPath
|
||||
)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
STRU strFileFullPath;
|
||||
LPWSTR pszFullPath = NULL;
|
||||
|
||||
// if relative path, prefix with root path and then convert to absolute path.
|
||||
if( pszPath[0] == L'.' )
|
||||
{
|
||||
hr = strFileFullPath.Copy(pszRootPath);
|
||||
if(FAILED(hr))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
if(!strFileFullPath.EndsWith(L"\\"))
|
||||
{
|
||||
hr = strFileFullPath.Append(L"\\");
|
||||
if(FAILED(hr))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hr = strFileFullPath.Append( pszPath );
|
||||
if(FAILED(hr))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
pszFullPath = new WCHAR[ strFileFullPath.QueryCCH() + 1];
|
||||
if( pszFullPath == NULL )
|
||||
{
|
||||
hr = E_OUTOFMEMORY;
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
if(_wfullpath( pszFullPath,
|
||||
strFileFullPath.QueryStr(),
|
||||
strFileFullPath.QueryCCH() + 1 ) == NULL )
|
||||
{
|
||||
hr = HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
// convert to canonical path
|
||||
hr = MakePathCanonicalizationProof( pszFullPath, pStruFullPath );
|
||||
if(FAILED(hr))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
Finished:
|
||||
|
||||
if( pszFullPath != NULL )
|
||||
{
|
||||
delete[] pszFullPath;
|
||||
pszFullPath = NULL;
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
|
@ -0,0 +1,168 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
#pragma once
|
||||
#pragma warning( disable : 4091)
|
||||
|
||||
//
|
||||
// System related headers
|
||||
//
|
||||
#define _WINSOCKAPI_
|
||||
|
||||
#define NTDDI_VERSION 0x06010000
|
||||
#define WINVER 0x0601
|
||||
#define _WIN32_WINNT 0x0601
|
||||
|
||||
#include <windows.h>
|
||||
#include <atlbase.h>
|
||||
#include <pdh.h>
|
||||
|
||||
//#include <ntassert.h>
|
||||
#include <Shlobj.h>
|
||||
#include <httpserv.h>
|
||||
|
||||
// This should remove our issue of compiling for win7 without header files.
|
||||
// We force the Windows 8 version check logic in iiswebsocket.h to succeed even though we're compiling for Windows 7.
|
||||
// Then, we set the version defines back to Windows 7 to for the remainder of the compilation.
|
||||
#undef NTDDI_VERSION
|
||||
#undef WINVER
|
||||
#undef _WIN32_WINNT
|
||||
#define NTDDI_VERSION 0x06020000
|
||||
#define WINVER 0x0602
|
||||
#define _WIN32_WINNT 0x0602
|
||||
#include <iiswebsocket.h>
|
||||
#undef NTDDI_VERSION
|
||||
#undef WINVER
|
||||
#undef _WIN32_WINNT
|
||||
|
||||
#define NTDDI_VERSION 0x06010000
|
||||
#define WINVER 0x0601
|
||||
#define _WIN32_WINNT 0x0601
|
||||
|
||||
#include <httptrace.h>
|
||||
#include <winhttp.h>
|
||||
|
||||
#include <cstdlib>
|
||||
#include <vector>
|
||||
#include <wchar.h>
|
||||
|
||||
//
|
||||
// Option available starting Windows 8.
|
||||
// 111 is the value in SDK on May 15, 2012.
|
||||
//
|
||||
#ifndef WINHTTP_OPTION_ASSURED_NON_BLOCKING_CALLBACKS
|
||||
#define WINHTTP_OPTION_ASSURED_NON_BLOCKING_CALLBACKS 111
|
||||
#endif
|
||||
|
||||
#define ASPNETCORE_EVENT_PROVIDER L"IIS AspNetCore Module"
|
||||
#define ASPNETCORE_IISEXPRESS_EVENT_PROVIDER L"IIS Express AspNetCore Module"
|
||||
|
||||
#define TIMESPAN_IN_MILLISECONDS(x) ((x)/((LONGLONG)(10000)))
|
||||
#define TIMESPAN_IN_SECONDS(x) ((TIMESPAN_IN_MILLISECONDS(x))/((LONGLONG)(1000)))
|
||||
#define TIMESPAN_IN_MINUTES(x) ((TIMESPAN_IN_SECONDS(x))/((LONGLONG)(60)))
|
||||
|
||||
#ifdef max
|
||||
#undef max
|
||||
template<typename T> inline T max(T a, T b)
|
||||
{
|
||||
return a > b ? a : b;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef min
|
||||
#undef min
|
||||
template<typename T> inline T min(T a, T b)
|
||||
{
|
||||
return a < b ? a : b;
|
||||
}
|
||||
#endif
|
||||
|
||||
inline bool IsSpace(char ch)
|
||||
{
|
||||
switch(ch)
|
||||
{
|
||||
case 32: // ' '
|
||||
case 9: // '\t'
|
||||
case 10: // '\n'
|
||||
case 13: // '\r'
|
||||
case 11: // '\v'
|
||||
case 12: // '\f'
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
#include <hashfn.h>
|
||||
#include <hashtable.h>
|
||||
#include "stringa.h"
|
||||
#include "stringu.h"
|
||||
//#include "treehash.h"
|
||||
|
||||
#include "dbgutil.h"
|
||||
#include "ahutil.h"
|
||||
#include "multisz.h"
|
||||
#include "multisza.h"
|
||||
#include "base64.h"
|
||||
#include "sttimer.h"
|
||||
#include <listentry.h>
|
||||
#include <datetime.h>
|
||||
#include <reftrace.h>
|
||||
#include <acache.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "environmentvariablehash.h"
|
||||
#include "..\aspnetcore_msg.h"
|
||||
#include "aspnetcore_event.h"
|
||||
#include "aspnetcoreconfig.h"
|
||||
#include "serverprocess.h"
|
||||
#include "processmanager.h"
|
||||
#include "filewatcher.h"
|
||||
#include "application.h"
|
||||
#include "applicationmanager.h"
|
||||
#include "inprocessstoredcontext.h"
|
||||
#include "inprocessapplication.h"
|
||||
#include "outprocessapplication.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
|
||||
WIN32_FROM_HRESULT(
|
||||
HRESULT hr
|
||||
)
|
||||
{
|
||||
if ((FAILED(hr)) &&
|
||||
(HRESULT_FACILITY(hr) == FACILITY_WIN32))
|
||||
{
|
||||
return HRESULT_CODE(hr);
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
FORCEINLINE
|
||||
HRESULT
|
||||
HRESULT_FROM_GETLASTERROR()
|
||||
{
|
||||
return ( GetLastError() != NO_ERROR )
|
||||
? HRESULT_FROM_WIN32( GetLastError() )
|
||||
: E_FAIL;
|
||||
}
|
||||
|
||||
extern BOOL g_fAsyncDisconnectAvailable;
|
||||
extern BOOL g_fWinHttpNonBlockingCallbackAvailable;
|
||||
extern PVOID g_pModuleId;
|
||||
extern BOOL g_fWebSocketSupported;
|
||||
extern BOOL g_fEnableReferenceCountTracing;
|
||||
extern DWORD g_dwActiveServerProcesses;
|
||||
extern DWORD g_OptionalWinHttpFlags;
|
||||
#pragma warning( error : 4091)
|
||||
|
|
@ -0,0 +1,294 @@
|
|||
// 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;i<m_dwProcessesPerApplication;++i)
|
||||
{
|
||||
m_ppServerProcessList[i] = NULL;
|
||||
}
|
||||
}
|
||||
m_fServerProcessListReady = TRUE;
|
||||
ReleaseSRWLockExclusive( &m_srwLock );
|
||||
fExclusiveLock = FALSE;
|
||||
}
|
||||
|
||||
AcquireSRWLockShared( &m_srwLock );
|
||||
fSharedLock = TRUE;
|
||||
|
||||
//
|
||||
// round robin through to the next available process.
|
||||
//
|
||||
|
||||
dwProcessIndex = (DWORD) InterlockedIncrement64( (LONGLONG*) &m_dwRouteToProcessIndex );
|
||||
dwProcessIndex = dwProcessIndex % m_dwProcessesPerApplication;
|
||||
ppSelectedServerProcess = &m_ppServerProcessList[dwProcessIndex];
|
||||
|
||||
if( *ppSelectedServerProcess != NULL &&
|
||||
m_ppServerProcessList[dwProcessIndex]->IsReady() )
|
||||
{
|
||||
m_ppServerProcessList[dwProcessIndex]->ReferenceServerProcess();
|
||||
*ppServerProcess = m_ppServerProcessList[dwProcessIndex];
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
ReleaseSRWLockShared( &m_srwLock );
|
||||
fSharedLock = FALSE;
|
||||
// should make the lock per process so that we can start processes simultaneously ?
|
||||
|
||||
if(m_ppServerProcessList[dwProcessIndex] == NULL || !m_ppServerProcessList[dwProcessIndex]->IsReady())
|
||||
{
|
||||
AcquireSRWLockExclusive( &m_srwLock );
|
||||
fExclusiveLock = TRUE;
|
||||
|
||||
if( m_ppServerProcessList[dwProcessIndex] != NULL )
|
||||
{
|
||||
if( !m_ppServerProcessList[dwProcessIndex]->IsReady() )
|
||||
{
|
||||
//
|
||||
// terminate existing process that is not ready
|
||||
// before creating new one.
|
||||
//
|
||||
|
||||
ShutdownProcessNoLock( m_ppServerProcessList[dwProcessIndex] );
|
||||
}
|
||||
else
|
||||
{
|
||||
// server is already up and ready to serve requests.
|
||||
m_ppServerProcessList[dwProcessIndex]->ReferenceServerProcess();
|
||||
*ppServerProcess = m_ppServerProcessList[dwProcessIndex];
|
||||
goto Finished;
|
||||
}
|
||||
}
|
||||
|
||||
if( RapidFailsPerMinuteExceeded(pConfig->QueryRapidFailsPerMinute()) )
|
||||
{
|
||||
//
|
||||
// rapid fails per minute exceeded, do not create new process.
|
||||
//
|
||||
|
||||
if( SUCCEEDED( strEventMsg.SafeSnwprintf(
|
||||
ASPNETCORE_EVENT_RAPID_FAIL_COUNT_EXCEEDED_MSG,
|
||||
pConfig->QueryRapidFailsPerMinute() ) ) )
|
||||
{
|
||||
apsz[0] = strEventMsg.QueryStr();
|
||||
|
||||
//
|
||||
// not checking return code because if ReportEvent
|
||||
// fails, we cannot do anything.
|
||||
//
|
||||
if (FORWARDING_HANDLER::QueryEventLog() != NULL)
|
||||
{
|
||||
ReportEventW(FORWARDING_HANDLER::QueryEventLog(),
|
||||
EVENTLOG_INFORMATION_TYPE,
|
||||
0,
|
||||
ASPNETCORE_EVENT_RAPID_FAIL_COUNT_EXCEEDED,
|
||||
NULL,
|
||||
1,
|
||||
0,
|
||||
apsz,
|
||||
NULL);
|
||||
}
|
||||
}
|
||||
|
||||
hr = HRESULT_FROM_WIN32(ERROR_SERVER_DISABLED);
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
if( m_ppServerProcessList[dwProcessIndex] == NULL )
|
||||
{
|
||||
m_ppServerProcessList[dwProcessIndex] = new SERVER_PROCESS();
|
||||
if( m_ppServerProcessList[dwProcessIndex] == NULL )
|
||||
{
|
||||
hr = E_OUTOFMEMORY;
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
hr = m_ppServerProcessList[dwProcessIndex]->Initialize(
|
||||
this,
|
||||
pConfig->QueryProcessPath(),
|
||||
pConfig->QueryArguments(),
|
||||
pConfig->QueryStartupTimeLimitInMS(),
|
||||
pConfig->QueryShutdownTimeLimitInMS(),
|
||||
pConfig->QueryWindowsAuthEnabled(),
|
||||
pConfig->QueryBasicAuthEnabled(),
|
||||
pConfig->QueryAnonymousAuthEnabled(),
|
||||
pConfig->QueryEnvironmentVariables(),
|
||||
pConfig->QueryStdoutLogEnabled(),
|
||||
pConfig->QueryStdoutLogFile()
|
||||
);
|
||||
if( FAILED( hr ) )
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
hr = m_ppServerProcessList[dwProcessIndex]->StartProcess(context);
|
||||
if( FAILED( hr ) )
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
}
|
||||
|
||||
if( !m_ppServerProcessList[dwProcessIndex]->IsReady() )
|
||||
{
|
||||
hr = HRESULT_FROM_WIN32( ERROR_CREATE_FAILED );
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
m_ppServerProcessList[dwProcessIndex]->ReferenceServerProcess();
|
||||
*ppServerProcess = m_ppServerProcessList[dwProcessIndex];
|
||||
}
|
||||
|
||||
Finished:
|
||||
|
||||
if( FAILED(hr) )
|
||||
{
|
||||
if(m_ppServerProcessList[dwProcessIndex] != NULL )
|
||||
{
|
||||
m_ppServerProcessList[dwProcessIndex]->DereferenceServerProcess();
|
||||
m_ppServerProcessList[dwProcessIndex] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if( fSharedLock )
|
||||
{
|
||||
ReleaseSRWLockShared( &m_srwLock );
|
||||
fSharedLock = FALSE;
|
||||
}
|
||||
|
||||
if( fExclusiveLock )
|
||||
{
|
||||
ReleaseSRWLockExclusive( &m_srwLock );
|
||||
fExclusiveLock = FALSE;
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
#include "precomp.hxx"
|
||||
|
||||
HRESULT
|
||||
PROTOCOL_CONFIG::Initialize()
|
||||
{
|
||||
HRESULT hr;
|
||||
STRU strTemp;
|
||||
|
||||
m_fKeepAlive = TRUE;
|
||||
m_msTimeout = 120000;
|
||||
m_fPreserveHostHeader = TRUE;
|
||||
m_fReverseRewriteHeaders = FALSE;
|
||||
|
||||
if (FAILED(hr = m_strXForwardedForName.CopyW(L"X-Forwarded-For")))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
if (FAILED(hr = m_strSslHeaderName.CopyW(L"X-Forwarded-Proto")))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
if (FAILED(hr = m_strClientCertName.CopyW(L"MS-ASPNETCORE-CLIENTCERT")))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
m_fIncludePortInXForwardedFor = TRUE;
|
||||
m_dwMinResponseBuffer = 0; // no response buffering
|
||||
m_dwResponseBufferLimit = 4096*1024;
|
||||
m_dwMaxResponseHeaderSize = 65536;
|
||||
|
||||
Finished:
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
VOID
|
||||
PROTOCOL_CONFIG::OverrideConfig(
|
||||
ASPNETCORE_CONFIG *pAspNetCoreConfig
|
||||
)
|
||||
{
|
||||
m_msTimeout = pAspNetCoreConfig->QueryRequestTimeoutInMS();
|
||||
}
|
||||
|
|
@ -0,0 +1,135 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
#include "precomp.hxx"
|
||||
|
||||
__override
|
||||
HRESULT
|
||||
CProxyModuleFactory::GetHttpModule(
|
||||
CHttpModule ** ppModule,
|
||||
IModuleAllocator * pAllocator
|
||||
)
|
||||
{
|
||||
CProxyModule *pModule = new (pAllocator) CProxyModule();
|
||||
if (pModule == NULL)
|
||||
{
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
|
||||
*ppModule = pModule;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
__override
|
||||
VOID
|
||||
CProxyModuleFactory::Terminate(
|
||||
VOID
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine description:
|
||||
|
||||
Function called by IIS for global (non-request-specific) notifications
|
||||
|
||||
Arguments:
|
||||
|
||||
None.
|
||||
|
||||
Return value:
|
||||
|
||||
None
|
||||
|
||||
--*/
|
||||
{
|
||||
FORWARDING_HANDLER::StaticTerminate();
|
||||
|
||||
WEBSOCKET_HANDLER::StaticTerminate();
|
||||
|
||||
if (g_pResponseHeaderHash != NULL)
|
||||
{
|
||||
g_pResponseHeaderHash->Clear();
|
||||
delete g_pResponseHeaderHash;
|
||||
g_pResponseHeaderHash = NULL;
|
||||
}
|
||||
|
||||
ALLOC_CACHE_HANDLER::StaticTerminate();
|
||||
|
||||
delete this;
|
||||
}
|
||||
|
||||
CProxyModule::CProxyModule(
|
||||
) : m_pHandler(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
CProxyModule::~CProxyModule()
|
||||
{
|
||||
if (m_pHandler != NULL)
|
||||
{
|
||||
m_pHandler->DereferenceForwardingHandler();
|
||||
m_pHandler = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
__override
|
||||
REQUEST_NOTIFICATION_STATUS
|
||||
CProxyModule::OnExecuteRequestHandler(
|
||||
IHttpContext * pHttpContext,
|
||||
IHttpEventProvider *
|
||||
)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
ASPNETCORE_CONFIG *pConfig = NULL;
|
||||
APPLICATION_MANAGER *pApplicationManager = NULL;
|
||||
APPLICATION *pApplication = NULL;
|
||||
hr = ASPNETCORE_CONFIG::GetConfig(pHttpContext, &pConfig);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
goto Failed;
|
||||
}
|
||||
|
||||
pApplicationManager = APPLICATION_MANAGER::GetInstance();
|
||||
if (pApplicationManager == NULL)
|
||||
{
|
||||
hr = E_OUTOFMEMORY;
|
||||
goto Failed;
|
||||
}
|
||||
|
||||
hr = pApplicationManager->GetApplication(
|
||||
pHttpContext,
|
||||
pConfig,
|
||||
&pApplication);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
goto Failed;
|
||||
}
|
||||
|
||||
m_pHandler = new FORWARDING_HANDLER(pHttpContext, pApplication);
|
||||
|
||||
if (m_pHandler == NULL)
|
||||
{
|
||||
hr = E_OUTOFMEMORY;
|
||||
goto Failed;
|
||||
}
|
||||
|
||||
return m_pHandler->OnExecuteRequestHandler();
|
||||
|
||||
Failed:
|
||||
pHttpContext->GetResponse()->SetStatus(500, "Internal Server Error", 0, hr);
|
||||
return REQUEST_NOTIFICATION_STATUS::RQ_NOTIFICATION_FINISH_REQUEST;
|
||||
}
|
||||
|
||||
__override
|
||||
REQUEST_NOTIFICATION_STATUS
|
||||
CProxyModule::OnAsyncCompletion(
|
||||
IHttpContext *,
|
||||
DWORD,
|
||||
BOOL,
|
||||
IHttpEventProvider *,
|
||||
IHttpCompletionInfo * pCompletionInfo
|
||||
)
|
||||
{
|
||||
return m_pHandler->OnAsyncCompletion(
|
||||
pCompletionInfo->GetCompletionBytes(),
|
||||
pCompletionInfo->GetCompletionStatus());
|
||||
}
|
||||
|
|
@ -0,0 +1,100 @@
|
|||
// 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;
|
||||
|
||||
HEADER_RECORD RESPONSE_HEADER_HASH::sm_rgHeaders[] =
|
||||
{
|
||||
{ "Cache-Control", HttpHeaderCacheControl },
|
||||
{ "Connection", HttpHeaderConnection },
|
||||
{ "Date", HttpHeaderDate },
|
||||
{ "Keep-Alive", HttpHeaderKeepAlive },
|
||||
{ "Pragma", HttpHeaderPragma },
|
||||
{ "Trailer", HttpHeaderTrailer },
|
||||
{ "Transfer-Encoding", HttpHeaderTransferEncoding },
|
||||
{ "Upgrade", HttpHeaderUpgrade },
|
||||
{ "Via", HttpHeaderVia },
|
||||
{ "Warning", HttpHeaderWarning },
|
||||
{ "Allow", HttpHeaderAllow },
|
||||
{ "Content-Length", HttpHeaderContentLength },
|
||||
{ "Content-Type", HttpHeaderContentType },
|
||||
{ "Content-Encoding", HttpHeaderContentEncoding },
|
||||
{ "Content-Language", HttpHeaderContentLanguage },
|
||||
{ "Content-Location", HttpHeaderContentLocation },
|
||||
{ "Content-MD5", HttpHeaderContentMd5 },
|
||||
{ "Content-Range", HttpHeaderContentRange },
|
||||
{ "Expires", HttpHeaderExpires },
|
||||
{ "Last-Modified", HttpHeaderLastModified },
|
||||
{ "Accept-Ranges", HttpHeaderAcceptRanges },
|
||||
{ "Age", HttpHeaderAge },
|
||||
{ "ETag", HttpHeaderEtag },
|
||||
{ "Location", HttpHeaderLocation },
|
||||
{ "Proxy-Authenticate", HttpHeaderProxyAuthenticate },
|
||||
{ "Retry-After", HttpHeaderRetryAfter },
|
||||
{ "Server", HttpHeaderServer },
|
||||
// Set it to something which cannot be a header name, in effect
|
||||
// making Server an unknown header. w:w is used to avoid collision with Keep-Alive.
|
||||
{ "w:w\r\n", HttpHeaderServer },
|
||||
// Set it to something which cannot be a header name, in effect
|
||||
// making Set-Cookie an unknown header
|
||||
{ "y:y\r\n", HttpHeaderSetCookie },
|
||||
{ "Vary", HttpHeaderVary },
|
||||
// Set it to something which cannot be a header name, in effect
|
||||
// making WWW-Authenticate an unknown header
|
||||
{ "z:z\r\n", HttpHeaderWwwAuthenticate }
|
||||
|
||||
};
|
||||
|
||||
HRESULT
|
||||
RESPONSE_HEADER_HASH::Initialize(
|
||||
VOID
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Initialize global header hash table
|
||||
|
||||
Arguments:
|
||||
|
||||
None
|
||||
|
||||
Return Value:
|
||||
|
||||
HRESULT
|
||||
|
||||
--*/
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
//
|
||||
// 31 response headers.
|
||||
// Make sure to update the number of buckets it new headers
|
||||
// are added. Test it to avoid collisions.
|
||||
//
|
||||
C_ASSERT(_countof(sm_rgHeaders) == 31);
|
||||
|
||||
//
|
||||
// 79 buckets will have less collisions for the 31 response headers.
|
||||
// Known collisions are "Age" colliding with "Expire" and "Location"
|
||||
// colliding with both "Expire" and "Age".
|
||||
//
|
||||
hr = HASH_TABLE::Initialize(79);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
return hr;
|
||||
}
|
||||
|
||||
for ( DWORD Index = 0; Index < _countof(sm_rgHeaders); ++Index )
|
||||
{
|
||||
if (FAILED(hr = InsertRecord(&sm_rgHeaders[Index])))
|
||||
{
|
||||
return hr;
|
||||
}
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,176 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
#include "precomp.hxx"
|
||||
|
||||
PFN_WINHTTP_WEBSOCKET_COMPLETE_UPGRADE
|
||||
WINHTTP_HELPER::sm_pfnWinHttpWebSocketCompleteUpgrade;
|
||||
|
||||
PFN_WINHTTP_WEBSOCKET_SEND
|
||||
WINHTTP_HELPER::sm_pfnWinHttpWebSocketSend;
|
||||
|
||||
PFN_WINHTTP_WEBSOCKET_RECEIVE
|
||||
WINHTTP_HELPER::sm_pfnWinHttpWebSocketReceive;
|
||||
|
||||
PFN_WINHTTP_WEBSOCKET_SHUTDOWN
|
||||
WINHTTP_HELPER::sm_pfnWinHttpWebSocketShutdown;
|
||||
|
||||
PFN_WINHTTP_WEBSOCKET_QUERY_CLOSE_STATUS
|
||||
WINHTTP_HELPER::sm_pfnWinHttpWebSocketQueryCloseStatus;
|
||||
|
||||
//static
|
||||
HRESULT
|
||||
WINHTTP_HELPER::StaticInitialize(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
if (!g_fWebSocketSupported)
|
||||
{
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
//
|
||||
// Initialize the function pointers for WinHttp Websocket API's.
|
||||
//
|
||||
|
||||
HMODULE hWinHttp = GetModuleHandleA("winhttp.dll");
|
||||
if (hWinHttp == NULL)
|
||||
{
|
||||
hr = HRESULT_FROM_WIN32(GetLastError());
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
sm_pfnWinHttpWebSocketCompleteUpgrade = (PFN_WINHTTP_WEBSOCKET_COMPLETE_UPGRADE)
|
||||
GetProcAddress(hWinHttp, "WinHttpWebSocketCompleteUpgrade");
|
||||
if (sm_pfnWinHttpWebSocketCompleteUpgrade == NULL)
|
||||
{
|
||||
hr = HRESULT_FROM_WIN32(GetLastError());
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
sm_pfnWinHttpWebSocketQueryCloseStatus = (PFN_WINHTTP_WEBSOCKET_QUERY_CLOSE_STATUS)
|
||||
GetProcAddress(hWinHttp, "WinHttpWebSocketQueryCloseStatus");
|
||||
if (sm_pfnWinHttpWebSocketQueryCloseStatus == NULL)
|
||||
{
|
||||
hr = HRESULT_FROM_WIN32(GetLastError());
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
sm_pfnWinHttpWebSocketReceive = (PFN_WINHTTP_WEBSOCKET_RECEIVE)
|
||||
GetProcAddress(hWinHttp, "WinHttpWebSocketReceive");
|
||||
if (sm_pfnWinHttpWebSocketReceive == NULL)
|
||||
{
|
||||
hr = HRESULT_FROM_WIN32(GetLastError());
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
sm_pfnWinHttpWebSocketSend = (PFN_WINHTTP_WEBSOCKET_SEND)
|
||||
GetProcAddress(hWinHttp, "WinHttpWebSocketSend");
|
||||
if (sm_pfnWinHttpWebSocketSend == NULL)
|
||||
{
|
||||
hr = HRESULT_FROM_WIN32(GetLastError());
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
sm_pfnWinHttpWebSocketShutdown = (PFN_WINHTTP_WEBSOCKET_SHUTDOWN)
|
||||
GetProcAddress(hWinHttp, "WinHttpWebSocketShutdown");
|
||||
if (sm_pfnWinHttpWebSocketShutdown == NULL)
|
||||
{
|
||||
hr = HRESULT_FROM_WIN32(GetLastError());
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
Finished:
|
||||
return hr;
|
||||
}
|
||||
|
||||
|
||||
//static
|
||||
VOID
|
||||
WINHTTP_HELPER::GetFlagsFromBufferType(
|
||||
__in WINHTTP_WEB_SOCKET_BUFFER_TYPE BufferType,
|
||||
__out BOOL * pfUtf8Encoded,
|
||||
__out BOOL * pfFinalFragment,
|
||||
__out BOOL * pfClose
|
||||
)
|
||||
{
|
||||
switch (BufferType)
|
||||
{
|
||||
case WINHTTP_WEB_SOCKET_BINARY_MESSAGE_BUFFER_TYPE:
|
||||
*pfUtf8Encoded = FALSE;
|
||||
*pfFinalFragment = TRUE;
|
||||
*pfClose = FALSE;
|
||||
|
||||
break;
|
||||
|
||||
case WINHTTP_WEB_SOCKET_BINARY_FRAGMENT_BUFFER_TYPE:
|
||||
*pfUtf8Encoded = FALSE;
|
||||
*pfFinalFragment = FALSE;
|
||||
*pfClose = FALSE;
|
||||
|
||||
break;
|
||||
|
||||
case WINHTTP_WEB_SOCKET_UTF8_MESSAGE_BUFFER_TYPE:
|
||||
*pfUtf8Encoded = TRUE;
|
||||
*pfFinalFragment = TRUE;
|
||||
*pfClose = FALSE;
|
||||
|
||||
break;
|
||||
|
||||
case WINHTTP_WEB_SOCKET_UTF8_FRAGMENT_BUFFER_TYPE:
|
||||
*pfUtf8Encoded = TRUE;
|
||||
*pfFinalFragment = FALSE;
|
||||
*pfClose = FALSE;
|
||||
|
||||
break;
|
||||
|
||||
case WINHTTP_WEB_SOCKET_CLOSE_BUFFER_TYPE:
|
||||
*pfUtf8Encoded = FALSE;
|
||||
*pfFinalFragment = FALSE;
|
||||
*pfClose = TRUE;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//static
|
||||
VOID
|
||||
WINHTTP_HELPER::GetBufferTypeFromFlags(
|
||||
__in BOOL fUtf8Encoded,
|
||||
__in BOOL fFinalFragment,
|
||||
__in BOOL fClose,
|
||||
__out WINHTTP_WEB_SOCKET_BUFFER_TYPE* pBufferType
|
||||
)
|
||||
{
|
||||
if (fClose)
|
||||
{
|
||||
*pBufferType = WINHTTP_WEB_SOCKET_CLOSE_BUFFER_TYPE;
|
||||
}
|
||||
else
|
||||
if (fUtf8Encoded)
|
||||
{
|
||||
if (fFinalFragment)
|
||||
{
|
||||
*pBufferType = WINHTTP_WEB_SOCKET_UTF8_MESSAGE_BUFFER_TYPE;
|
||||
}
|
||||
else
|
||||
{
|
||||
*pBufferType = WINHTTP_WEB_SOCKET_UTF8_FRAGMENT_BUFFER_TYPE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (fFinalFragment)
|
||||
{
|
||||
*pBufferType = WINHTTP_WEB_SOCKET_BINARY_MESSAGE_BUFFER_TYPE;
|
||||
}
|
||||
else
|
||||
{
|
||||
*pBufferType = WINHTTP_WEB_SOCKET_BINARY_FRAGMENT_BUFFER_TYPE;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
<!--
|
||||
|
||||
IIS Asp.Net Core Extension Schema
|
||||
|
||||
** Please DO NOT edit this file yourself. **
|
||||
|
||||
If you want to add configuration sections to the schema, you may place
|
||||
them in .xml files similar to this one, in this directory. They will be
|
||||
picked up automatically on startup.
|
||||
|
||||
-->
|
||||
|
||||
<configSchema>
|
||||
<sectionSchema name="system.webServer/aspNetCore">
|
||||
<attribute name="processPath" type="string" expanded="true"/>
|
||||
<attribute name="arguments" type="string" expanded="true" defaultValue=""/>
|
||||
<attribute name="startupTimeLimit" type="uint" defaultValue="120" validationType="integerRange" validationParameter="0,3600"/>
|
||||
<!-- in seconds -->
|
||||
<attribute name="shutdownTimeLimit" type="uint" defaultValue="10" validationType="integerRange" validationParameter="0,600"/>
|
||||
<!-- in seconds -->
|
||||
<attribute name="rapidFailsPerMinute" type="uint" defaultValue="10" validationType="integerRange" validationParameter="0,100"/>
|
||||
<attribute name="requestTimeout" type="timeSpan" defaultValue="00:02:00" validationType="timeSpanRange" validationParameter="0,1296000,60"/>
|
||||
<attribute name="stdoutLogEnabled" type="bool" defaultValue="false" />
|
||||
<attribute name="stdoutLogFile" type="string" defaultValue=".\aspnetcore-stdout" expanded="true"/>
|
||||
<attribute name="processesPerApplication" type="uint" defaultValue="1" validationType="integerRange" validationParameter="1,100"/>
|
||||
<attribute name="forwardWindowsAuthToken" type="bool" defaultValue="true" />
|
||||
<attribute name="disableStartUpErrorPage" type="bool" defaultValue="false" />
|
||||
<attribute name="hostingModel" type="string" />
|
||||
<element name="recycleOnFileChange">
|
||||
|
||||
<collection addElement="file" clearElement="clear">
|
||||
<attribute name="path" type="string" required="true" validationType="nonEmptyString" expanded="true"/>
|
||||
</collection>
|
||||
</element>
|
||||
<element name="environmentVariables">
|
||||
<collection addElement="environmentVariable" clearElement="clear" >
|
||||
<attribute name="name" type="string" required="true" validationType="nonEmptyString"/>
|
||||
<attribute name="value" type="string" required="true"/>
|
||||
</collection>
|
||||
</element>
|
||||
</sectionSchema>
|
||||
</configSchema>
|
||||
Binary file not shown.
Binary file not shown.
|
|
@ -0,0 +1,181 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{4787A64F-9A3E-4867-A55A-70CB4B2B2FFE}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>IISLib</RootNamespace>
|
||||
<ProjectName>IISLib</ProjectName>
|
||||
<WindowsTargetPlatformVersion>10.0.15063.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup />
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="acache.h" />
|
||||
<ClInclude Include="ahutil.h" />
|
||||
<ClInclude Include="base64.h" />
|
||||
<ClInclude Include="buffer.h" />
|
||||
<ClInclude Include="datetime.h" />
|
||||
<ClInclude Include="dbgutil.h" />
|
||||
<ClInclude Include="hashfn.h" />
|
||||
<ClInclude Include="hashtable.h" />
|
||||
<ClInclude Include="listentry.h" />
|
||||
<ClInclude Include="macros.h" />
|
||||
<ClInclude Include="multisz.h" />
|
||||
<ClInclude Include="multisza.h" />
|
||||
<ClInclude Include="ntassert.h" />
|
||||
<ClInclude Include="percpu.h" />
|
||||
<ClInclude Include="precomp.h" />
|
||||
<ClInclude Include="prime.h" />
|
||||
<ClInclude Include="pudebug.h" />
|
||||
<ClInclude Include="reftrace.h" />
|
||||
<ClInclude Include="rwlock.h" />
|
||||
<ClInclude Include="stringa.h" />
|
||||
<ClInclude Include="stringu.h" />
|
||||
<ClInclude Include="tracelog.h" />
|
||||
<ClInclude Include="treehash.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="acache.cxx" />
|
||||
<ClCompile Include="ahutil.cpp" />
|
||||
<ClCompile Include="base64.cpp" />
|
||||
<ClCompile Include="multisz.cpp" />
|
||||
<ClCompile Include="multisza.cpp" />
|
||||
<ClCompile Include="reftrace.c" />
|
||||
<ClCompile Include="stringa.cpp" />
|
||||
<ClCompile Include="stringu.cpp" />
|
||||
<ClCompile Include="tracelog.c" />
|
||||
<ClCompile Include="util.cxx" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,443 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
#include "precomp.h"
|
||||
|
||||
LONG ALLOC_CACHE_HANDLER::sm_nFillPattern = 0xACA50000;
|
||||
HANDLE ALLOC_CACHE_HANDLER::sm_hHeap;
|
||||
|
||||
//
|
||||
// This class is used to implement the free list. We cast the free'd
|
||||
// memory block to a FREE_LIST_HEADER*. The signature is used to guard against
|
||||
// double deletion. We also fill memory with a pattern.
|
||||
//
|
||||
class FREE_LIST_HEADER
|
||||
{
|
||||
public:
|
||||
SLIST_ENTRY ListEntry;
|
||||
DWORD dwSignature;
|
||||
|
||||
enum
|
||||
{
|
||||
FREE_SIGNATURE = (('A') | ('C' << 8) | ('a' << 16) | (('$' << 24) | 0x80)),
|
||||
};
|
||||
};
|
||||
|
||||
ALLOC_CACHE_HANDLER::ALLOC_CACHE_HANDLER(
|
||||
VOID
|
||||
) : m_nThreshold(0),
|
||||
m_cbSize(0),
|
||||
m_pFreeLists(NULL),
|
||||
m_nTotal(0)
|
||||
{
|
||||
}
|
||||
|
||||
ALLOC_CACHE_HANDLER::~ALLOC_CACHE_HANDLER(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
if (m_pFreeLists != NULL)
|
||||
{
|
||||
CleanupLookaside();
|
||||
m_pFreeLists->Dispose();
|
||||
m_pFreeLists = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT
|
||||
ALLOC_CACHE_HANDLER::Initialize(
|
||||
DWORD cbSize,
|
||||
LONG nThreshold
|
||||
)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
m_nThreshold = nThreshold;
|
||||
if ( m_nThreshold > 0xffff)
|
||||
{
|
||||
//
|
||||
// This will be compared against QueryDepthSList return value (USHORT).
|
||||
//
|
||||
m_nThreshold = 0xffff;
|
||||
}
|
||||
|
||||
if ( IsPageheapEnabled() )
|
||||
{
|
||||
//
|
||||
// Disable acache.
|
||||
//
|
||||
m_nThreshold = 0;
|
||||
}
|
||||
|
||||
//
|
||||
// Make sure the block is big enough to hold a FREE_LIST_HEADER.
|
||||
//
|
||||
m_cbSize = cbSize;
|
||||
m_cbSize = max(m_cbSize, sizeof(FREE_LIST_HEADER));
|
||||
|
||||
//
|
||||
// Round up the block size to a multiple of the size of a LONG (for
|
||||
// the fill pattern in Free()).
|
||||
//
|
||||
m_cbSize = (m_cbSize + sizeof(LONG) - 1) & ~(sizeof(LONG) - 1);
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER >= 1600 // VC10
|
||||
auto Init = [] (SLIST_HEADER* pHead)
|
||||
{
|
||||
InitializeSListHead(pHead);
|
||||
};
|
||||
#else
|
||||
class Functor
|
||||
{
|
||||
public:
|
||||
void operator()(SLIST_HEADER* pHead)
|
||||
{
|
||||
InitializeSListHead(pHead);
|
||||
}
|
||||
} Init;
|
||||
#endif
|
||||
|
||||
hr = PER_CPU<SLIST_HEADER>::Create(Init,
|
||||
&m_pFreeLists );
|
||||
if (FAILED(hr))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
m_nFillPattern = InterlockedIncrement(&sm_nFillPattern);
|
||||
|
||||
Finished:
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
// static
|
||||
HRESULT
|
||||
ALLOC_CACHE_HANDLER::StaticInitialize(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
//
|
||||
// Since the memory allocated is fixed size,
|
||||
// a heap is not really needed, allocations can be done
|
||||
// using VirtualAllocEx[Numa]. For now use Windows Heap.
|
||||
//
|
||||
// Be aware that creating one private heap consumes more
|
||||
// virtual address space for the worker process.
|
||||
//
|
||||
sm_hHeap = GetProcessHeap();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
// static
|
||||
VOID
|
||||
ALLOC_CACHE_HANDLER::StaticTerminate(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
sm_hHeap = NULL;
|
||||
}
|
||||
|
||||
VOID
|
||||
ALLOC_CACHE_HANDLER::CleanupLookaside(
|
||||
VOID
|
||||
)
|
||||
/*++
|
||||
Description:
|
||||
This function cleans up the lookaside list by removing storage space.
|
||||
|
||||
Arguments:
|
||||
None.
|
||||
|
||||
Returns:
|
||||
None
|
||||
--*/
|
||||
{
|
||||
//
|
||||
// Free up all the entries in the list.
|
||||
// Don't use InterlockedFlushSList, in order to work
|
||||
// memory must be 16 bytes aligned and currently it is 64.
|
||||
//
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER >= 1600 // VC10
|
||||
auto Predicate = [=] (SLIST_HEADER * pListHeader)
|
||||
{
|
||||
PSLIST_ENTRY pl;
|
||||
LONG NodesToDelete = QueryDepthSList( pListHeader );
|
||||
|
||||
pl = InterlockedPopEntrySList( pListHeader );
|
||||
while ( pl != NULL && --NodesToDelete >= 0 )
|
||||
{
|
||||
InterlockedDecrement( &m_nTotal);
|
||||
|
||||
::HeapFree( sm_hHeap, 0, pl );
|
||||
|
||||
pl = InterlockedPopEntrySList(pListHeader);
|
||||
}
|
||||
};
|
||||
#else
|
||||
class Functor
|
||||
{
|
||||
public:
|
||||
explicit Functor(ALLOC_CACHE_HANDLER * pThis) : _pThis(pThis)
|
||||
{
|
||||
}
|
||||
void operator()(SLIST_HEADER * pListHeader)
|
||||
{
|
||||
PSLIST_ENTRY pl;
|
||||
LONG NodesToDelete = QueryDepthSList( pListHeader );
|
||||
|
||||
pl = InterlockedPopEntrySList( pListHeader );
|
||||
while ( pl != NULL && --NodesToDelete >= 0 )
|
||||
{
|
||||
InterlockedDecrement( &_pThis->m_nTotal);
|
||||
|
||||
::HeapFree( sm_hHeap, 0, pl );
|
||||
|
||||
pl = InterlockedPopEntrySList(pListHeader);
|
||||
}
|
||||
}
|
||||
private:
|
||||
ALLOC_CACHE_HANDLER * _pThis;
|
||||
} Predicate(this);
|
||||
#endif
|
||||
|
||||
m_pFreeLists ->ForEach(Predicate);
|
||||
}
|
||||
|
||||
LPVOID
|
||||
ALLOC_CACHE_HANDLER::Alloc(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
LPVOID pMemory = NULL;
|
||||
|
||||
if ( m_nThreshold > 0 )
|
||||
{
|
||||
SLIST_HEADER * pListHeader = m_pFreeLists ->GetLocal();
|
||||
pMemory = (LPVOID) InterlockedPopEntrySList(pListHeader); // get the real object
|
||||
|
||||
if (pMemory != NULL)
|
||||
{
|
||||
FREE_LIST_HEADER* pfl = (FREE_LIST_HEADER*) pMemory;
|
||||
//
|
||||
// If the signature is wrong then somebody's been scribbling
|
||||
// on memory that they've freed.
|
||||
//
|
||||
DBG_ASSERT(pfl->dwSignature == FREE_LIST_HEADER::FREE_SIGNATURE);
|
||||
}
|
||||
}
|
||||
|
||||
if ( pMemory == NULL )
|
||||
{
|
||||
//
|
||||
// No free entry. Need to alloc a new object.
|
||||
//
|
||||
pMemory = (LPVOID) ::HeapAlloc( sm_hHeap,
|
||||
0,
|
||||
m_cbSize );
|
||||
|
||||
if ( pMemory != NULL )
|
||||
{
|
||||
//
|
||||
// Update counters.
|
||||
//
|
||||
m_nTotal++;
|
||||
}
|
||||
}
|
||||
|
||||
if ( pMemory == NULL )
|
||||
{
|
||||
SetLastError( ERROR_NOT_ENOUGH_MEMORY );
|
||||
}
|
||||
else
|
||||
{
|
||||
FREE_LIST_HEADER* pfl = (FREE_LIST_HEADER*) pMemory;
|
||||
pfl->dwSignature = 0; // clear; just in case caller never overwrites
|
||||
}
|
||||
|
||||
return pMemory;
|
||||
}
|
||||
|
||||
VOID
|
||||
ALLOC_CACHE_HANDLER::Free(
|
||||
__in LPVOID pMemory
|
||||
)
|
||||
{
|
||||
//
|
||||
// Assume that this is allocated using the Alloc() function.
|
||||
//
|
||||
DBG_ASSERT(NULL != pMemory);
|
||||
|
||||
//
|
||||
// Use a signature to check against double deletions.
|
||||
//
|
||||
FREE_LIST_HEADER* pfl = (FREE_LIST_HEADER*) pMemory;
|
||||
DBG_ASSERT(pfl->dwSignature != FREE_LIST_HEADER::FREE_SIGNATURE);
|
||||
|
||||
//
|
||||
// Start filling the space beyond the portion overlaid by the initial
|
||||
// FREE_LIST_HEADER. Fill at most 6 DWORDS.
|
||||
//
|
||||
LONG* pl = (LONG*) (pfl+1);
|
||||
|
||||
for (LONG cb = (LONG)min(6 * sizeof(LONG),m_cbSize) - sizeof(FREE_LIST_HEADER);
|
||||
cb > 0;
|
||||
cb -= sizeof(LONG))
|
||||
{
|
||||
*pl++ = m_nFillPattern;
|
||||
}
|
||||
|
||||
//
|
||||
// Now, set the signature.
|
||||
//
|
||||
pfl->dwSignature = FREE_LIST_HEADER::FREE_SIGNATURE;
|
||||
|
||||
//
|
||||
// Store the items in the alloc cache.
|
||||
//
|
||||
SLIST_HEADER * pListHeader = m_pFreeLists ->GetLocal();
|
||||
|
||||
if ( QueryDepthSList(pListHeader) >= m_nThreshold )
|
||||
{
|
||||
//
|
||||
// Threshold for free entries is exceeded. Free the object to
|
||||
// process pool.
|
||||
//
|
||||
::HeapFree( sm_hHeap, 0, pMemory );
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
// Store the given pointer in the single linear list
|
||||
//
|
||||
InterlockedPushEntrySList(pListHeader, &pfl->ListEntry);
|
||||
}
|
||||
}
|
||||
|
||||
DWORD
|
||||
ALLOC_CACHE_HANDLER::QueryDepthForAllSLists(
|
||||
VOID
|
||||
)
|
||||
/*++
|
||||
|
||||
Description:
|
||||
|
||||
Aggregates the total count of elements in all lists.
|
||||
|
||||
Arguments:
|
||||
|
||||
None.
|
||||
|
||||
Return Value:
|
||||
|
||||
Total count (snapshot).
|
||||
|
||||
--*/
|
||||
{
|
||||
DWORD Count = 0;
|
||||
|
||||
if (m_pFreeLists != NULL)
|
||||
{
|
||||
#if defined(_MSC_VER) && _MSC_VER >= 1600 // VC10
|
||||
auto Predicate = [&Count] (SLIST_HEADER * pListHeader)
|
||||
{
|
||||
Count += QueryDepthSList(pListHeader);
|
||||
};
|
||||
#else
|
||||
class Functor
|
||||
{
|
||||
public:
|
||||
explicit Functor(DWORD& Count) : _Count(Count)
|
||||
{
|
||||
}
|
||||
void operator()(SLIST_HEADER * pListHeader)
|
||||
{
|
||||
_Count += QueryDepthSList(pListHeader);
|
||||
}
|
||||
private:
|
||||
DWORD& _Count;
|
||||
} Predicate(Count);
|
||||
#endif
|
||||
//
|
||||
// [&Count] means that the method can modify local variable Count.
|
||||
//
|
||||
m_pFreeLists ->ForEach(Predicate);
|
||||
}
|
||||
|
||||
return Count;
|
||||
}
|
||||
|
||||
// static
|
||||
BOOL
|
||||
ALLOC_CACHE_HANDLER::IsPageheapEnabled(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
BOOL fRet = FALSE;
|
||||
BOOL fLockedHeap = FALSE;
|
||||
HMODULE hModule = NULL;
|
||||
HANDLE hHeap = NULL;
|
||||
PROCESS_HEAP_ENTRY heapEntry = {0};
|
||||
|
||||
//
|
||||
// If verifier.dll is loaded - we are running under app verifier == pageheap is enabled
|
||||
//
|
||||
hModule = GetModuleHandle( L"verifier.dll" );
|
||||
if ( hModule != NULL )
|
||||
{
|
||||
hModule = NULL;
|
||||
fRet = TRUE;
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
//
|
||||
// Create a heap for calling heapwalk
|
||||
// otherwise HeapWalk turns off lookasides for a useful heap
|
||||
//
|
||||
hHeap = ::HeapCreate( 0, 0, 0 );
|
||||
if ( hHeap == NULL )
|
||||
{
|
||||
fRet = FALSE;
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
fRet = ::HeapLock( hHeap );
|
||||
if ( !fRet )
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
fLockedHeap = TRUE;
|
||||
|
||||
//
|
||||
// If HeapWalk is unsupported -> then running page heap
|
||||
//
|
||||
fRet = ::HeapWalk( hHeap, &heapEntry );
|
||||
if ( !fRet )
|
||||
{
|
||||
if ( GetLastError() == ERROR_INVALID_FUNCTION )
|
||||
{
|
||||
fRet = TRUE;
|
||||
goto Finished;
|
||||
}
|
||||
}
|
||||
|
||||
fRet = FALSE;
|
||||
|
||||
Finished:
|
||||
|
||||
if ( fLockedHeap )
|
||||
{
|
||||
fLockedHeap = FALSE;
|
||||
DBG_REQUIRE( ::HeapUnlock( hHeap ) );
|
||||
}
|
||||
|
||||
if ( hHeap )
|
||||
{
|
||||
DBG_REQUIRE( ::HeapDestroy( hHeap ) );
|
||||
hHeap = NULL;
|
||||
}
|
||||
|
||||
return fRet;
|
||||
}
|
||||
|
|
@ -0,0 +1,115 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "percpu.h"
|
||||
|
||||
class ALLOC_CACHE_HANDLER
|
||||
{
|
||||
public:
|
||||
|
||||
ALLOC_CACHE_HANDLER(
|
||||
VOID
|
||||
);
|
||||
|
||||
~ALLOC_CACHE_HANDLER(
|
||||
VOID
|
||||
);
|
||||
|
||||
HRESULT
|
||||
Initialize(
|
||||
DWORD cbSize,
|
||||
LONG nThreshold
|
||||
);
|
||||
|
||||
LPVOID
|
||||
Alloc(
|
||||
VOID
|
||||
);
|
||||
|
||||
VOID
|
||||
Free(
|
||||
__in LPVOID pMemory
|
||||
);
|
||||
|
||||
|
||||
private:
|
||||
|
||||
VOID
|
||||
CleanupLookaside(
|
||||
VOID
|
||||
);
|
||||
|
||||
DWORD
|
||||
QueryDepthForAllSLists(
|
||||
VOID
|
||||
);
|
||||
|
||||
LONG m_nThreshold;
|
||||
DWORD m_cbSize;
|
||||
|
||||
PER_CPU<SLIST_HEADER> * m_pFreeLists;
|
||||
|
||||
//
|
||||
// Total heap allocations done over the lifetime.
|
||||
// Note that this is not interlocked, it is just a hint for debugging.
|
||||
//
|
||||
volatile LONG m_nTotal;
|
||||
|
||||
LONG m_nFillPattern;
|
||||
|
||||
public:
|
||||
|
||||
static
|
||||
HRESULT
|
||||
StaticInitialize(
|
||||
VOID
|
||||
);
|
||||
|
||||
static
|
||||
VOID
|
||||
StaticTerminate(
|
||||
VOID
|
||||
);
|
||||
|
||||
static
|
||||
BOOL
|
||||
IsPageheapEnabled();
|
||||
|
||||
private:
|
||||
|
||||
static LONG sm_nFillPattern;
|
||||
static HANDLE sm_hHeap;
|
||||
};
|
||||
|
||||
|
||||
// You can use ALLOC_CACHE_HANDLER as a per-class allocator
|
||||
// in your C++ classes. Add the following to your class definition:
|
||||
//
|
||||
// protected:
|
||||
// static ALLOC_CACHE_HANDLER* sm_palloc;
|
||||
// public:
|
||||
// static void* operator new(size_t s)
|
||||
// {
|
||||
// IRTLASSERT(s == sizeof(C));
|
||||
// IRTLASSERT(sm_palloc != NULL);
|
||||
// return sm_palloc->Alloc();
|
||||
// }
|
||||
// static void operator delete(void* pv)
|
||||
// {
|
||||
// IRTLASSERT(pv != NULL);
|
||||
// if (sm_palloc != NULL)
|
||||
// sm_palloc->Free(pv);
|
||||
// }
|
||||
//
|
||||
// Obviously, you must initialize sm_palloc before you can allocate
|
||||
// any objects of this class.
|
||||
//
|
||||
// Note that if you derive a class from this base class, the derived class
|
||||
// must also provide its own operator new and operator delete. If not, the
|
||||
// base class's allocator will be called, but the size of the derived
|
||||
// object will almost certainly be larger than that of the base object.
|
||||
// Furthermore, the allocator will not be used for arrays of objects
|
||||
// (override operator new[] and operator delete[]), but this is a
|
||||
// harder problem since the allocator works with one fixed size.
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,258 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
#pragma once
|
||||
#include<Windows.h>
|
||||
|
||||
HRESULT
|
||||
SetElementProperty(
|
||||
IN IAppHostElement * pElement,
|
||||
IN CONST WCHAR * szPropName,
|
||||
IN CONST VARIANT * varPropValue
|
||||
);
|
||||
|
||||
HRESULT
|
||||
SetElementStringProperty(
|
||||
IN IAppHostElement * pElement,
|
||||
IN CONST WCHAR * szPropName,
|
||||
IN CONST WCHAR * szPropValue
|
||||
);
|
||||
|
||||
HRESULT
|
||||
GetElementStringProperty(
|
||||
IN IAppHostElement * pElement,
|
||||
IN CONST WCHAR * szPropName,
|
||||
OUT BSTR * pbstrPropValue
|
||||
);
|
||||
|
||||
HRESULT
|
||||
GetElementStringProperty(
|
||||
IN IAppHostElement * pElement,
|
||||
IN CONST WCHAR * szPropName,
|
||||
OUT STRU * pstrPropValue
|
||||
);
|
||||
|
||||
HRESULT
|
||||
GetElementBoolProperty(
|
||||
IN IAppHostElement * pElement,
|
||||
IN LPCWSTR pszPropertyName,
|
||||
OUT BOOL * pBool
|
||||
);
|
||||
|
||||
HRESULT
|
||||
GetElementBoolProperty(
|
||||
IN IAppHostElement * pElement,
|
||||
IN LPCWSTR pszPropertyName,
|
||||
OUT bool * pBool
|
||||
);
|
||||
|
||||
HRESULT
|
||||
GetElementChildByName(
|
||||
IN IAppHostElement * pElement,
|
||||
IN LPCWSTR pszElementName,
|
||||
OUT IAppHostElement ** ppChildElement
|
||||
);
|
||||
|
||||
HRESULT
|
||||
GetElementDWORDProperty(
|
||||
IN IAppHostElement * pElement,
|
||||
IN LPCWSTR pszPropertyName,
|
||||
OUT DWORD * pdwValue
|
||||
);
|
||||
|
||||
HRESULT
|
||||
GetElementLONGLONGProperty(
|
||||
IN IAppHostElement * pElement,
|
||||
IN LPCWSTR pszPropertyName,
|
||||
OUT LONGLONG * pllValue
|
||||
);
|
||||
|
||||
|
||||
HRESULT
|
||||
GetElementRawTimeSpanProperty(
|
||||
IN IAppHostElement * pElement,
|
||||
IN LPCWSTR pszPropertyName,
|
||||
OUT ULONGLONG * pulonglong
|
||||
);
|
||||
|
||||
#define FIND_ELEMENT_CASE_SENSITIVE 0x00000000
|
||||
#define FIND_ELEMENT_CASE_INSENSITIVE 0x00000001
|
||||
|
||||
HRESULT
|
||||
DeleteElementFromCollection(
|
||||
IAppHostElementCollection *pCollection,
|
||||
CONST WCHAR * szKeyName,
|
||||
CONST WCHAR * szKeyValue,
|
||||
ULONG BehaviorFlags,
|
||||
BOOL * pfDeleted
|
||||
);
|
||||
|
||||
HRESULT
|
||||
DeleteAllElementsFromCollection(
|
||||
IAppHostElementCollection *pCollection,
|
||||
CONST WCHAR * szKeyName,
|
||||
CONST WCHAR * szKeyValue,
|
||||
ULONG BehaviorFlags,
|
||||
UINT * pNumDeleted
|
||||
);
|
||||
|
||||
HRESULT
|
||||
FindElementInCollection(
|
||||
IAppHostElementCollection *pCollection,
|
||||
CONST WCHAR * szKeyName,
|
||||
CONST WCHAR * szKeyValue,
|
||||
ULONG BehaviorFlags,
|
||||
OUT ULONG * pIndex
|
||||
);
|
||||
|
||||
HRESULT
|
||||
VariantAssign(
|
||||
IN OUT VARIANT * pv,
|
||||
IN CONST WCHAR * sz
|
||||
);
|
||||
|
||||
HRESULT
|
||||
GetLocationFromFile(
|
||||
IN IAppHostAdminManager * pAdminMgr,
|
||||
IN CONST WCHAR * szConfigPath,
|
||||
IN CONST WCHAR * szLocationPath,
|
||||
OUT IAppHostConfigLocation ** ppLocation,
|
||||
OUT BOOL * pFound
|
||||
);
|
||||
|
||||
HRESULT
|
||||
GetSectionFromLocation(
|
||||
IN IAppHostConfigLocation * pLocation,
|
||||
IN CONST WCHAR * szSectionName,
|
||||
OUT IAppHostElement ** ppSectionElement,
|
||||
OUT BOOL * pFound
|
||||
);
|
||||
|
||||
HRESULT
|
||||
GetAdminElement(
|
||||
IN IAppHostAdminManager * pAdminMgr,
|
||||
IN CONST WCHAR * szConfigPath,
|
||||
IN CONST WCHAR * szElementName,
|
||||
OUT IAppHostElement ** pElement
|
||||
);
|
||||
|
||||
HRESULT
|
||||
ClearAdminElement(
|
||||
IN IAppHostAdminManager * pAdminMgr,
|
||||
IN CONST WCHAR * szConfigPath,
|
||||
IN CONST WCHAR * szElementName
|
||||
);
|
||||
|
||||
HRESULT
|
||||
ClearElementFromAllSites(
|
||||
IN IAppHostAdminManager * pAdminMgr,
|
||||
IN CONST WCHAR * szConfigPath,
|
||||
IN CONST WCHAR * szElementName
|
||||
);
|
||||
|
||||
HRESULT
|
||||
ClearElementFromAllLocations(
|
||||
IN IAppHostAdminManager * pAdminMgr,
|
||||
IN CONST WCHAR * szConfigPath,
|
||||
IN CONST WCHAR * szElementName
|
||||
);
|
||||
|
||||
HRESULT
|
||||
ClearLocationElements(
|
||||
IN IAppHostConfigLocation * pLocation,
|
||||
IN CONST WCHAR * szElementName
|
||||
);
|
||||
|
||||
HRESULT
|
||||
CompareElementName(
|
||||
IN IAppHostElement * pElement,
|
||||
IN CONST WCHAR * szNameToMatch,
|
||||
OUT BOOL * pMatched
|
||||
);
|
||||
|
||||
HRESULT
|
||||
ClearChildElementsByName(
|
||||
IN IAppHostChildElementCollection * pCollection,
|
||||
IN CONST WCHAR * szElementName,
|
||||
OUT BOOL * pFound
|
||||
);
|
||||
|
||||
HRESULT
|
||||
GetSitesCollection(
|
||||
IN IAppHostAdminManager * pAdminMgr,
|
||||
IN CONST WCHAR * szConfigPath,
|
||||
OUT IAppHostElementCollection ** pSitesCollection
|
||||
);
|
||||
|
||||
HRESULT
|
||||
GetLocationCollection(
|
||||
IN IAppHostAdminManager * pAdminMgr,
|
||||
IN CONST WCHAR * szConfigPath,
|
||||
OUT IAppHostConfigLocationCollection ** pLocationCollection
|
||||
);
|
||||
|
||||
struct ENUM_INDEX
|
||||
{
|
||||
VARIANT Index;
|
||||
ULONG Count;
|
||||
};
|
||||
|
||||
HRESULT
|
||||
FindFirstElement(
|
||||
IN IAppHostElementCollection * pCollection,
|
||||
OUT ENUM_INDEX * pIndex,
|
||||
OUT IAppHostElement ** pElement
|
||||
);
|
||||
|
||||
HRESULT
|
||||
FindNextElement(
|
||||
IN IAppHostElementCollection * pCollection,
|
||||
IN OUT ENUM_INDEX * pIndex,
|
||||
OUT IAppHostElement ** pElement
|
||||
);
|
||||
|
||||
HRESULT
|
||||
FindFirstChildElement(
|
||||
IN IAppHostChildElementCollection * pCollection,
|
||||
OUT ENUM_INDEX * pIndex,
|
||||
OUT IAppHostElement ** pElement
|
||||
);
|
||||
|
||||
HRESULT
|
||||
FindNextChildElement(
|
||||
IN IAppHostChildElementCollection * pCollection,
|
||||
IN OUT ENUM_INDEX * pIndex,
|
||||
OUT IAppHostElement ** pElement
|
||||
);
|
||||
|
||||
HRESULT
|
||||
FindFirstLocation(
|
||||
IN IAppHostConfigLocationCollection * pCollection,
|
||||
OUT ENUM_INDEX * pIndex,
|
||||
OUT IAppHostConfigLocation ** pLocation
|
||||
);
|
||||
|
||||
HRESULT
|
||||
FindNextLocation(
|
||||
IN IAppHostConfigLocationCollection * pCollection,
|
||||
IN OUT ENUM_INDEX * pIndex,
|
||||
OUT IAppHostConfigLocation ** pLocation
|
||||
);
|
||||
|
||||
HRESULT
|
||||
FindFirstLocationElement(
|
||||
IN IAppHostConfigLocation * pLocation,
|
||||
OUT ENUM_INDEX * pIndex,
|
||||
OUT IAppHostElement ** pElement
|
||||
);
|
||||
|
||||
HRESULT
|
||||
FindNextLocationElement(
|
||||
IN IAppHostConfigLocation * pLocation,
|
||||
IN OUT ENUM_INDEX * pIndex,
|
||||
OUT IAppHostElement ** pElement
|
||||
);
|
||||
|
||||
HRESULT GetSharedConfigEnabled(
|
||||
BOOL * pfIsSharedConfig
|
||||
);
|
||||
|
|
@ -0,0 +1,482 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
#include "precomp.h"
|
||||
|
||||
DWORD
|
||||
Base64Encode(
|
||||
__in_bcount(cbDecodedBufferSize) VOID * pDecodedBuffer,
|
||||
IN DWORD cbDecodedBufferSize,
|
||||
__out_ecount_opt(cchEncodedStringSize) PWSTR pszEncodedString,
|
||||
IN DWORD cchEncodedStringSize,
|
||||
__out_opt DWORD * pcchEncoded
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Decode a base64-encoded string.
|
||||
|
||||
Arguments:
|
||||
|
||||
pDecodedBuffer (IN) - buffer to encode.
|
||||
cbDecodedBufferSize (IN) - size of buffer to encode.
|
||||
cchEncodedStringSize (IN) - size of the buffer for the encoded string.
|
||||
pszEncodedString (OUT) = the encoded string.
|
||||
pcchEncoded (OUT) - size in characters of the encoded string.
|
||||
|
||||
Return Values:
|
||||
|
||||
0 - success.
|
||||
E_OUTOFMEMORY
|
||||
|
||||
--*/
|
||||
{
|
||||
static WCHAR rgchEncodeTable[64] = {
|
||||
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
|
||||
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
|
||||
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
|
||||
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
|
||||
};
|
||||
|
||||
DWORD ib;
|
||||
DWORD ich;
|
||||
DWORD cchEncoded;
|
||||
BYTE b0, b1, b2;
|
||||
BYTE * pbDecodedBuffer = (BYTE *) pDecodedBuffer;
|
||||
|
||||
// Calculate encoded string size.
|
||||
cchEncoded = 1 + (cbDecodedBufferSize + 2) / 3 * 4;
|
||||
|
||||
if (NULL != pcchEncoded) {
|
||||
*pcchEncoded = cchEncoded;
|
||||
}
|
||||
|
||||
if (cchEncodedStringSize == 0 && pszEncodedString == NULL) {
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
if (cchEncodedStringSize < cchEncoded) {
|
||||
// Given buffer is too small to hold encoded string.
|
||||
return ERROR_INSUFFICIENT_BUFFER;
|
||||
}
|
||||
|
||||
// Encode data byte triplets into four-byte clusters.
|
||||
ib = ich = 0;
|
||||
while (ib < cbDecodedBufferSize) {
|
||||
b0 = pbDecodedBuffer[ib++];
|
||||
b1 = (ib < cbDecodedBufferSize) ? pbDecodedBuffer[ib++] : 0;
|
||||
b2 = (ib < cbDecodedBufferSize) ? pbDecodedBuffer[ib++] : 0;
|
||||
|
||||
//
|
||||
// The checks below for buffer overflow seems redundant to me.
|
||||
// But it's the only way I can find to keep OACR quiet so it
|
||||
// will have to do.
|
||||
//
|
||||
|
||||
pszEncodedString[ich++] = rgchEncodeTable[b0 >> 2];
|
||||
if ( ich >= cchEncodedStringSize )
|
||||
{
|
||||
DBG_ASSERT( FALSE );
|
||||
return ERROR_BUFFER_OVERFLOW;
|
||||
}
|
||||
|
||||
pszEncodedString[ich++] = rgchEncodeTable[((b0 << 4) & 0x30) | ((b1 >> 4) & 0x0f)];
|
||||
if ( ich >= cchEncodedStringSize )
|
||||
{
|
||||
DBG_ASSERT( FALSE );
|
||||
return ERROR_BUFFER_OVERFLOW;
|
||||
}
|
||||
|
||||
pszEncodedString[ich++] = rgchEncodeTable[((b1 << 2) & 0x3c) | ((b2 >> 6) & 0x03)];
|
||||
if ( ich >= cchEncodedStringSize )
|
||||
{
|
||||
DBG_ASSERT( FALSE );
|
||||
return ERROR_BUFFER_OVERFLOW;
|
||||
}
|
||||
|
||||
pszEncodedString[ich++] = rgchEncodeTable[b2 & 0x3f];
|
||||
if ( ich >= cchEncodedStringSize )
|
||||
{
|
||||
DBG_ASSERT( FALSE );
|
||||
return ERROR_BUFFER_OVERFLOW;
|
||||
}
|
||||
}
|
||||
|
||||
// Pad the last cluster as necessary to indicate the number of data bytes
|
||||
// it represents.
|
||||
switch (cbDecodedBufferSize % 3) {
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
pszEncodedString[ich - 2] = '=';
|
||||
__fallthrough;
|
||||
case 2:
|
||||
pszEncodedString[ich - 1] = '=';
|
||||
break;
|
||||
}
|
||||
|
||||
// Null-terminate the encoded string.
|
||||
pszEncodedString[ich++] = '\0';
|
||||
|
||||
DBG_ASSERT(ich == cchEncoded);
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
DWORD
|
||||
Base64Decode(
|
||||
__in PCWSTR pszEncodedString,
|
||||
__out_opt VOID * pDecodeBuffer,
|
||||
__in DWORD cbDecodeBufferSize,
|
||||
__out_opt DWORD * pcbDecoded
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Decode a base64-encoded string.
|
||||
|
||||
Arguments:
|
||||
|
||||
pszEncodedString (IN) - base64-encoded string to decode.
|
||||
cbDecodeBufferSize (IN) - size in bytes of the decode buffer.
|
||||
pbDecodeBuffer (OUT) - holds the decoded data.
|
||||
pcbDecoded (OUT) - number of data bytes in the decoded data (if success or
|
||||
STATUS_BUFFER_TOO_SMALL).
|
||||
|
||||
Return Values:
|
||||
|
||||
0 - success.
|
||||
E_OUTOFMEMORY
|
||||
E_INVALIDARG
|
||||
|
||||
--*/
|
||||
{
|
||||
#define NA (255)
|
||||
#define DECODE(x) (((ULONG)(x) < sizeof(rgbDecodeTable)) ? rgbDecodeTable[x] : NA)
|
||||
|
||||
static BYTE rgbDecodeTable[128] = {
|
||||
NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, // 0-15
|
||||
NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, // 16-31
|
||||
NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, 62, NA, NA, NA, 63, // 32-47
|
||||
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, NA, NA, NA, 0, NA, NA, // 48-63
|
||||
NA, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, // 64-79
|
||||
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, NA, NA, NA, NA, NA, // 80-95
|
||||
NA, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, // 96-111
|
||||
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, NA, NA, NA, NA, NA, // 112-127
|
||||
};
|
||||
|
||||
DWORD cbDecoded;
|
||||
DWORD cchEncodedSize;
|
||||
DWORD ich;
|
||||
DWORD ib;
|
||||
BYTE b0, b1, b2, b3;
|
||||
BYTE * pbDecodeBuffer = (BYTE *) pDecodeBuffer;
|
||||
|
||||
cchEncodedSize = (DWORD)wcslen(pszEncodedString);
|
||||
if (NULL != pcbDecoded) {
|
||||
*pcbDecoded = 0;
|
||||
}
|
||||
|
||||
if ((0 == cchEncodedSize) || (0 != (cchEncodedSize % 4))) {
|
||||
// Input string is not sized correctly to be base64.
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
// Calculate decoded buffer size.
|
||||
cbDecoded = (cchEncodedSize + 3) / 4 * 3;
|
||||
if (pszEncodedString[cchEncodedSize-1] == '=') {
|
||||
if (pszEncodedString[cchEncodedSize-2] == '=') {
|
||||
// Only one data byte is encoded in the last cluster.
|
||||
cbDecoded -= 2;
|
||||
}
|
||||
else {
|
||||
// Only two data bytes are encoded in the last cluster.
|
||||
cbDecoded -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (NULL != pcbDecoded) {
|
||||
*pcbDecoded = cbDecoded;
|
||||
}
|
||||
|
||||
if (cbDecodeBufferSize == 0 && pDecodeBuffer == NULL) {
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
if (cbDecoded > cbDecodeBufferSize) {
|
||||
// Supplied buffer is too small.
|
||||
return ERROR_INSUFFICIENT_BUFFER;
|
||||
}
|
||||
|
||||
// Decode each four-byte cluster into the corresponding three data bytes.
|
||||
ich = ib = 0;
|
||||
while (ich < cchEncodedSize) {
|
||||
b0 = DECODE(pszEncodedString[ich]); ich++;
|
||||
b1 = DECODE(pszEncodedString[ich]); ich++;
|
||||
b2 = DECODE(pszEncodedString[ich]); ich++;
|
||||
b3 = DECODE(pszEncodedString[ich]); ich++;
|
||||
|
||||
if ((NA == b0) || (NA == b1) || (NA == b2) || (NA == b3)) {
|
||||
// Contents of input string are not base64.
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
pbDecodeBuffer[ib++] = (b0 << 2) | (b1 >> 4);
|
||||
|
||||
if (ib < cbDecoded) {
|
||||
pbDecodeBuffer[ib++] = (b1 << 4) | (b2 >> 2);
|
||||
|
||||
if (ib < cbDecoded) {
|
||||
pbDecodeBuffer[ib++] = (b2 << 6) | b3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DBG_ASSERT(ib == cbDecoded);
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
DWORD
|
||||
Base64Encode(
|
||||
__in_bcount(cbDecodedBufferSize) VOID * pDecodedBuffer,
|
||||
IN DWORD cbDecodedBufferSize,
|
||||
__out_ecount_opt(cchEncodedStringSize) PSTR pszEncodedString,
|
||||
IN DWORD cchEncodedStringSize,
|
||||
__out_opt DWORD * pcchEncoded
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Decode a base64-encoded string.
|
||||
|
||||
Arguments:
|
||||
|
||||
pDecodedBuffer (IN) - buffer to encode.
|
||||
cbDecodedBufferSize (IN) - size of buffer to encode.
|
||||
cchEncodedStringSize (IN) - size of the buffer for the encoded string.
|
||||
pszEncodedString (OUT) = the encoded string.
|
||||
pcchEncoded (OUT) - size in characters of the encoded string.
|
||||
|
||||
Return Values:
|
||||
|
||||
0 - success.
|
||||
E_OUTOFMEMORY
|
||||
|
||||
--*/
|
||||
{
|
||||
static CHAR rgchEncodeTable[64] = {
|
||||
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
|
||||
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
|
||||
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
|
||||
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
|
||||
};
|
||||
|
||||
DWORD ib;
|
||||
DWORD ich;
|
||||
DWORD cchEncoded;
|
||||
BYTE b0, b1, b2;
|
||||
BYTE * pbDecodedBuffer = (BYTE *) pDecodedBuffer;
|
||||
|
||||
// Calculate encoded string size.
|
||||
cchEncoded = 1 + (cbDecodedBufferSize + 2) / 3 * 4;
|
||||
|
||||
if (NULL != pcchEncoded) {
|
||||
*pcchEncoded = cchEncoded;
|
||||
}
|
||||
|
||||
if (cchEncodedStringSize == 0 && pszEncodedString == NULL) {
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
if (cchEncodedStringSize < cchEncoded) {
|
||||
// Given buffer is too small to hold encoded string.
|
||||
return ERROR_INSUFFICIENT_BUFFER;
|
||||
}
|
||||
|
||||
// Encode data byte triplets into four-byte clusters.
|
||||
ib = ich = 0;
|
||||
while (ib < cbDecodedBufferSize) {
|
||||
b0 = pbDecodedBuffer[ib++];
|
||||
b1 = (ib < cbDecodedBufferSize) ? pbDecodedBuffer[ib++] : 0;
|
||||
b2 = (ib < cbDecodedBufferSize) ? pbDecodedBuffer[ib++] : 0;
|
||||
|
||||
//
|
||||
// The checks below for buffer overflow seems redundant to me.
|
||||
// But it's the only way I can find to keep OACR quiet so it
|
||||
// will have to do.
|
||||
//
|
||||
|
||||
pszEncodedString[ich++] = rgchEncodeTable[b0 >> 2];
|
||||
if ( ich >= cchEncodedStringSize )
|
||||
{
|
||||
DBG_ASSERT( FALSE );
|
||||
return ERROR_BUFFER_OVERFLOW;
|
||||
}
|
||||
|
||||
pszEncodedString[ich++] = rgchEncodeTable[((b0 << 4) & 0x30) | ((b1 >> 4) & 0x0f)];
|
||||
if ( ich >= cchEncodedStringSize )
|
||||
{
|
||||
DBG_ASSERT( FALSE );
|
||||
return ERROR_BUFFER_OVERFLOW;
|
||||
}
|
||||
|
||||
pszEncodedString[ich++] = rgchEncodeTable[((b1 << 2) & 0x3c) | ((b2 >> 6) & 0x03)];
|
||||
if ( ich >= cchEncodedStringSize )
|
||||
{
|
||||
DBG_ASSERT( FALSE );
|
||||
return ERROR_BUFFER_OVERFLOW;
|
||||
}
|
||||
|
||||
pszEncodedString[ich++] = rgchEncodeTable[b2 & 0x3f];
|
||||
if ( ich >= cchEncodedStringSize )
|
||||
{
|
||||
DBG_ASSERT( FALSE );
|
||||
return ERROR_BUFFER_OVERFLOW;
|
||||
}
|
||||
}
|
||||
|
||||
// Pad the last cluster as necessary to indicate the number of data bytes
|
||||
// it represents.
|
||||
switch (cbDecodedBufferSize % 3) {
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
pszEncodedString[ich - 2] = '=';
|
||||
__fallthrough;
|
||||
case 2:
|
||||
pszEncodedString[ich - 1] = '=';
|
||||
break;
|
||||
}
|
||||
|
||||
// Null-terminate the encoded string.
|
||||
pszEncodedString[ich++] = '\0';
|
||||
|
||||
DBG_ASSERT(ich == cchEncoded);
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
DWORD
|
||||
Base64Decode(
|
||||
__in PCSTR pszEncodedString,
|
||||
__out_opt VOID * pDecodeBuffer,
|
||||
__in DWORD cbDecodeBufferSize,
|
||||
__out_opt DWORD * pcbDecoded
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Decode a base64-encoded string.
|
||||
|
||||
Arguments:
|
||||
|
||||
pszEncodedString (IN) - base64-encoded string to decode.
|
||||
cbDecodeBufferSize (IN) - size in bytes of the decode buffer.
|
||||
pbDecodeBuffer (OUT) - holds the decoded data.
|
||||
pcbDecoded (OUT) - number of data bytes in the decoded data (if success or
|
||||
STATUS_BUFFER_TOO_SMALL).
|
||||
|
||||
Return Values:
|
||||
|
||||
0 - success.
|
||||
E_OUTOFMEMORY
|
||||
E_INVALIDARG
|
||||
|
||||
--*/
|
||||
{
|
||||
#define NA (255)
|
||||
#define DECODE(x) (((ULONG)(x) < sizeof(rgbDecodeTable)) ? rgbDecodeTable[x] : NA)
|
||||
|
||||
static BYTE rgbDecodeTable[128] = {
|
||||
NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, // 0-15
|
||||
NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, // 16-31
|
||||
NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, 62, NA, NA, NA, 63, // 32-47
|
||||
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, NA, NA, NA, 0, NA, NA, // 48-63
|
||||
NA, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, // 64-79
|
||||
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, NA, NA, NA, NA, NA, // 80-95
|
||||
NA, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, // 96-111
|
||||
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, NA, NA, NA, NA, NA, // 112-127
|
||||
};
|
||||
|
||||
DWORD cbDecoded;
|
||||
DWORD cchEncodedSize;
|
||||
DWORD ich;
|
||||
DWORD ib;
|
||||
BYTE b0, b1, b2, b3;
|
||||
BYTE * pbDecodeBuffer = (BYTE *) pDecodeBuffer;
|
||||
|
||||
cchEncodedSize = (DWORD)strlen(pszEncodedString);
|
||||
if (NULL != pcbDecoded) {
|
||||
*pcbDecoded = 0;
|
||||
}
|
||||
|
||||
if ((0 == cchEncodedSize) || (0 != (cchEncodedSize % 4))) {
|
||||
// Input string is not sized correctly to be base64.
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
// Calculate decoded buffer size.
|
||||
cbDecoded = (cchEncodedSize + 3) / 4 * 3;
|
||||
if (pszEncodedString[cchEncodedSize-1] == '=') {
|
||||
if (pszEncodedString[cchEncodedSize-2] == '=') {
|
||||
// Only one data byte is encoded in the last cluster.
|
||||
cbDecoded -= 2;
|
||||
}
|
||||
else {
|
||||
// Only two data bytes are encoded in the last cluster.
|
||||
cbDecoded -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (NULL != pcbDecoded) {
|
||||
*pcbDecoded = cbDecoded;
|
||||
}
|
||||
|
||||
if (cbDecodeBufferSize == 0 && pDecodeBuffer == NULL) {
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
if (cbDecoded > cbDecodeBufferSize) {
|
||||
// Supplied buffer is too small.
|
||||
return ERROR_INSUFFICIENT_BUFFER;
|
||||
}
|
||||
|
||||
// Decode each four-byte cluster into the corresponding three data bytes.
|
||||
ich = ib = 0;
|
||||
while (ich < cchEncodedSize) {
|
||||
b0 = DECODE(pszEncodedString[ich]); ich++;
|
||||
b1 = DECODE(pszEncodedString[ich]); ich++;
|
||||
b2 = DECODE(pszEncodedString[ich]); ich++;
|
||||
b3 = DECODE(pszEncodedString[ich]); ich++;
|
||||
|
||||
if ((NA == b0) || (NA == b1) || (NA == b2) || (NA == b3)) {
|
||||
// Contents of input string are not base64.
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
pbDecodeBuffer[ib++] = (b0 << 2) | (b1 >> 4);
|
||||
|
||||
if (ib < cbDecoded) {
|
||||
pbDecodeBuffer[ib++] = (b1 << 4) | (b2 >> 2);
|
||||
|
||||
if (ib < cbDecoded) {
|
||||
pbDecodeBuffer[ib++] = (b2 << 6) | b3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DBG_ASSERT(ib == cbDecoded);
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
#ifndef _BASE64_H_
|
||||
#define _BASE64_H_
|
||||
|
||||
DWORD
|
||||
Base64Encode(
|
||||
__in_bcount( cbDecodedBufferSize ) VOID * pDecodedBuffer,
|
||||
IN DWORD cbDecodedBufferSize,
|
||||
__out_ecount_opt( cchEncodedStringSize ) PWSTR pszEncodedString,
|
||||
IN DWORD cchEncodedStringSize,
|
||||
__out_opt DWORD * pcchEncoded
|
||||
);
|
||||
|
||||
DWORD
|
||||
Base64Decode(
|
||||
__in PCWSTR pszEncodedString,
|
||||
__out_opt VOID * pDecodeBuffer,
|
||||
__in DWORD cbDecodeBufferSize,
|
||||
__out_opt DWORD * pcbDecoded
|
||||
);
|
||||
|
||||
DWORD
|
||||
Base64Encode(
|
||||
__in_bcount( cbDecodedBufferSize ) VOID * pDecodedBuffer,
|
||||
IN DWORD cbDecodedBufferSize,
|
||||
__out_ecount_opt( cchEncodedStringSize ) PSTR pszEncodedString,
|
||||
IN DWORD cchEncodedStringSize,
|
||||
__out_opt DWORD * pcchEncoded
|
||||
);
|
||||
|
||||
DWORD
|
||||
Base64Decode(
|
||||
__in PCSTR pszEncodedString,
|
||||
__out_opt VOID * pDecodeBuffer,
|
||||
__in DWORD cbDecodeBufferSize,
|
||||
__out_opt DWORD * pcbDecoded
|
||||
);
|
||||
|
||||
#endif // _BASE64_HXX_
|
||||
|
||||
|
|
@ -0,0 +1,271 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <crtdbg.h>
|
||||
|
||||
|
||||
//
|
||||
// BUFFER_T class shouldn't be used directly. Use BUFFER specialization class instead.
|
||||
// The only BUFFER_T partners are STRU and STRA classes.
|
||||
// BUFFER_T cannot hold other but primitive types since it doesn't call
|
||||
// constructor and destructor.
|
||||
//
|
||||
// Note: Size is in bytes.
|
||||
//
|
||||
template<typename T, DWORD LENGTH>
|
||||
class BUFFER_T
|
||||
{
|
||||
public:
|
||||
|
||||
BUFFER_T()
|
||||
: m_cbBuffer( sizeof(m_rgBuffer) ),
|
||||
m_fHeapAllocated( false ),
|
||||
m_pBuffer(m_rgBuffer)
|
||||
/*++
|
||||
Description:
|
||||
|
||||
Default constructor where the inline buffer is used.
|
||||
|
||||
Arguments:
|
||||
|
||||
None.
|
||||
|
||||
Returns:
|
||||
|
||||
None.
|
||||
|
||||
--*/
|
||||
{
|
||||
}
|
||||
|
||||
BUFFER_T(
|
||||
__inout_bcount(cbInit) T* pbInit,
|
||||
__in DWORD cbInit
|
||||
) : m_pBuffer( pbInit ),
|
||||
m_cbBuffer( cbInit ),
|
||||
m_fHeapAllocated( false )
|
||||
/*++
|
||||
Description:
|
||||
|
||||
Instantiate BUFFER, initially using pbInit as buffer
|
||||
This is useful for stack-buffers and inline-buffer class members
|
||||
(see STACK_BUFFER and INLINE_BUFFER_INIT below)
|
||||
|
||||
BUFFER does not free pbInit.
|
||||
|
||||
Arguments:
|
||||
|
||||
pbInit - Initial buffer to use.
|
||||
cbInit - Size of pbInit in bytes (not in elements).
|
||||
|
||||
Returns:
|
||||
|
||||
None.
|
||||
|
||||
--*/
|
||||
{
|
||||
_ASSERTE( NULL != pbInit );
|
||||
_ASSERTE( cbInit > 0 );
|
||||
}
|
||||
|
||||
~BUFFER_T()
|
||||
{
|
||||
if( IsHeapAllocated() )
|
||||
{
|
||||
_ASSERTE( NULL != m_pBuffer );
|
||||
HeapFree( GetProcessHeap(), 0, m_pBuffer );
|
||||
m_pBuffer = NULL;
|
||||
m_cbBuffer = 0;
|
||||
m_fHeapAllocated = false;
|
||||
}
|
||||
}
|
||||
|
||||
T*
|
||||
QueryPtr(
|
||||
VOID
|
||||
) const
|
||||
{
|
||||
//
|
||||
// Return pointer to data buffer.
|
||||
//
|
||||
return m_pBuffer;
|
||||
}
|
||||
|
||||
DWORD
|
||||
QuerySize(
|
||||
VOID
|
||||
) const
|
||||
{
|
||||
//
|
||||
// Return number of bytes.
|
||||
//
|
||||
return m_cbBuffer;
|
||||
}
|
||||
|
||||
__success(return == true)
|
||||
bool
|
||||
Resize(
|
||||
const SIZE_T cbNewSize,
|
||||
const bool fZeroMemoryBeyondOldSize = false
|
||||
)
|
||||
/*++
|
||||
Description:
|
||||
|
||||
Resizes the buffer.
|
||||
|
||||
Arguments:
|
||||
|
||||
cbNewSize - Size in bytes to grow to.
|
||||
fZeroMemoryBeyondOldSize
|
||||
- Whether to zero the region of memory of the
|
||||
new buffer beyond the original size.
|
||||
|
||||
Returns:
|
||||
|
||||
TRUE on success, FALSE on failure.
|
||||
|
||||
--*/
|
||||
{
|
||||
PVOID pNewMem;
|
||||
|
||||
if ( cbNewSize <= m_cbBuffer )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( cbNewSize > MAXDWORD )
|
||||
{
|
||||
SetLastError( ERROR_INVALID_PARAMETER );
|
||||
return false;
|
||||
}
|
||||
|
||||
DWORD dwHeapAllocFlags = fZeroMemoryBeyondOldSize ? HEAP_ZERO_MEMORY : 0;
|
||||
|
||||
if( IsHeapAllocated() )
|
||||
{
|
||||
pNewMem = HeapReAlloc( GetProcessHeap(), dwHeapAllocFlags, m_pBuffer, cbNewSize );
|
||||
}
|
||||
else
|
||||
{
|
||||
pNewMem = HeapAlloc( GetProcessHeap(), dwHeapAllocFlags, cbNewSize );
|
||||
}
|
||||
|
||||
if( pNewMem == NULL )
|
||||
{
|
||||
SetLastError( ERROR_NOT_ENOUGH_MEMORY );
|
||||
return false;
|
||||
}
|
||||
|
||||
if( !IsHeapAllocated() )
|
||||
{
|
||||
//
|
||||
// First time this block is allocated. Copy over old contents.
|
||||
//
|
||||
memcpy_s( pNewMem, static_cast<DWORD>(cbNewSize), m_pBuffer, m_cbBuffer );
|
||||
m_fHeapAllocated = true;
|
||||
}
|
||||
|
||||
m_pBuffer = reinterpret_cast<T*>(pNewMem);
|
||||
m_cbBuffer = static_cast<DWORD>(cbNewSize);
|
||||
|
||||
_ASSERTE( m_pBuffer != NULL );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
bool
|
||||
IsHeapAllocated(
|
||||
VOID
|
||||
) const
|
||||
{
|
||||
return m_fHeapAllocated;
|
||||
}
|
||||
|
||||
//
|
||||
// The default inline buffer.
|
||||
// This member should be at the beginning for alignment purposes.
|
||||
//
|
||||
T m_rgBuffer[LENGTH];
|
||||
|
||||
//
|
||||
// Is m_pBuffer dynamically allocated?
|
||||
//
|
||||
bool m_fHeapAllocated;
|
||||
|
||||
//
|
||||
// Size of the buffer as requested by client in bytes.
|
||||
//
|
||||
DWORD m_cbBuffer;
|
||||
|
||||
//
|
||||
// Pointer to buffer.
|
||||
//
|
||||
__field_bcount_full(m_cbBuffer)
|
||||
T* m_pBuffer;
|
||||
};
|
||||
|
||||
//
|
||||
// Resizes the buffer by 2 if the ideal size is bigger
|
||||
// than the buffer length. That give us lg(n) allocations.
|
||||
//
|
||||
// Use template inferring like:
|
||||
//
|
||||
// BUFFER buff;
|
||||
// hr = ResizeBufferByTwo(buff, 100);
|
||||
//
|
||||
template<typename T, DWORD LENGTH>
|
||||
HRESULT
|
||||
ResizeBufferByTwo(
|
||||
BUFFER_T<T,LENGTH>& Buffer,
|
||||
SIZE_T cbIdealSize,
|
||||
bool fZeroMemoryBeyondOldSize = false
|
||||
)
|
||||
{
|
||||
if (cbIdealSize > Buffer.QuerySize())
|
||||
{
|
||||
if (!Buffer.Resize(max(cbIdealSize, static_cast<SIZE_T>(Buffer.QuerySize() * 2)),
|
||||
fZeroMemoryBeyondOldSize))
|
||||
{
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
//
|
||||
// Lots of code uses BUFFER class to store a bunch of different
|
||||
// structures, so m_rgBuffer needs to be 8 byte aligned when it is used
|
||||
// as an opaque buffer.
|
||||
//
|
||||
#define INLINED_BUFFER_LEN 32
|
||||
typedef BUFFER_T<BYTE, INLINED_BUFFER_LEN> BUFFER;
|
||||
|
||||
//
|
||||
// Assumption of macros below for pointer alignment purposes
|
||||
//
|
||||
C_ASSERT( sizeof(VOID*) <= sizeof(ULONGLONG) );
|
||||
|
||||
//
|
||||
// Declare a BUFFER that will use stack memory of <size>
|
||||
// bytes. If the buffer overflows then a heap buffer will be allocated.
|
||||
//
|
||||
#define STACK_BUFFER( _name, _size ) \
|
||||
ULONGLONG __aqw##_name[ ( ( (_size) + sizeof(ULONGLONG) - 1 ) / sizeof(ULONGLONG) ) ]; \
|
||||
BUFFER _name( (BYTE*)__aqw##_name, sizeof(__aqw##_name) )
|
||||
|
||||
//
|
||||
// Macros for declaring and initializing a BUFFER that will use inline memory
|
||||
// of <size> bytes as a member of an object.
|
||||
//
|
||||
#define INLINE_BUFFER( _name, _size ) \
|
||||
ULONGLONG __aqw##_name[ ( ( (_size) + sizeof(ULONGLONG) - 1 ) / sizeof(ULONGLONG) ) ]; \
|
||||
BUFFER _name;
|
||||
|
||||
#define INLINE_BUFFER_INIT( _name ) \
|
||||
_name( (BYTE*)__aqw##_name, sizeof( __aqw##_name ) )
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
#ifndef _DATETIME_H_
|
||||
#define _DATETIME_H_
|
||||
|
||||
BOOL
|
||||
StringTimeToFileTime(
|
||||
PCSTR pszTime,
|
||||
ULONGLONG * pulTime
|
||||
);
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -0,0 +1,102 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
#ifndef _DBGUTIL_H_
|
||||
#define _DBGUTIL_H_
|
||||
|
||||
#include <crtdbg.h>
|
||||
|
||||
//
|
||||
// TODO
|
||||
// Using _CrtDbg implementation. If hooking is desired
|
||||
// wrappers should be provided here so that we can reimplement
|
||||
// if neecessary.
|
||||
//
|
||||
// IF_DEBUG/DEBUG FLAGS
|
||||
//
|
||||
// registry configuration
|
||||
//
|
||||
|
||||
//
|
||||
// Debug error levels for DEBUG_FLAGS_VAR.
|
||||
//
|
||||
|
||||
#define DEBUG_FLAG_INFO 0x00000001
|
||||
#define DEBUG_FLAG_WARN 0x00000002
|
||||
#define DEBUG_FLAG_ERROR 0x00000004
|
||||
|
||||
//
|
||||
// Predefined error level values. These are backwards from the
|
||||
// windows definitions.
|
||||
//
|
||||
|
||||
#define DEBUG_FLAGS_INFO (DEBUG_FLAG_ERROR | DEBUG_FLAG_WARN | DEBUG_FLAG_INFO)
|
||||
#define DEBUG_FLAGS_WARN (DEBUG_FLAG_ERROR | DEBUG_FLAG_WARN)
|
||||
#define DEBUG_FLAGS_ERROR (DEBUG_FLAG_ERROR)
|
||||
#define DEBUG_FLAGS_ANY (DEBUG_FLAG_INFO | DEBUG_FLAG_WARN | DEBUG_FLAG_ERROR)
|
||||
|
||||
//
|
||||
// Global variables to control tracing. Generally per module
|
||||
//
|
||||
|
||||
#ifndef DEBUG_FLAGS_VAR
|
||||
#define DEBUG_FLAGS_VAR g_dwDebugFlags
|
||||
#endif
|
||||
|
||||
#ifndef DEBUG_LABEL_VAR
|
||||
#define DEBUG_LABEL_VAR g_szDebugLabel
|
||||
#endif
|
||||
|
||||
extern PCSTR DEBUG_LABEL_VAR;
|
||||
extern DWORD DEBUG_FLAGS_VAR;
|
||||
|
||||
//
|
||||
// Module should make this declaration globally.
|
||||
//
|
||||
|
||||
#define DECLARE_DEBUG_PRINT_OBJECT( _pszLabel_ ) \
|
||||
PCSTR DEBUG_LABEL_VAR = _pszLabel_; \
|
||||
DWORD DEBUG_FLAGS_VAR = DEBUG_FLAGS_ANY; \
|
||||
|
||||
#define DECLARE_DEBUG_PRINT_OBJECT2( _pszLabel_, _dwLevel_ ) \
|
||||
PCSTR DEBUG_LABEL_VAR = _pszLabel_; \
|
||||
DWORD DEBUG_FLAGS_VAR = _dwLevel_; \
|
||||
|
||||
//
|
||||
// This doesn't do anything now. Should be safe to call in dll main.
|
||||
//
|
||||
|
||||
#define CREATE_DEBUG_PRINT_OBJECT
|
||||
|
||||
//
|
||||
// Trace macros
|
||||
//
|
||||
|
||||
#define DBG_CONTEXT _CRT_WARN, __FILE__, __LINE__, DEBUG_LABEL_VAR
|
||||
|
||||
#ifdef DEBUG
|
||||
#define DBGINFO(args) \
|
||||
{if (DEBUG_FLAGS_VAR & DEBUG_FLAG_INFO) { _CrtDbgReport args; }}
|
||||
#define DBGWARN(args) \
|
||||
{if (DEBUG_FLAGS_VAR & DEBUG_FLAG_WARN) { _CrtDbgReport args; }}
|
||||
#define DBGERROR(args) \
|
||||
{if (DEBUG_FLAGS_VAR & DEBUG_FLAG_ERROR) { _CrtDbgReport args; }}
|
||||
#else
|
||||
#define DBGINFO
|
||||
#define DBGWARN
|
||||
#define DBGERROR
|
||||
#endif
|
||||
|
||||
#define DBGPRINTF DBGINFO
|
||||
|
||||
//
|
||||
// Simple error traces
|
||||
//
|
||||
|
||||
#define DBGERROR_HR( _hr_ ) \
|
||||
DBGERROR((DBG_CONTEXT, "hr=0x%x\n", _hr_))
|
||||
|
||||
#define DBGERROR_STATUS( _status_ ) \
|
||||
DBGERROR((DBG_CONTEXT, "status=%d\n", _status_))
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,325 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
#ifndef __HASHFN_H__
|
||||
#define __HASHFN_H__
|
||||
|
||||
|
||||
// Produce a scrambled, randomish number in the range 0 to RANDOM_PRIME-1.
|
||||
// Applying this to the results of the other hash functions is likely to
|
||||
// produce a much better distribution, especially for the identity hash
|
||||
// functions such as Hash(char c), where records will tend to cluster at
|
||||
// the low end of the hashtable otherwise. LKRhash applies this internally
|
||||
// to all hash signatures for exactly this reason.
|
||||
|
||||
inline DWORD
|
||||
HashScramble(DWORD dwHash)
|
||||
{
|
||||
// Here are 10 primes slightly greater than 10^9
|
||||
// 1000000007, 1000000009, 1000000021, 1000000033, 1000000087,
|
||||
// 1000000093, 1000000097, 1000000103, 1000000123, 1000000181.
|
||||
|
||||
// default value for "scrambling constant"
|
||||
const DWORD RANDOM_CONSTANT = 314159269UL;
|
||||
// large prime number, also used for scrambling
|
||||
const DWORD RANDOM_PRIME = 1000000007UL;
|
||||
|
||||
return (RANDOM_CONSTANT * dwHash) % RANDOM_PRIME ;
|
||||
}
|
||||
|
||||
|
||||
// Faster scrambling function suggested by Eric Jacobsen
|
||||
|
||||
inline DWORD
|
||||
HashRandomizeBits(DWORD dw)
|
||||
{
|
||||
return (((dw * 1103515245 + 12345) >> 16)
|
||||
| ((dw * 69069 + 1) & 0xffff0000));
|
||||
}
|
||||
|
||||
|
||||
// Small prime number used as a multiplier in the supplied hash functions
|
||||
const DWORD HASH_MULTIPLIER = 101;
|
||||
|
||||
#undef HASH_SHIFT_MULTIPLY
|
||||
|
||||
#ifdef HASH_SHIFT_MULTIPLY
|
||||
# define HASH_MULTIPLY(dw) (((dw) << 7) - (dw))
|
||||
#else
|
||||
# define HASH_MULTIPLY(dw) ((dw) * HASH_MULTIPLIER)
|
||||
#endif
|
||||
|
||||
// Fast, simple hash function that tends to give a good distribution.
|
||||
// Apply HashScramble to the result if you're using this for something
|
||||
// other than LKRhash.
|
||||
|
||||
inline DWORD
|
||||
HashString(
|
||||
const char* psz,
|
||||
DWORD dwHash = 0)
|
||||
{
|
||||
// force compiler to use unsigned arithmetic
|
||||
const unsigned char* upsz = (const unsigned char*) psz;
|
||||
|
||||
for ( ; *upsz; ++upsz)
|
||||
dwHash = HASH_MULTIPLY(dwHash) + *upsz;
|
||||
|
||||
return dwHash;
|
||||
}
|
||||
|
||||
inline DWORD
|
||||
HashString(
|
||||
__in_ecount(cch) const char* psz,
|
||||
__in DWORD cch,
|
||||
__in DWORD dwHash
|
||||
)
|
||||
{
|
||||
// force compiler to use unsigned arithmetic
|
||||
const unsigned char* upsz = (const unsigned char*) psz;
|
||||
|
||||
for (DWORD Index = 0;
|
||||
Index < cch;
|
||||
++Index, ++upsz)
|
||||
{
|
||||
dwHash = HASH_MULTIPLY(dwHash) + *upsz;
|
||||
}
|
||||
|
||||
return dwHash;
|
||||
}
|
||||
|
||||
|
||||
// Unicode version of above
|
||||
|
||||
inline DWORD
|
||||
HashString(
|
||||
const wchar_t* pwsz,
|
||||
DWORD dwHash = 0)
|
||||
{
|
||||
for ( ; *pwsz; ++pwsz)
|
||||
dwHash = HASH_MULTIPLY(dwHash) + *pwsz;
|
||||
|
||||
return dwHash;
|
||||
}
|
||||
|
||||
// Based on length of the string instead of null-terminating character
|
||||
|
||||
inline DWORD
|
||||
HashString(
|
||||
__in_ecount(cch) const wchar_t* pwsz,
|
||||
__in DWORD cch,
|
||||
__in DWORD dwHash
|
||||
)
|
||||
{
|
||||
for (DWORD Index = 0;
|
||||
Index < cch;
|
||||
++Index, ++pwsz)
|
||||
{
|
||||
dwHash = HASH_MULTIPLY(dwHash) + *pwsz;
|
||||
}
|
||||
|
||||
return dwHash;
|
||||
}
|
||||
|
||||
|
||||
// Quick-'n'-dirty case-insensitive string hash function.
|
||||
// Make sure that you follow up with _stricmp or _mbsicmp. You should
|
||||
// also cache the length of strings and check those first. Caching
|
||||
// an uppercase version of a string can help too.
|
||||
// Again, apply HashScramble to the result if using with something other
|
||||
// than LKRhash.
|
||||
// Note: this is not really adequate for MBCS strings.
|
||||
|
||||
inline DWORD
|
||||
HashStringNoCase(
|
||||
const char* psz,
|
||||
DWORD dwHash = 0)
|
||||
{
|
||||
const unsigned char* upsz = (const unsigned char*) psz;
|
||||
|
||||
for ( ; *upsz; ++upsz)
|
||||
dwHash = HASH_MULTIPLY(dwHash)
|
||||
+ (*upsz & 0xDF); // strip off lowercase bit
|
||||
|
||||
return dwHash;
|
||||
}
|
||||
|
||||
inline DWORD
|
||||
HashStringNoCase(
|
||||
__in_ecount(cch)
|
||||
const char* psz,
|
||||
SIZE_T cch,
|
||||
DWORD dwHash)
|
||||
{
|
||||
const unsigned char* upsz = (const unsigned char*) psz;
|
||||
|
||||
for (SIZE_T Index = 0;
|
||||
Index < cch;
|
||||
++Index, ++upsz)
|
||||
{
|
||||
dwHash = HASH_MULTIPLY(dwHash)
|
||||
+ (*upsz & 0xDF); // strip off lowercase bit
|
||||
}
|
||||
return dwHash;
|
||||
}
|
||||
|
||||
|
||||
// Unicode version of above
|
||||
|
||||
inline DWORD
|
||||
HashStringNoCase(
|
||||
const wchar_t* pwsz,
|
||||
DWORD dwHash = 0)
|
||||
{
|
||||
for ( ; *pwsz; ++pwsz)
|
||||
dwHash = HASH_MULTIPLY(dwHash) + (*pwsz & 0xFFDF);
|
||||
|
||||
return dwHash;
|
||||
}
|
||||
|
||||
// Unicode version of above with length
|
||||
|
||||
inline DWORD
|
||||
HashStringNoCase(
|
||||
__in_ecount(cch)
|
||||
const wchar_t* pwsz,
|
||||
SIZE_T cch,
|
||||
DWORD dwHash)
|
||||
{
|
||||
for (SIZE_T Index = 0;
|
||||
Index < cch;
|
||||
++Index, ++pwsz)
|
||||
{
|
||||
dwHash = HASH_MULTIPLY(dwHash) + (*pwsz & 0xFFDF);
|
||||
}
|
||||
return dwHash;
|
||||
}
|
||||
|
||||
|
||||
// HashBlob returns the hash of a blob of arbitrary binary data.
|
||||
//
|
||||
// Warning: HashBlob is generally not the right way to hash a class object.
|
||||
// Consider:
|
||||
// class CFoo {
|
||||
// public:
|
||||
// char m_ch;
|
||||
// double m_d;
|
||||
// char* m_psz;
|
||||
// };
|
||||
//
|
||||
// inline DWORD Hash(const CFoo& rFoo)
|
||||
// { return HashBlob(&rFoo, sizeof(CFoo)); }
|
||||
//
|
||||
// This is the wrong way to hash a CFoo for two reasons: (a) there will be
|
||||
// a 7-byte gap between m_ch and m_d imposed by the alignment restrictions
|
||||
// of doubles, which will be filled with random data (usually non-zero for
|
||||
// stack variables), and (b) it hashes the address (rather than the
|
||||
// contents) of the string m_psz. Similarly,
|
||||
//
|
||||
// bool operator==(const CFoo& rFoo1, const CFoo& rFoo2)
|
||||
// { return memcmp(&rFoo1, &rFoo2, sizeof(CFoo)) == 0; }
|
||||
//
|
||||
// does the wrong thing. Much better to do this:
|
||||
//
|
||||
// DWORD Hash(const CFoo& rFoo)
|
||||
// {
|
||||
// return HashString(rFoo.m_psz,
|
||||
// HASH_MULTIPLIER * Hash(rFoo.m_ch)
|
||||
// + Hash(rFoo.m_d));
|
||||
// }
|
||||
//
|
||||
// Again, apply HashScramble if using with something other than LKRhash.
|
||||
|
||||
inline DWORD
|
||||
HashBlob(
|
||||
const void* pv,
|
||||
size_t cb,
|
||||
DWORD dwHash = 0)
|
||||
{
|
||||
const BYTE * pb = static_cast<const BYTE *>(pv);
|
||||
|
||||
while (cb-- > 0)
|
||||
dwHash = HASH_MULTIPLY(dwHash) + *pb++;
|
||||
|
||||
return dwHash;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
// Overloaded hash functions for all the major builtin types.
|
||||
// Again, apply HashScramble to result if using with something other than
|
||||
// LKRhash.
|
||||
//
|
||||
|
||||
inline DWORD Hash(const char* psz)
|
||||
{ return HashString(psz); }
|
||||
|
||||
inline DWORD Hash(const unsigned char* pusz)
|
||||
{ return HashString(reinterpret_cast<const char*>(pusz)); }
|
||||
|
||||
inline DWORD Hash(const signed char* pssz)
|
||||
{ return HashString(reinterpret_cast<const char*>(pssz)); }
|
||||
|
||||
inline DWORD Hash(const wchar_t* pwsz)
|
||||
{ return HashString(pwsz); }
|
||||
|
||||
inline DWORD
|
||||
Hash(
|
||||
const GUID* pguid,
|
||||
DWORD dwHash = 0)
|
||||
{
|
||||
|
||||
return * reinterpret_cast<const DWORD *>(const_cast<GUID*>(pguid)) + dwHash;
|
||||
}
|
||||
|
||||
// Identity hash functions: scalar values map to themselves
|
||||
inline DWORD Hash(char c)
|
||||
{ return c; }
|
||||
|
||||
inline DWORD Hash(unsigned char uc)
|
||||
{ return uc; }
|
||||
|
||||
inline DWORD Hash(signed char sc)
|
||||
{ return sc; }
|
||||
|
||||
inline DWORD Hash(short sh)
|
||||
{ return sh; }
|
||||
|
||||
inline DWORD Hash(unsigned short ush)
|
||||
{ return ush; }
|
||||
|
||||
inline DWORD Hash(int i)
|
||||
{ return i; }
|
||||
|
||||
inline DWORD Hash(unsigned int u)
|
||||
{ return u; }
|
||||
|
||||
inline DWORD Hash(long l)
|
||||
{ return l; }
|
||||
|
||||
inline DWORD Hash(unsigned long ul)
|
||||
{ return ul; }
|
||||
|
||||
inline DWORD Hash(float f)
|
||||
{
|
||||
// be careful of rounding errors when computing keys
|
||||
union {
|
||||
float f;
|
||||
DWORD dw;
|
||||
} u;
|
||||
u.f = f;
|
||||
return u.dw;
|
||||
}
|
||||
|
||||
inline DWORD Hash(double dbl)
|
||||
{
|
||||
// be careful of rounding errors when computing keys
|
||||
union {
|
||||
double dbl;
|
||||
DWORD dw[2];
|
||||
} u;
|
||||
u.dbl = dbl;
|
||||
return u.dw[0] * HASH_MULTIPLIER + u.dw[1];
|
||||
}
|
||||
|
||||
#endif // __HASHFN_H__
|
||||
|
|
@ -0,0 +1,666 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <crtdbg.h>
|
||||
#include "rwlock.h"
|
||||
#include "prime.h"
|
||||
|
||||
template <class _Record>
|
||||
class HASH_NODE
|
||||
{
|
||||
template <class _Record, class _Key>
|
||||
friend class HASH_TABLE;
|
||||
|
||||
HASH_NODE(
|
||||
_Record * pRecord,
|
||||
DWORD dwHash
|
||||
) : _pNext (NULL),
|
||||
_pRecord (pRecord),
|
||||
_dwHash (dwHash)
|
||||
{}
|
||||
|
||||
~HASH_NODE()
|
||||
{
|
||||
_ASSERTE(_pRecord == NULL);
|
||||
}
|
||||
|
||||
private:
|
||||
// Next node in the hash table look-aside
|
||||
HASH_NODE<_Record> *_pNext;
|
||||
|
||||
// actual record
|
||||
_Record * _pRecord;
|
||||
|
||||
// hash value
|
||||
DWORD _dwHash;
|
||||
};
|
||||
|
||||
template <class _Record, class _Key>
|
||||
class HASH_TABLE
|
||||
{
|
||||
protected:
|
||||
typedef BOOL
|
||||
(PFN_DELETE_IF)(
|
||||
_Record * pRecord,
|
||||
PVOID pvContext
|
||||
);
|
||||
|
||||
typedef VOID
|
||||
(PFN_APPLY)(
|
||||
_Record * pRecord,
|
||||
PVOID pvContext
|
||||
);
|
||||
|
||||
public:
|
||||
HASH_TABLE(
|
||||
VOID
|
||||
)
|
||||
: _ppBuckets( NULL ),
|
||||
_nBuckets( 0 ),
|
||||
_nItems( 0 )
|
||||
{
|
||||
}
|
||||
|
||||
virtual
|
||||
~HASH_TABLE();
|
||||
|
||||
virtual
|
||||
VOID
|
||||
ReferenceRecord(
|
||||
_Record * pRecord
|
||||
) = 0;
|
||||
|
||||
virtual
|
||||
VOID
|
||||
DereferenceRecord(
|
||||
_Record * pRecord
|
||||
) = 0;
|
||||
|
||||
virtual
|
||||
_Key
|
||||
ExtractKey(
|
||||
_Record * pRecord
|
||||
) = 0;
|
||||
|
||||
virtual
|
||||
DWORD
|
||||
CalcKeyHash(
|
||||
_Key key
|
||||
) = 0;
|
||||
|
||||
virtual
|
||||
BOOL
|
||||
EqualKeys(
|
||||
_Key key1,
|
||||
_Key key2
|
||||
) = 0;
|
||||
|
||||
DWORD
|
||||
Count(
|
||||
VOID
|
||||
) const;
|
||||
|
||||
bool
|
||||
IsInitialized(
|
||||
VOID
|
||||
) const;
|
||||
|
||||
virtual
|
||||
VOID
|
||||
Clear();
|
||||
|
||||
HRESULT
|
||||
Initialize(
|
||||
DWORD nBucketSize
|
||||
);
|
||||
|
||||
virtual
|
||||
VOID
|
||||
FindKey(
|
||||
_Key key,
|
||||
_Record ** ppRecord
|
||||
);
|
||||
|
||||
virtual
|
||||
HRESULT
|
||||
InsertRecord(
|
||||
_Record * pRecord
|
||||
);
|
||||
|
||||
virtual
|
||||
VOID
|
||||
DeleteKey(
|
||||
_Key key
|
||||
);
|
||||
|
||||
virtual
|
||||
VOID
|
||||
DeleteIf(
|
||||
PFN_DELETE_IF pfnDeleteIf,
|
||||
PVOID pvContext
|
||||
);
|
||||
|
||||
VOID
|
||||
Apply(
|
||||
PFN_APPLY pfnApply,
|
||||
PVOID pvContext
|
||||
);
|
||||
|
||||
private:
|
||||
|
||||
__success(*ppNode != NULL && return != FALSE)
|
||||
BOOL
|
||||
FindNodeInternal(
|
||||
_Key key,
|
||||
DWORD dwHash,
|
||||
__deref_out
|
||||
HASH_NODE<_Record> ** ppNode,
|
||||
__deref_opt_out
|
||||
HASH_NODE<_Record> *** pppPreviousNodeNextPointer = NULL
|
||||
);
|
||||
|
||||
VOID
|
||||
DeleteNode(
|
||||
HASH_NODE<_Record> * pNode
|
||||
)
|
||||
{
|
||||
if (pNode->_pRecord != NULL)
|
||||
{
|
||||
DereferenceRecord(pNode->_pRecord);
|
||||
pNode->_pRecord = NULL;
|
||||
}
|
||||
|
||||
delete pNode;
|
||||
}
|
||||
|
||||
VOID
|
||||
RehashTableIfNeeded(
|
||||
VOID
|
||||
);
|
||||
|
||||
HASH_NODE<_Record> ** _ppBuckets;
|
||||
DWORD _nBuckets;
|
||||
DWORD _nItems;
|
||||
//
|
||||
// Allow to use lock object in const methods.
|
||||
//
|
||||
mutable
|
||||
CWSDRWLock _tableLock;
|
||||
};
|
||||
|
||||
template <class _Record, class _Key>
|
||||
HRESULT
|
||||
HASH_TABLE<_Record,_Key>::Initialize(
|
||||
DWORD nBuckets
|
||||
)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
if ( nBuckets == 0 )
|
||||
{
|
||||
hr = E_INVALIDARG;
|
||||
goto Failed;
|
||||
}
|
||||
|
||||
if (nBuckets >= MAXDWORD/sizeof(HASH_NODE<_Record> *))
|
||||
{
|
||||
hr = E_INVALIDARG;
|
||||
goto Failed;
|
||||
}
|
||||
|
||||
_ASSERTE(_ppBuckets == NULL );
|
||||
if ( _ppBuckets != NULL )
|
||||
{
|
||||
hr = E_INVALIDARG;
|
||||
goto Failed;
|
||||
}
|
||||
|
||||
hr = _tableLock.Init();
|
||||
if ( FAILED( hr ) )
|
||||
{
|
||||
goto Failed;
|
||||
}
|
||||
|
||||
_ppBuckets = (HASH_NODE<_Record> **)HeapAlloc(
|
||||
GetProcessHeap(),
|
||||
HEAP_ZERO_MEMORY,
|
||||
nBuckets*sizeof(HASH_NODE<_Record> *));
|
||||
if (_ppBuckets == NULL)
|
||||
{
|
||||
hr = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
|
||||
goto Failed;
|
||||
}
|
||||
_nBuckets = nBuckets;
|
||||
|
||||
return S_OK;
|
||||
|
||||
Failed:
|
||||
|
||||
if (_ppBuckets)
|
||||
{
|
||||
HeapFree(GetProcessHeap(),
|
||||
0,
|
||||
_ppBuckets);
|
||||
_ppBuckets = NULL;
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
|
||||
template <class _Record, class _Key>
|
||||
HASH_TABLE<_Record,_Key>::~HASH_TABLE()
|
||||
{
|
||||
if (_ppBuckets == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_ASSERTE(_nItems == 0);
|
||||
|
||||
HeapFree(GetProcessHeap(),
|
||||
0,
|
||||
_ppBuckets);
|
||||
_ppBuckets = NULL;
|
||||
_nBuckets = 0;
|
||||
}
|
||||
|
||||
template< class _Record, class _Key>
|
||||
DWORD
|
||||
HASH_TABLE<_Record,_Key>::Count() const
|
||||
{
|
||||
return _nItems;
|
||||
}
|
||||
|
||||
template< class _Record, class _Key>
|
||||
bool
|
||||
HASH_TABLE<_Record,_Key>::IsInitialized(
|
||||
VOID
|
||||
) const
|
||||
{
|
||||
return _ppBuckets != NULL;
|
||||
}
|
||||
|
||||
|
||||
template <class _Record, class _Key>
|
||||
VOID
|
||||
HASH_TABLE<_Record,_Key>::Clear()
|
||||
{
|
||||
HASH_NODE<_Record> *pCurrent;
|
||||
HASH_NODE<_Record> *pNext;
|
||||
|
||||
// This is here in the off cases where someone instantiates a hashtable
|
||||
// and then does an automatic "clear" before its destruction WITHOUT
|
||||
// ever initializing it.
|
||||
if ( ! _tableLock.QueryInited() )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_tableLock.ExclusiveAcquire();
|
||||
|
||||
for (DWORD i=0; i<_nBuckets; i++)
|
||||
{
|
||||
pCurrent = _ppBuckets[i];
|
||||
_ppBuckets[i] = NULL;
|
||||
while (pCurrent != NULL)
|
||||
{
|
||||
pNext = pCurrent->_pNext;
|
||||
DeleteNode(pCurrent);
|
||||
pCurrent = pNext;
|
||||
}
|
||||
}
|
||||
|
||||
_nItems = 0;
|
||||
_tableLock.ExclusiveRelease();
|
||||
}
|
||||
|
||||
template <class _Record, class _Key>
|
||||
__success(*ppNode != NULL && return != FALSE)
|
||||
BOOL
|
||||
HASH_TABLE<_Record,_Key>::FindNodeInternal(
|
||||
_Key key,
|
||||
DWORD dwHash,
|
||||
__deref_out
|
||||
HASH_NODE<_Record> ** ppNode,
|
||||
__deref_opt_out
|
||||
HASH_NODE<_Record> *** pppPreviousNodeNextPointer
|
||||
)
|
||||
/*++
|
||||
Return value indicates whether the item is found
|
||||
key, dwHash - key and hash for the node to find
|
||||
ppNode - on successful return, the node found, on failed return, the first
|
||||
node with hash value greater than the node to be found
|
||||
pppPreviousNodeNextPointer - the pointer to previous node's _pNext
|
||||
|
||||
This routine may be called under either read or write lock
|
||||
--*/
|
||||
{
|
||||
HASH_NODE<_Record> **ppPreviousNodeNextPointer;
|
||||
HASH_NODE<_Record> *pNode;
|
||||
BOOL fFound = FALSE;
|
||||
|
||||
ppPreviousNodeNextPointer = _ppBuckets + (dwHash % _nBuckets);
|
||||
pNode = *ppPreviousNodeNextPointer;
|
||||
while (pNode != NULL)
|
||||
{
|
||||
if (pNode->_dwHash == dwHash)
|
||||
{
|
||||
if (EqualKeys(key,
|
||||
ExtractKey(pNode->_pRecord)))
|
||||
{
|
||||
fFound = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (pNode->_dwHash > dwHash)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
ppPreviousNodeNextPointer = &(pNode->_pNext);
|
||||
pNode = *ppPreviousNodeNextPointer;
|
||||
}
|
||||
|
||||
__analysis_assume( (pNode == NULL && fFound == FALSE) ||
|
||||
(pNode != NULL && fFound == TRUE ) );
|
||||
*ppNode = pNode;
|
||||
if (pppPreviousNodeNextPointer != NULL)
|
||||
{
|
||||
*pppPreviousNodeNextPointer = ppPreviousNodeNextPointer;
|
||||
}
|
||||
return fFound;
|
||||
}
|
||||
|
||||
template <class _Record, class _Key>
|
||||
VOID
|
||||
HASH_TABLE<_Record,_Key>::FindKey(
|
||||
_Key key,
|
||||
_Record ** ppRecord
|
||||
)
|
||||
{
|
||||
HASH_NODE<_Record> *pNode;
|
||||
|
||||
*ppRecord = NULL;
|
||||
|
||||
DWORD dwHash = CalcKeyHash(key);
|
||||
|
||||
_tableLock.SharedAcquire();
|
||||
|
||||
if (FindNodeInternal(key, dwHash, &pNode) &&
|
||||
pNode->_pRecord != NULL)
|
||||
{
|
||||
ReferenceRecord(pNode->_pRecord);
|
||||
*ppRecord = pNode->_pRecord;
|
||||
}
|
||||
|
||||
_tableLock.SharedRelease();
|
||||
}
|
||||
|
||||
template <class _Record, class _Key>
|
||||
HRESULT
|
||||
HASH_TABLE<_Record,_Key>::InsertRecord(
|
||||
_Record * pRecord
|
||||
)
|
||||
/*++
|
||||
This method inserts a node for this record and also empty nodes for paths
|
||||
in the heirarchy leading upto this path
|
||||
|
||||
The insert is done under only a read-lock - this is possible by keeping
|
||||
the hashes in a bucket in increasing order and using interlocked operations
|
||||
to actually insert the item in the hash-bucket lookaside list and the parent
|
||||
children list
|
||||
|
||||
Returns HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS) if the record already exists.
|
||||
Never leak this error to the end user because "*file* already exists" may be confusing.
|
||||
--*/
|
||||
{
|
||||
BOOL fLocked = FALSE;
|
||||
_Key key = ExtractKey(pRecord);
|
||||
DWORD dwHash = CalcKeyHash(key);
|
||||
HRESULT hr = S_OK;
|
||||
HASH_NODE<_Record> * pNewNode;
|
||||
HASH_NODE<_Record> * pNextNode;
|
||||
HASH_NODE<_Record> ** ppPreviousNodeNextPointer;
|
||||
|
||||
//
|
||||
// Ownership of pRecord is not transferred to pNewNode yet, so remember
|
||||
// to either set it to null before deleting pNewNode or add an extra
|
||||
// reference later - this is to make sure we do not do an extra ref/deref
|
||||
// which users may view as getting flushed out of the hash-table
|
||||
//
|
||||
pNewNode = new HASH_NODE<_Record>(pRecord, dwHash);
|
||||
if (pNewNode == NULL)
|
||||
{
|
||||
hr = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
_tableLock.SharedAcquire();
|
||||
fLocked = TRUE;
|
||||
|
||||
do
|
||||
{
|
||||
//
|
||||
// Find the right place to add this node
|
||||
//
|
||||
if (FindNodeInternal(key, dwHash, &pNextNode, &ppPreviousNodeNextPointer))
|
||||
{
|
||||
//
|
||||
// If node already there, return error
|
||||
//
|
||||
pNewNode->_pRecord = NULL;
|
||||
DeleteNode(pNewNode);
|
||||
|
||||
//
|
||||
// We should never leak this error to the end user
|
||||
// because "file already exists" may be confusing.
|
||||
//
|
||||
hr = HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS);
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
//
|
||||
// If another node got inserted in between, we will have to retry
|
||||
//
|
||||
pNewNode->_pNext = pNextNode;
|
||||
} while (InterlockedCompareExchangePointer((PVOID *)ppPreviousNodeNextPointer,
|
||||
pNewNode,
|
||||
pNextNode) != pNextNode);
|
||||
// pass ownership of pRecord now
|
||||
if (pRecord != NULL)
|
||||
{
|
||||
ReferenceRecord(pRecord);
|
||||
pRecord = NULL;
|
||||
}
|
||||
InterlockedIncrement((LONG *)&_nItems);
|
||||
|
||||
Finished:
|
||||
|
||||
if (fLocked)
|
||||
{
|
||||
_tableLock.SharedRelease();
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
RehashTableIfNeeded();
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
template <class _Record, class _Key>
|
||||
VOID
|
||||
HASH_TABLE<_Record,_Key>::DeleteKey(
|
||||
_Key key
|
||||
)
|
||||
{
|
||||
HASH_NODE<_Record> *pNode;
|
||||
HASH_NODE<_Record> **ppPreviousNodeNextPointer;
|
||||
|
||||
DWORD dwHash = CalcKeyHash(key);
|
||||
|
||||
_tableLock.ExclusiveAcquire();
|
||||
|
||||
if (FindNodeInternal(key, dwHash, &pNode, &ppPreviousNodeNextPointer))
|
||||
{
|
||||
*ppPreviousNodeNextPointer = pNode->_pNext;
|
||||
DeleteNode(pNode);
|
||||
_nItems--;
|
||||
}
|
||||
|
||||
_tableLock.ExclusiveRelease();
|
||||
}
|
||||
|
||||
template <class _Record, class _Key>
|
||||
VOID
|
||||
HASH_TABLE<_Record,_Key>::DeleteIf(
|
||||
PFN_DELETE_IF pfnDeleteIf,
|
||||
PVOID pvContext
|
||||
)
|
||||
{
|
||||
HASH_NODE<_Record> *pNode;
|
||||
HASH_NODE<_Record> **ppPreviousNodeNextPointer;
|
||||
|
||||
_tableLock.ExclusiveAcquire();
|
||||
|
||||
for (DWORD i=0; i<_nBuckets; i++)
|
||||
{
|
||||
ppPreviousNodeNextPointer = _ppBuckets + i;
|
||||
pNode = *ppPreviousNodeNextPointer;
|
||||
while (pNode != NULL)
|
||||
{
|
||||
//
|
||||
// Non empty nodes deleted based on DeleteIf, empty nodes deleted
|
||||
// if they have no children
|
||||
//
|
||||
if (pfnDeleteIf(pNode->_pRecord, pvContext))
|
||||
{
|
||||
*ppPreviousNodeNextPointer = pNode->_pNext;
|
||||
DeleteNode(pNode);
|
||||
_nItems--;
|
||||
}
|
||||
else
|
||||
{
|
||||
ppPreviousNodeNextPointer = &pNode->_pNext;
|
||||
}
|
||||
|
||||
pNode = *ppPreviousNodeNextPointer;
|
||||
}
|
||||
}
|
||||
|
||||
_tableLock.ExclusiveRelease();
|
||||
}
|
||||
|
||||
template <class _Record, class _Key>
|
||||
VOID
|
||||
HASH_TABLE<_Record,_Key>::Apply(
|
||||
PFN_APPLY pfnApply,
|
||||
PVOID pvContext
|
||||
)
|
||||
{
|
||||
HASH_NODE<_Record> *pNode;
|
||||
|
||||
_tableLock.SharedAcquire();
|
||||
|
||||
for (DWORD i=0; i<_nBuckets; i++)
|
||||
{
|
||||
pNode = _ppBuckets[i];
|
||||
while (pNode != NULL)
|
||||
{
|
||||
if (pNode->_pRecord != NULL)
|
||||
{
|
||||
pfnApply(pNode->_pRecord, pvContext);
|
||||
}
|
||||
|
||||
pNode = pNode->_pNext;
|
||||
}
|
||||
}
|
||||
|
||||
_tableLock.SharedRelease();
|
||||
}
|
||||
|
||||
template <class _Record, class _Key>
|
||||
VOID
|
||||
HASH_TABLE<_Record,_Key>::RehashTableIfNeeded(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
HASH_NODE<_Record> **ppBuckets;
|
||||
DWORD nBuckets;
|
||||
HASH_NODE<_Record> *pNode;
|
||||
HASH_NODE<_Record> *pNextNode;
|
||||
HASH_NODE<_Record> **ppNextPointer;
|
||||
HASH_NODE<_Record> *pNewNextNode;
|
||||
DWORD nNewBuckets;
|
||||
|
||||
//
|
||||
// If number of items has become too many, we will double the hash table
|
||||
// size (we never reduce it however)
|
||||
//
|
||||
if (_nItems <= PRIME::GetPrime(2*_nBuckets))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_tableLock.ExclusiveAcquire();
|
||||
|
||||
nNewBuckets = PRIME::GetPrime(2*_nBuckets);
|
||||
|
||||
if (_nItems <= nNewBuckets)
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
nBuckets = nNewBuckets;
|
||||
if (nBuckets >= 0xffffffff/sizeof(HASH_NODE<_Record> *))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
ppBuckets = (HASH_NODE<_Record> **)HeapAlloc(
|
||||
GetProcessHeap(),
|
||||
HEAP_ZERO_MEMORY,
|
||||
nBuckets*sizeof(HASH_NODE<_Record> *));
|
||||
if (ppBuckets == NULL)
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
//
|
||||
// Take out nodes from the old hash table and insert in the new one, make
|
||||
// sure to keep the hashes in increasing order
|
||||
//
|
||||
for (DWORD i=0; i<_nBuckets; i++)
|
||||
{
|
||||
pNode = _ppBuckets[i];
|
||||
while (pNode != NULL)
|
||||
{
|
||||
pNextNode = pNode->_pNext;
|
||||
|
||||
ppNextPointer = ppBuckets + (pNode->_dwHash % nBuckets);
|
||||
pNewNextNode = *ppNextPointer;
|
||||
while (pNewNextNode != NULL &&
|
||||
pNewNextNode->_dwHash <= pNode->_dwHash)
|
||||
{
|
||||
ppNextPointer = &pNewNextNode->_pNext;
|
||||
pNewNextNode = pNewNextNode->_pNext;
|
||||
}
|
||||
pNode->_pNext = pNewNextNode;
|
||||
*ppNextPointer = pNode;
|
||||
|
||||
pNode = pNextNode;
|
||||
}
|
||||
}
|
||||
|
||||
HeapFree(GetProcessHeap(), 0, _ppBuckets);
|
||||
_ppBuckets = ppBuckets;
|
||||
_nBuckets = nBuckets;
|
||||
ppBuckets = NULL;
|
||||
|
||||
Finished:
|
||||
|
||||
_tableLock.ExclusiveRelease();
|
||||
}
|
||||
|
|
@ -0,0 +1,163 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef _LIST_ENTRY_H
|
||||
#define _LIST_ENTRY_H
|
||||
|
||||
//
|
||||
// Doubly-linked list manipulation routines.
|
||||
//
|
||||
|
||||
|
||||
#define InitializeListHead32(ListHead) (\
|
||||
(ListHead)->Flink = (ListHead)->Blink = PtrToUlong((ListHead)))
|
||||
|
||||
|
||||
FORCEINLINE
|
||||
VOID
|
||||
InitializeListHead(
|
||||
IN PLIST_ENTRY ListHead
|
||||
)
|
||||
{
|
||||
ListHead->Flink = ListHead->Blink = ListHead;
|
||||
}
|
||||
|
||||
FORCEINLINE
|
||||
BOOLEAN
|
||||
IsListEmpty(
|
||||
IN const LIST_ENTRY * ListHead
|
||||
)
|
||||
{
|
||||
return (BOOLEAN)(ListHead->Flink == ListHead);
|
||||
}
|
||||
|
||||
FORCEINLINE
|
||||
BOOLEAN
|
||||
RemoveEntryList(
|
||||
IN PLIST_ENTRY Entry
|
||||
)
|
||||
{
|
||||
PLIST_ENTRY Blink;
|
||||
PLIST_ENTRY Flink;
|
||||
|
||||
Flink = Entry->Flink;
|
||||
Blink = Entry->Blink;
|
||||
Blink->Flink = Flink;
|
||||
Flink->Blink = Blink;
|
||||
return (BOOLEAN)(Flink == Blink);
|
||||
}
|
||||
|
||||
FORCEINLINE
|
||||
PLIST_ENTRY
|
||||
RemoveHeadList(
|
||||
IN PLIST_ENTRY ListHead
|
||||
)
|
||||
{
|
||||
PLIST_ENTRY Flink;
|
||||
PLIST_ENTRY Entry;
|
||||
|
||||
Entry = ListHead->Flink;
|
||||
Flink = Entry->Flink;
|
||||
ListHead->Flink = Flink;
|
||||
Flink->Blink = ListHead;
|
||||
return Entry;
|
||||
}
|
||||
|
||||
|
||||
|
||||
FORCEINLINE
|
||||
PLIST_ENTRY
|
||||
RemoveTailList(
|
||||
IN PLIST_ENTRY ListHead
|
||||
)
|
||||
{
|
||||
PLIST_ENTRY Blink;
|
||||
PLIST_ENTRY Entry;
|
||||
|
||||
Entry = ListHead->Blink;
|
||||
Blink = Entry->Blink;
|
||||
ListHead->Blink = Blink;
|
||||
Blink->Flink = ListHead;
|
||||
return Entry;
|
||||
}
|
||||
|
||||
|
||||
FORCEINLINE
|
||||
VOID
|
||||
InsertTailList(
|
||||
IN PLIST_ENTRY ListHead,
|
||||
IN PLIST_ENTRY Entry
|
||||
)
|
||||
{
|
||||
PLIST_ENTRY Blink;
|
||||
|
||||
Blink = ListHead->Blink;
|
||||
Entry->Flink = ListHead;
|
||||
Entry->Blink = Blink;
|
||||
Blink->Flink = Entry;
|
||||
ListHead->Blink = Entry;
|
||||
}
|
||||
|
||||
|
||||
FORCEINLINE
|
||||
VOID
|
||||
InsertHeadList(
|
||||
IN PLIST_ENTRY ListHead,
|
||||
IN PLIST_ENTRY Entry
|
||||
)
|
||||
{
|
||||
PLIST_ENTRY Flink;
|
||||
|
||||
Flink = ListHead->Flink;
|
||||
Entry->Flink = Flink;
|
||||
Entry->Blink = ListHead;
|
||||
Flink->Blink = Entry;
|
||||
ListHead->Flink = Entry;
|
||||
}
|
||||
|
||||
FORCEINLINE
|
||||
VOID
|
||||
AppendTailList(
|
||||
IN PLIST_ENTRY ListHead,
|
||||
IN PLIST_ENTRY ListToAppend
|
||||
)
|
||||
{
|
||||
PLIST_ENTRY ListEnd = ListHead->Blink;
|
||||
|
||||
ListHead->Blink->Flink = ListToAppend;
|
||||
ListHead->Blink = ListToAppend->Blink;
|
||||
ListToAppend->Blink->Flink = ListHead;
|
||||
ListToAppend->Blink = ListEnd;
|
||||
}
|
||||
|
||||
FORCEINLINE
|
||||
PSINGLE_LIST_ENTRY
|
||||
PopEntryList(
|
||||
PSINGLE_LIST_ENTRY ListHead
|
||||
)
|
||||
{
|
||||
PSINGLE_LIST_ENTRY FirstEntry;
|
||||
FirstEntry = ListHead->Next;
|
||||
if (FirstEntry != NULL) {
|
||||
ListHead->Next = FirstEntry->Next;
|
||||
}
|
||||
|
||||
return FirstEntry;
|
||||
}
|
||||
|
||||
|
||||
FORCEINLINE
|
||||
VOID
|
||||
PushEntryList(
|
||||
PSINGLE_LIST_ENTRY ListHead,
|
||||
PSINGLE_LIST_ENTRY Entry
|
||||
)
|
||||
{
|
||||
Entry->Next = ListHead->Next;
|
||||
ListHead->Next = Entry;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
#ifndef _MACROS_H
|
||||
#define _MACROS_H
|
||||
|
||||
//
|
||||
// The DIFF macro should be used around an expression involving pointer
|
||||
// subtraction. The expression passed to DIFF is cast to a size_t type,
|
||||
// allowing the result to be easily assigned to any 32-bit variable or
|
||||
// passed to a function expecting a 32-bit argument.
|
||||
//
|
||||
|
||||
#define DIFF(x) ((size_t)(x))
|
||||
|
||||
// Change a hexadecimal digit to its numerical equivalent
|
||||
#define TOHEX( ch ) \
|
||||
((ch) > L'9' ? \
|
||||
(ch) >= L'a' ? \
|
||||
(ch) - L'a' + 10 : \
|
||||
(ch) - L'A' + 10 \
|
||||
: (ch) - L'0')
|
||||
|
||||
|
||||
// Change a number to its Hexadecimal equivalent
|
||||
|
||||
#define TODIGIT( nDigit ) \
|
||||
(CHAR)((nDigit) > 9 ? \
|
||||
(nDigit) - 10 + 'A' \
|
||||
: (nDigit) + '0')
|
||||
|
||||
|
||||
inline int
|
||||
SAFEIsSpace(UCHAR c)
|
||||
{
|
||||
return isspace( c );
|
||||
}
|
||||
|
||||
inline int
|
||||
SAFEIsAlNum(UCHAR c)
|
||||
{
|
||||
return isalnum( c );
|
||||
}
|
||||
|
||||
inline int
|
||||
SAFEIsAlpha(UCHAR c)
|
||||
{
|
||||
return isalpha( c );
|
||||
}
|
||||
|
||||
inline int
|
||||
SAFEIsXDigit(UCHAR c)
|
||||
{
|
||||
return isxdigit( c );
|
||||
}
|
||||
|
||||
inline int
|
||||
SAFEIsDigit(UCHAR c)
|
||||
{
|
||||
return isdigit( c );
|
||||
}
|
||||
|
||||
#endif // _MACROS_H
|
||||
|
|
@ -0,0 +1,474 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
|
||||
#pragma warning (disable : 4267)
|
||||
|
||||
#include "precomp.h"
|
||||
#include "multisz.h"
|
||||
#include <tchar.h>
|
||||
|
||||
//
|
||||
// Private Definitions
|
||||
//
|
||||
|
||||
#define MAXULONG 4294967295
|
||||
#define ISWHITE( ch ) ((ch) == L' ' || (ch) == L'\t' || (ch) == L'\r')
|
||||
|
||||
//
|
||||
// When appending data, this is the extra amount we request to avoid
|
||||
// reallocations
|
||||
//
|
||||
#define STR_SLOP 128
|
||||
|
||||
|
||||
DWORD
|
||||
MULTISZ::CalcLength( const WCHAR * str,
|
||||
LPDWORD pcStrings )
|
||||
{
|
||||
DWORD count = 0;
|
||||
DWORD total = 1;
|
||||
DWORD len;
|
||||
|
||||
while( *str ) {
|
||||
len = ::wcslen( str ) + 1;
|
||||
total += len;
|
||||
str += len;
|
||||
count++;
|
||||
}
|
||||
|
||||
if( pcStrings != NULL ) {
|
||||
*pcStrings = count;
|
||||
}
|
||||
|
||||
return total;
|
||||
|
||||
} // MULTISZ::CalcLength
|
||||
|
||||
|
||||
BOOL
|
||||
MULTISZ::FindString( const WCHAR * str )
|
||||
{
|
||||
|
||||
WCHAR * multisz;
|
||||
|
||||
//
|
||||
// Sanity check.
|
||||
//
|
||||
|
||||
DBG_ASSERT( QueryStr() != NULL );
|
||||
DBG_ASSERT( str != NULL );
|
||||
DBG_ASSERT( *str != '\0' );
|
||||
|
||||
//
|
||||
// Scan it.
|
||||
//
|
||||
|
||||
multisz = QueryStr();
|
||||
|
||||
while( *multisz != '\0' ) {
|
||||
|
||||
if( !::wcscmp( multisz, str ) ) {
|
||||
|
||||
return TRUE;
|
||||
|
||||
}
|
||||
|
||||
multisz += ::wcslen( multisz ) + 1;
|
||||
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
|
||||
} // MULTISZ::FindString
|
||||
|
||||
|
||||
BOOL
|
||||
MULTISZ::FindStringNoCase( const WCHAR * str )
|
||||
{
|
||||
|
||||
WCHAR * multisz;
|
||||
|
||||
//
|
||||
// Sanity check.
|
||||
//
|
||||
|
||||
DBG_ASSERT( QueryStr() != NULL );
|
||||
DBG_ASSERT( str != NULL );
|
||||
DBG_ASSERT( *str != '\0' );
|
||||
|
||||
//
|
||||
// Scan it.
|
||||
//
|
||||
|
||||
multisz = QueryStr();
|
||||
|
||||
while( *multisz != '\0' ) {
|
||||
|
||||
if( !_wcsicmp( multisz, str ) ) {
|
||||
|
||||
return TRUE;
|
||||
|
||||
}
|
||||
|
||||
multisz += wcslen( multisz ) + 1;
|
||||
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
|
||||
} // MULTISZ::FindStringNoCase
|
||||
|
||||
|
||||
VOID
|
||||
MULTISZ::AuxInit( const WCHAR * pInit )
|
||||
{
|
||||
BOOL fRet;
|
||||
|
||||
if ( pInit )
|
||||
{
|
||||
DWORD cStrings;
|
||||
int cbCopy = CalcLength( pInit, &cStrings ) * sizeof(WCHAR);
|
||||
fRet = Resize( cbCopy );
|
||||
|
||||
if ( fRet ) {
|
||||
CopyMemory( QueryPtr(), pInit, cbCopy );
|
||||
m_cchLen = (cbCopy)/sizeof(WCHAR);
|
||||
m_cStrings = cStrings;
|
||||
} else {
|
||||
// BUFFER::SetValid( FALSE);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
Reset();
|
||||
|
||||
}
|
||||
|
||||
} // MULTISZ::AuxInit()
|
||||
|
||||
|
||||
/*******************************************************************
|
||||
|
||||
NAME: MULTISZ::AuxAppend
|
||||
|
||||
SYNOPSIS: Appends the string onto the multisz.
|
||||
|
||||
ENTRY: Object to append
|
||||
********************************************************************/
|
||||
|
||||
BOOL MULTISZ::AuxAppend( const WCHAR * pStr, UINT cbStr, BOOL fAddSlop )
|
||||
{
|
||||
DBG_ASSERT( pStr != NULL );
|
||||
|
||||
UINT cbThis = QueryCB();
|
||||
|
||||
DBG_ASSERT( cbThis >= 2 );
|
||||
|
||||
if( cbThis == 4 ) {
|
||||
|
||||
//
|
||||
// It's empty, so start at the beginning.
|
||||
//
|
||||
|
||||
cbThis = 0;
|
||||
|
||||
} else {
|
||||
|
||||
//
|
||||
// It's not empty, so back up over the final terminating NULL.
|
||||
//
|
||||
|
||||
cbThis -= sizeof(WCHAR);
|
||||
|
||||
}
|
||||
|
||||
//
|
||||
// Only resize when we have to. When we do resize, we tack on
|
||||
// some extra space to avoid extra reallocations.
|
||||
//
|
||||
// Note: QuerySize returns the requested size of the string buffer,
|
||||
// *not* the strlen of the buffer
|
||||
//
|
||||
|
||||
//AcIncrement( CacMultiszAppend);
|
||||
|
||||
//
|
||||
// Check for the arithmetic overflow
|
||||
//
|
||||
// ( 2 * sizeof( WCHAR ) ) is for the double terminator
|
||||
//
|
||||
ULONGLONG cb64Required = (ULONGLONG)cbThis + cbStr + 2 * sizeof(WCHAR);
|
||||
if ( cb64Required > MAXULONG )
|
||||
{
|
||||
SetLastError( ERROR_ARITHMETIC_OVERFLOW );
|
||||
return FALSE;
|
||||
}
|
||||
if ( QuerySize() < (DWORD) cb64Required )
|
||||
{
|
||||
ULONGLONG cb64AllocSize = cb64Required + (fAddSlop ? STR_SLOP : 0 );
|
||||
//
|
||||
// Check for the arithmetic overflow
|
||||
//
|
||||
if ( cb64AllocSize > MAXULONG )
|
||||
{
|
||||
SetLastError( ERROR_ARITHMETIC_OVERFLOW );
|
||||
return FALSE;
|
||||
}
|
||||
if ( !Resize( (DWORD) cb64AllocSize ) )
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// copy the exact string and tack on the double terminator
|
||||
memcpy( (BYTE *) QueryPtr() + cbThis,
|
||||
pStr,
|
||||
cbStr);
|
||||
*(WCHAR *)((BYTE *)QueryPtr() + cbThis + cbStr) = L'\0';
|
||||
*(WCHAR *)((BYTE *)QueryPtr() + cbThis + cbStr + sizeof(WCHAR) ) = L'\0';
|
||||
|
||||
m_cchLen = CalcLength( (const WCHAR *)QueryPtr(), &m_cStrings );
|
||||
return TRUE;
|
||||
|
||||
} // MULTISZ::AuxAppend()
|
||||
|
||||
|
||||
#if 0
|
||||
|
||||
BOOL
|
||||
MULTISZ::CopyToBuffer( WCHAR * lpszBuffer, LPDWORD lpcch) const
|
||||
/*++
|
||||
Description:
|
||||
Copies the string into the WCHAR buffer passed in if the buffer
|
||||
is sufficient to hold the translated string.
|
||||
If the buffer is small, the function returns small and sets *lpcch
|
||||
to contain the required number of characters.
|
||||
|
||||
Arguments:
|
||||
lpszBuffer pointer to WCHAR buffer which on return contains
|
||||
the UNICODE version of string on success.
|
||||
lpcch pointer to DWORD containing the length of the buffer.
|
||||
If *lpcch == 0 then the function returns TRUE with
|
||||
the count of characters required stored in *lpcch.
|
||||
Also in this case lpszBuffer is not affected.
|
||||
Returns:
|
||||
TRUE on success.
|
||||
FALSE on failure. Use GetLastError() for further details.
|
||||
--*/
|
||||
{
|
||||
BOOL fReturn = TRUE;
|
||||
|
||||
if ( lpcch == NULL) {
|
||||
SetLastError( ERROR_INVALID_PARAMETER);
|
||||
return ( FALSE);
|
||||
}
|
||||
|
||||
if ( *lpcch == 0) {
|
||||
|
||||
//
|
||||
// Inquiring the size of buffer alone
|
||||
//
|
||||
*lpcch = QueryCCH() + 1; // add one character for terminating null
|
||||
} else {
|
||||
|
||||
//
|
||||
// Copy after conversion from ANSI to Unicode
|
||||
//
|
||||
int iRet;
|
||||
iRet = MultiByteToWideChar( CP_ACP,
|
||||
MB_PRECOMPOSED | MB_ERR_INVALID_CHARS,
|
||||
QueryStrA(), QueryCCH() + 1,
|
||||
lpszBuffer, (int )*lpcch);
|
||||
|
||||
if ( iRet == 0 || iRet != (int ) *lpcch) {
|
||||
|
||||
//
|
||||
// Error in conversion.
|
||||
//
|
||||
fReturn = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return ( fReturn);
|
||||
} // MULTISZ::CopyToBuffer()
|
||||
#endif
|
||||
|
||||
BOOL
|
||||
MULTISZ::CopyToBuffer( __out_ecount_opt(*lpcch) WCHAR * lpszBuffer, LPDWORD lpcch) const
|
||||
/*++
|
||||
Description:
|
||||
Copies the string into the WCHAR buffer passed in if the buffer
|
||||
is sufficient to hold the translated string.
|
||||
If the buffer is small, the function returns small and sets *lpcch
|
||||
to contain the required number of characters.
|
||||
|
||||
Arguments:
|
||||
lpszBuffer pointer to WCHAR buffer which on return contains
|
||||
the string on success.
|
||||
lpcch pointer to DWORD containing the length of the buffer.
|
||||
If *lpcch == 0 then the function returns TRUE with
|
||||
the count of characters required stored in lpcch.
|
||||
Also in this case lpszBuffer is not affected.
|
||||
Returns:
|
||||
TRUE on success.
|
||||
FALSE on failure. Use GetLastError() for further details.
|
||||
--*/
|
||||
{
|
||||
BOOL fReturn = TRUE;
|
||||
|
||||
if ( lpcch == NULL) {
|
||||
SetLastError( ERROR_INVALID_PARAMETER);
|
||||
return ( FALSE);
|
||||
}
|
||||
|
||||
register DWORD cch = QueryCCH();
|
||||
|
||||
if ( *lpcch >= cch) {
|
||||
|
||||
DBG_ASSERT( lpszBuffer);
|
||||
memcpy( lpszBuffer, QueryStr(), cch * sizeof(WCHAR));
|
||||
} else {
|
||||
DBG_ASSERT( *lpcch < cch);
|
||||
SetLastError( ERROR_INSUFFICIENT_BUFFER);
|
||||
fReturn = FALSE;
|
||||
}
|
||||
|
||||
*lpcch = cch;
|
||||
|
||||
return ( fReturn);
|
||||
} // MULTISZ::CopyToBuffer()
|
||||
|
||||
BOOL
|
||||
MULTISZ::Equals(
|
||||
MULTISZ* pmszRhs
|
||||
)
|
||||
//
|
||||
// Compares this to pmszRhs, returns TRUE if equal
|
||||
//
|
||||
{
|
||||
DBG_ASSERT( NULL != pmszRhs );
|
||||
|
||||
PCWSTR pszLhs = First( );
|
||||
PCWSTR pszRhs = pmszRhs->First( );
|
||||
|
||||
if( m_cStrings != pmszRhs->m_cStrings )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
while( NULL != pszLhs )
|
||||
{
|
||||
DBG_ASSERT( NULL != pszRhs );
|
||||
|
||||
if( 0 != wcscmp( pszLhs, pszRhs ) )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
pszLhs = Next( pszLhs );
|
||||
pszRhs = pmszRhs->Next( pszRhs );
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
SplitCommaDelimitedString(
|
||||
PCWSTR pszList,
|
||||
BOOL fTrimEntries,
|
||||
BOOL fRemoveEmptyEntries,
|
||||
MULTISZ * pmszList
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Split comma delimited string into a multisz. Additional leading empty
|
||||
entries after the first are discarded.
|
||||
|
||||
Arguments:
|
||||
|
||||
pszList - List to split up
|
||||
fTrimEntries - Whether each entry should be trimmed before added to multisz
|
||||
fRemoveEmptyEntries - Whether empty entires should be discarded
|
||||
pmszList - Filled with MULTISZ list
|
||||
|
||||
Return Value:
|
||||
|
||||
HRESULT
|
||||
|
||||
--*/
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
if ( pszList == NULL ||
|
||||
pmszList == NULL )
|
||||
{
|
||||
DBG_ASSERT( FALSE );
|
||||
hr = HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
pmszList->Reset();
|
||||
|
||||
/*
|
||||
pszCurrent: start of the current entry which may be the comma that
|
||||
precedes the next entry if the entry is empty
|
||||
|
||||
pszNext: the comma that precedes the next entry. If
|
||||
pszCurrent == pszNext, then the entry is empty
|
||||
|
||||
pszEnd: just past the end of the current entry
|
||||
*/
|
||||
|
||||
for ( PCWSTR pszCurrent = pszList,
|
||||
pszNext = wcschr( pszCurrent, L',' )
|
||||
;
|
||||
;
|
||||
pszCurrent = pszNext + 1,
|
||||
pszNext = wcschr( pszCurrent, L',' ) )
|
||||
{
|
||||
PCWSTR pszEnd = NULL;
|
||||
|
||||
if ( pszNext != NULL )
|
||||
{
|
||||
pszEnd = pszNext;
|
||||
}
|
||||
else
|
||||
{
|
||||
pszEnd = pszCurrent + wcslen( pszCurrent );
|
||||
}
|
||||
|
||||
if ( fTrimEntries )
|
||||
{
|
||||
while ( pszCurrent < pszEnd && ISWHITE( pszCurrent[ 0 ] ) )
|
||||
{
|
||||
pszCurrent++;
|
||||
}
|
||||
|
||||
while ( pszEnd > pszCurrent && ISWHITE( pszEnd[ -1 ] ) )
|
||||
{
|
||||
pszEnd--;
|
||||
}
|
||||
}
|
||||
|
||||
if ( pszCurrent != pszEnd || !fRemoveEmptyEntries )
|
||||
{
|
||||
if ( !pmszList->Append( pszCurrent, (DWORD) ( pszEnd - pszCurrent ) ) )
|
||||
{
|
||||
hr = HRESULT_FROM_WIN32( GetLastError() );
|
||||
goto Finished;
|
||||
}
|
||||
}
|
||||
|
||||
if ( pszNext == NULL )
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Finished:
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
#pragma warning(default:4267)
|
||||
|
|
@ -0,0 +1,225 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
#ifndef _MULTISZ_H_
|
||||
#define _MULTISZ_H_
|
||||
|
||||
#include "stringu.h"
|
||||
#include "ntassert.h"
|
||||
|
||||
/*++
|
||||
class MULTISZ:
|
||||
|
||||
Intention:
|
||||
A light-weight multi-string class supporting encapsulated string class.
|
||||
|
||||
This object is derived from BUFFER class.
|
||||
It maintains following state:
|
||||
|
||||
m_fValid - whether this object is valid -
|
||||
used only by MULTISZ() init functions
|
||||
* NYI: I need to kill this someday *
|
||||
m_cchLen - string length cached when we update the string.
|
||||
m_cStrings - number of strings.
|
||||
|
||||
Member Functions:
|
||||
There are two categories of functions:
|
||||
1) Safe Functions - which do integrity checking of state
|
||||
2) UnSafe Functions - which do not do integrity checking, but
|
||||
enable writing to the data stream freely.
|
||||
(someday this will be enabled as Safe versions without
|
||||
problem for users)
|
||||
|
||||
--*/
|
||||
class MULTISZ : public BUFFER
|
||||
{
|
||||
public:
|
||||
|
||||
MULTISZ()
|
||||
: BUFFER (),
|
||||
m_cchLen ( 0),
|
||||
m_cStrings(0)
|
||||
{ Reset(); }
|
||||
|
||||
// creates a stack version of the MULTISZ object - uses passed in stack buffer
|
||||
// MULTISZ does not free this pbInit on its own.
|
||||
MULTISZ( __in_bcount(cbInit) WCHAR * pbInit, DWORD cbInit)
|
||||
: BUFFER( (BYTE *) pbInit, cbInit),
|
||||
m_cchLen (0),
|
||||
m_cStrings(0)
|
||||
{}
|
||||
|
||||
MULTISZ( const WCHAR * pchInit )
|
||||
: BUFFER (),
|
||||
m_cchLen ( 0),
|
||||
m_cStrings(0)
|
||||
{ AuxInit(pchInit); }
|
||||
|
||||
MULTISZ( const MULTISZ & str )
|
||||
: BUFFER (),
|
||||
m_cchLen ( 0),
|
||||
m_cStrings(0)
|
||||
{ AuxInit( str.QueryStr()); }
|
||||
|
||||
// BOOL IsValid(VOID) const { return ( BUFFER::IsValid()) ; }
|
||||
//
|
||||
// Checks and returns TRUE if this string has no valid data else FALSE
|
||||
//
|
||||
BOOL IsEmpty( VOID) const { return ( *QueryStr() == L'\0'); }
|
||||
|
||||
BOOL Append( const WCHAR * pchInit ) {
|
||||
return ((pchInit != NULL) ? (AuxAppend( pchInit,
|
||||
(DWORD) (::wcslen(pchInit)) * sizeof(WCHAR)
|
||||
)) :
|
||||
TRUE);
|
||||
}
|
||||
|
||||
|
||||
BOOL Append( const WCHAR * pchInit, DWORD cchLen ) {
|
||||
return ((pchInit != NULL) ? (AuxAppend( pchInit,
|
||||
cchLen * sizeof(WCHAR))) :
|
||||
TRUE);
|
||||
}
|
||||
|
||||
BOOL Append( STRU & str )
|
||||
{ return AuxAppend( str.QueryStr(),
|
||||
(str.QueryCCH()) * sizeof(WCHAR)); }
|
||||
|
||||
// Resets the internal string to be NULL string. Buffer remains cached.
|
||||
VOID Reset( VOID)
|
||||
{ DBG_ASSERT( QueryPtr() != NULL);
|
||||
QueryStr()[0] = L'\0';
|
||||
QueryStr()[1] = L'\0';
|
||||
m_cchLen = 2;
|
||||
m_cStrings = 0;
|
||||
}
|
||||
|
||||
BOOL Copy( const WCHAR * pchInit, IN DWORD cbLen ) {
|
||||
if ( QueryPtr() ) { Reset(); }
|
||||
return ( (pchInit != NULL) ?
|
||||
AuxAppend( pchInit, cbLen, FALSE ):
|
||||
TRUE);
|
||||
}
|
||||
|
||||
BOOL Copy( const MULTISZ & str )
|
||||
{ return ( Copy(str.QueryStr(), str.QueryCB())); }
|
||||
|
||||
//
|
||||
// Returns the number of bytes in the string including the terminating
|
||||
// NULLs
|
||||
//
|
||||
UINT QueryCB( VOID ) const
|
||||
{ return ( m_cchLen * sizeof(WCHAR)); }
|
||||
|
||||
//
|
||||
// Returns # of characters in the string including the terminating NULLs
|
||||
//
|
||||
UINT QueryCCH( VOID ) const { return (m_cchLen); }
|
||||
|
||||
//
|
||||
// Returns # of strings in the multisz.
|
||||
//
|
||||
|
||||
DWORD QueryStringCount( VOID ) const { return m_cStrings; }
|
||||
|
||||
//
|
||||
// Makes a copy of the stored string in given buffer
|
||||
//
|
||||
BOOL CopyToBuffer( __out_ecount_opt(*lpcch) WCHAR * lpszBuffer, LPDWORD lpcch) const;
|
||||
|
||||
//
|
||||
// Return the string buffer
|
||||
//
|
||||
WCHAR * QueryStrA( VOID ) const { return ( QueryStr()); }
|
||||
WCHAR * QueryStr( VOID ) const { return ((WCHAR *) QueryPtr()); }
|
||||
|
||||
//
|
||||
// Makes a clone of the current string in the string pointer passed in.
|
||||
//
|
||||
BOOL
|
||||
Clone( OUT MULTISZ * pstrClone) const
|
||||
{
|
||||
return ((pstrClone == NULL) ?
|
||||
(SetLastError(ERROR_INVALID_PARAMETER), FALSE) :
|
||||
(pstrClone->Copy( *this))
|
||||
);
|
||||
} // MULTISZ::Clone()
|
||||
|
||||
//
|
||||
// Recalculates the length of *this because we've modified the buffers
|
||||
// directly
|
||||
//
|
||||
|
||||
VOID RecalcLen( VOID )
|
||||
{ m_cchLen = MULTISZ::CalcLength( QueryStr(), &m_cStrings ); }
|
||||
|
||||
//
|
||||
// Calculate total character length of a MULTI_SZ, including the
|
||||
// terminating NULLs.
|
||||
//
|
||||
|
||||
static DWORD CalcLength( const WCHAR * str,
|
||||
LPDWORD pcStrings = NULL );
|
||||
|
||||
//
|
||||
// Determine if the MULTISZ contains a specific string.
|
||||
//
|
||||
|
||||
BOOL FindString( const WCHAR * str );
|
||||
|
||||
BOOL FindString( STRU & str )
|
||||
{ return FindString( str.QueryStr() ); }
|
||||
|
||||
//
|
||||
// Determine if the MULTISZ contains a specific string - case-insensitive
|
||||
//
|
||||
|
||||
BOOL FindStringNoCase( const WCHAR * str );
|
||||
|
||||
BOOL FindStringNoCase( STRU & str )
|
||||
{ return FindStringNoCase( str.QueryStr() ); }
|
||||
|
||||
//
|
||||
// Used for scanning a multisz.
|
||||
//
|
||||
|
||||
const WCHAR * First( VOID ) const
|
||||
{ return *QueryStr() == L'\0' ? NULL : QueryStr(); }
|
||||
|
||||
const WCHAR * Next( const WCHAR * Current ) const
|
||||
{ Current += ::wcslen( Current ) + 1;
|
||||
return *Current == L'\0' ? NULL : Current; }
|
||||
|
||||
BOOL
|
||||
Equals(
|
||||
MULTISZ* pmszRhs
|
||||
);
|
||||
|
||||
private:
|
||||
|
||||
DWORD m_cchLen;
|
||||
DWORD m_cStrings;
|
||||
VOID AuxInit( const WCHAR * pInit );
|
||||
BOOL AuxAppend( const WCHAR * pInit,
|
||||
UINT cbStr, BOOL fAddSlop = TRUE );
|
||||
|
||||
};
|
||||
|
||||
//
|
||||
// Quick macro for declaring a MULTISZ that will use stack memory of <size>
|
||||
// bytes. If the buffer overflows then a heap buffer will be allocated
|
||||
//
|
||||
|
||||
#define STACK_MULTISZ( name, size ) WCHAR __ach##name[size]; \
|
||||
MULTISZ name( __ach##name, sizeof( __ach##name ))
|
||||
|
||||
HRESULT
|
||||
SplitCommaDelimitedString(
|
||||
PCWSTR pszList,
|
||||
BOOL fTrimEntries,
|
||||
BOOL fRemoveEmptyEntries,
|
||||
MULTISZ * pmszList
|
||||
);
|
||||
|
||||
#endif // !_MULTISZ_HXX_
|
||||
|
||||
|
|
@ -0,0 +1,408 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
#pragma warning (disable : 4267)
|
||||
#include "precomp.h"
|
||||
#include "multisza.h"
|
||||
#include <tchar.h>
|
||||
|
||||
//
|
||||
// Private Definitions
|
||||
//
|
||||
|
||||
#define MAXULONG 4294967295
|
||||
#define ISWHITE( ch ) ((ch) == L' ' || (ch) == L'\t' || (ch) == L'\r')
|
||||
|
||||
//
|
||||
// When appending data, this is the extra amount we request to avoid
|
||||
// reallocations
|
||||
//
|
||||
#define STR_SLOP 128
|
||||
|
||||
|
||||
DWORD
|
||||
MULTISZA::CalcLength( const CHAR * str,
|
||||
LPDWORD pcStrings )
|
||||
{
|
||||
DWORD count = 0;
|
||||
DWORD total = 1;
|
||||
DWORD len;
|
||||
|
||||
while( *str ) {
|
||||
len = ::strlen( str ) + 1;
|
||||
total += len;
|
||||
str += len;
|
||||
count++;
|
||||
}
|
||||
|
||||
if( pcStrings != NULL ) {
|
||||
*pcStrings = count;
|
||||
}
|
||||
|
||||
return total;
|
||||
|
||||
} // MULTISZA::CalcLength
|
||||
|
||||
|
||||
BOOL
|
||||
MULTISZA::FindString( const CHAR * str )
|
||||
{
|
||||
|
||||
CHAR * multisz;
|
||||
|
||||
//
|
||||
// Sanity check.
|
||||
//
|
||||
|
||||
DBG_ASSERT( QueryStr() != NULL );
|
||||
DBG_ASSERT( str != NULL );
|
||||
DBG_ASSERT( *str != '\0' );
|
||||
|
||||
//
|
||||
// Scan it.
|
||||
//
|
||||
|
||||
multisz = QueryStr();
|
||||
|
||||
while( *multisz != '\0' ) {
|
||||
|
||||
if( !::strcmp( multisz, str ) ) {
|
||||
|
||||
return TRUE;
|
||||
|
||||
}
|
||||
|
||||
multisz += ::strlen( multisz ) + 1;
|
||||
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
|
||||
} // MULTISZA::FindString
|
||||
|
||||
|
||||
BOOL
|
||||
MULTISZA::FindStringNoCase( const CHAR * str )
|
||||
{
|
||||
|
||||
CHAR * multisz;
|
||||
|
||||
//
|
||||
// Sanity check.
|
||||
//
|
||||
|
||||
DBG_ASSERT( QueryStr() != NULL );
|
||||
DBG_ASSERT( str != NULL );
|
||||
DBG_ASSERT( *str != '\0' );
|
||||
|
||||
//
|
||||
// Scan it.
|
||||
//
|
||||
|
||||
multisz = QueryStr();
|
||||
|
||||
while( *multisz != '\0' ) {
|
||||
|
||||
if( !_stricmp( multisz, str ) ) {
|
||||
|
||||
return TRUE;
|
||||
|
||||
}
|
||||
|
||||
multisz += strlen( multisz ) + 1;
|
||||
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
|
||||
} // MULTISZA::FindStringNoCase
|
||||
|
||||
|
||||
VOID
|
||||
MULTISZA::AuxInit( const CHAR * pInit )
|
||||
{
|
||||
BOOL fRet;
|
||||
|
||||
if ( pInit )
|
||||
{
|
||||
DWORD cStrings;
|
||||
int cbCopy = CalcLength( pInit, &cStrings ) * sizeof(CHAR);
|
||||
fRet = Resize( cbCopy );
|
||||
|
||||
if ( fRet ) {
|
||||
CopyMemory( QueryPtr(), pInit, cbCopy );
|
||||
m_cchLen = (cbCopy)/sizeof(CHAR);
|
||||
m_cStrings = cStrings;
|
||||
} else {
|
||||
// BUFFER::SetValid( FALSE);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
Reset();
|
||||
|
||||
}
|
||||
|
||||
} // MULTISZA::AuxInit()
|
||||
|
||||
|
||||
/*******************************************************************
|
||||
|
||||
NAME: MULTISZA::AuxAppend
|
||||
|
||||
SYNOPSIS: Appends the string onto the MULTISZA.
|
||||
|
||||
ENTRY: Object to append
|
||||
********************************************************************/
|
||||
|
||||
BOOL MULTISZA::AuxAppend( const CHAR * pStr, UINT cbStr, BOOL fAddSlop )
|
||||
{
|
||||
DBG_ASSERT( pStr != NULL );
|
||||
|
||||
UINT cbThis = QueryCB();
|
||||
|
||||
if( cbThis == 2 ) {
|
||||
|
||||
//
|
||||
// It's empty, so start at the beginning.
|
||||
//
|
||||
|
||||
cbThis = 0;
|
||||
|
||||
} else {
|
||||
|
||||
//
|
||||
// It's not empty, so back up over the final terminating NULL.
|
||||
//
|
||||
|
||||
cbThis -= sizeof(CHAR);
|
||||
|
||||
}
|
||||
|
||||
//
|
||||
// Only resize when we have to. When we do resize, we tack on
|
||||
// some extra space to avoid extra reallocations.
|
||||
//
|
||||
// Note: QuerySize returns the requested size of the string buffer,
|
||||
// *not* the strlen of the buffer
|
||||
//
|
||||
|
||||
//AcIncrement( CacMultiszAppend);
|
||||
|
||||
//
|
||||
// Check for the arithmetic overflow
|
||||
//
|
||||
// ( 2 * sizeof( CHAR ) ) is for the double terminator
|
||||
//
|
||||
ULONGLONG cb64Required = (ULONGLONG)cbThis + cbStr + 2 * sizeof(CHAR);
|
||||
if ( cb64Required > MAXULONG )
|
||||
{
|
||||
SetLastError( ERROR_ARITHMETIC_OVERFLOW );
|
||||
return FALSE;
|
||||
}
|
||||
if ( QuerySize() < (DWORD) cb64Required )
|
||||
{
|
||||
ULONGLONG cb64AllocSize = cb64Required + (fAddSlop ? STR_SLOP : 0 );
|
||||
//
|
||||
// Check for the arithmetic overflow
|
||||
//
|
||||
if ( cb64AllocSize > MAXULONG )
|
||||
{
|
||||
SetLastError( ERROR_ARITHMETIC_OVERFLOW );
|
||||
return FALSE;
|
||||
}
|
||||
if ( !Resize( (DWORD) cb64AllocSize ) )
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// copy the exact string and tack on the double terminator
|
||||
memcpy( (BYTE *) QueryPtr() + cbThis,
|
||||
pStr,
|
||||
cbStr);
|
||||
*(CHAR *)((BYTE *)QueryPtr() + cbThis + cbStr) = L'\0';
|
||||
*(CHAR *)((BYTE *)QueryPtr() + cbThis + cbStr + sizeof(CHAR) ) = L'\0';
|
||||
|
||||
m_cchLen = CalcLength( (const CHAR *)QueryPtr(), &m_cStrings );
|
||||
return TRUE;
|
||||
|
||||
} // MULTISZA::AuxAppend()
|
||||
|
||||
BOOL
|
||||
MULTISZA::CopyToBuffer( __out_ecount_opt(*lpcch) CHAR * lpszBuffer, LPDWORD lpcch) const
|
||||
/*++
|
||||
Description:
|
||||
Copies the string into the CHAR buffer passed in if the buffer
|
||||
is sufficient to hold the translated string.
|
||||
If the buffer is small, the function returns small and sets *lpcch
|
||||
to contain the required number of characters.
|
||||
|
||||
Arguments:
|
||||
lpszBuffer pointer to CHAR buffer which on return contains
|
||||
the string on success.
|
||||
lpcch pointer to DWORD containing the length of the buffer.
|
||||
If *lpcch == 0 then the function returns TRUE with
|
||||
the count of characters required stored in lpcch.
|
||||
Also in this case lpszBuffer is not affected.
|
||||
Returns:
|
||||
TRUE on success.
|
||||
FALSE on failure. Use GetLastError() for further details.
|
||||
--*/
|
||||
{
|
||||
BOOL fReturn = TRUE;
|
||||
|
||||
if ( lpcch == NULL) {
|
||||
SetLastError( ERROR_INVALID_PARAMETER);
|
||||
return ( FALSE);
|
||||
}
|
||||
|
||||
register DWORD cch = QueryCCH();
|
||||
|
||||
if ( *lpcch >= cch) {
|
||||
|
||||
DBG_ASSERT( lpszBuffer);
|
||||
memcpy( lpszBuffer, QueryStr(), cch * sizeof(CHAR));
|
||||
} else {
|
||||
DBG_ASSERT( *lpcch < cch);
|
||||
SetLastError( ERROR_INSUFFICIENT_BUFFER);
|
||||
fReturn = FALSE;
|
||||
}
|
||||
|
||||
*lpcch = cch;
|
||||
|
||||
return ( fReturn);
|
||||
} // MULTISZA::CopyToBuffer()
|
||||
|
||||
BOOL
|
||||
MULTISZA::Equals(
|
||||
MULTISZA* pmszRhs
|
||||
)
|
||||
//
|
||||
// Compares this to pmszRhs, returns TRUE if equal
|
||||
//
|
||||
{
|
||||
DBG_ASSERT( NULL != pmszRhs );
|
||||
|
||||
PCSTR pszLhs = First( );
|
||||
PCSTR pszRhs = pmszRhs->First( );
|
||||
|
||||
if( m_cStrings != pmszRhs->m_cStrings )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
while( NULL != pszLhs )
|
||||
{
|
||||
DBG_ASSERT( NULL != pszRhs );
|
||||
|
||||
if( 0 != strcmp( pszLhs, pszRhs ) )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
pszLhs = Next( pszLhs );
|
||||
pszRhs = pmszRhs->Next( pszRhs );
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
SplitCommaDelimitedString(
|
||||
PCSTR pszList,
|
||||
BOOL fTrimEntries,
|
||||
BOOL fRemoveEmptyEntries,
|
||||
MULTISZA * pmszList
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Split comma delimited string into a MULTISZA. Additional leading empty
|
||||
entries after the first are discarded.
|
||||
|
||||
Arguments:
|
||||
|
||||
pszList - List to split up
|
||||
fTrimEntries - Whether each entry should be trimmed before added to MULTISZA
|
||||
fRemoveEmptyEntries - Whether empty entires should be discarded
|
||||
pmszList - Filled with MULTISZA list
|
||||
|
||||
Return Value:
|
||||
|
||||
HRESULT
|
||||
|
||||
--*/
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
if ( pszList == NULL ||
|
||||
pmszList == NULL )
|
||||
{
|
||||
DBG_ASSERT( FALSE );
|
||||
hr = HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
pmszList->Reset();
|
||||
|
||||
/*
|
||||
pszCurrent: start of the current entry which may be the comma that
|
||||
precedes the next entry if the entry is empty
|
||||
|
||||
pszNext: the comma that precedes the next entry. If
|
||||
pszCurrent == pszNext, then the entry is empty
|
||||
|
||||
pszEnd: just past the end of the current entry
|
||||
*/
|
||||
|
||||
for ( PCSTR pszCurrent = pszList,
|
||||
pszNext = strchr( pszCurrent, L',' )
|
||||
;
|
||||
;
|
||||
pszCurrent = pszNext + 1,
|
||||
pszNext = strchr( pszCurrent, L',' ) )
|
||||
{
|
||||
PCSTR pszEnd = NULL;
|
||||
|
||||
if ( pszNext != NULL )
|
||||
{
|
||||
pszEnd = pszNext;
|
||||
}
|
||||
else
|
||||
{
|
||||
pszEnd = pszCurrent + strlen( pszCurrent );
|
||||
}
|
||||
|
||||
if ( fTrimEntries )
|
||||
{
|
||||
while ( pszCurrent < pszEnd && ISWHITE( pszCurrent[ 0 ] ) )
|
||||
{
|
||||
pszCurrent++;
|
||||
}
|
||||
|
||||
while ( pszEnd > pszCurrent && ISWHITE( pszEnd[ -1 ] ) )
|
||||
{
|
||||
pszEnd--;
|
||||
}
|
||||
}
|
||||
|
||||
if ( pszCurrent != pszEnd || !fRemoveEmptyEntries )
|
||||
{
|
||||
if ( !pmszList->Append( pszCurrent, (DWORD) ( pszEnd - pszCurrent ) ) )
|
||||
{
|
||||
hr = HRESULT_FROM_WIN32( GetLastError() );
|
||||
goto Finished;
|
||||
}
|
||||
}
|
||||
|
||||
if ( pszNext == NULL )
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Finished:
|
||||
|
||||
return hr;
|
||||
}
|
||||
#pragma warning(default:4267)
|
||||
|
|
@ -0,0 +1,226 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
#ifndef _MULTISZA_H_
|
||||
#define _MULTISZA_H_
|
||||
|
||||
#include <Windows.h>
|
||||
#include "stringa.h"
|
||||
|
||||
|
||||
/*++
|
||||
class MULTISZ:
|
||||
|
||||
Intention:
|
||||
A light-weight multi-string class supporting encapsulated string class.
|
||||
|
||||
This object is derived from BUFFER class.
|
||||
It maintains following state:
|
||||
|
||||
m_fValid - whether this object is valid -
|
||||
used only by MULTISZ() init functions
|
||||
* NYI: I need to kill this someday *
|
||||
m_cchLen - string length cached when we update the string.
|
||||
m_cStrings - number of strings.
|
||||
|
||||
Member Functions:
|
||||
There are two categories of functions:
|
||||
1) Safe Functions - which do integrity checking of state
|
||||
2) UnSafe Functions - which do not do integrity checking, but
|
||||
enable writing to the data stream freely.
|
||||
(someday this will be enabled as Safe versions without
|
||||
problem for users)
|
||||
|
||||
--*/
|
||||
class MULTISZA : public BUFFER
|
||||
{
|
||||
public:
|
||||
|
||||
MULTISZA()
|
||||
: BUFFER (),
|
||||
m_cchLen ( 0),
|
||||
m_cStrings(0)
|
||||
{ Reset(); }
|
||||
|
||||
// creates a stack version of the MULTISZA object - uses passed in stack buffer
|
||||
// MULTISZA does not free this pbInit on its own.
|
||||
MULTISZA( __in_bcount(cbInit) CHAR * pbInit, DWORD cbInit)
|
||||
: BUFFER( (BYTE *) pbInit, cbInit),
|
||||
m_cchLen (0),
|
||||
m_cStrings(0)
|
||||
{}
|
||||
|
||||
MULTISZA( const CHAR * pchInit )
|
||||
: BUFFER (),
|
||||
m_cchLen ( 0),
|
||||
m_cStrings(0)
|
||||
{ AuxInit(pchInit); }
|
||||
|
||||
MULTISZA( const MULTISZA & str )
|
||||
: BUFFER (),
|
||||
m_cchLen ( 0),
|
||||
m_cStrings(0)
|
||||
{ AuxInit( str.QueryStr()); }
|
||||
|
||||
// BOOL IsValid(VOID) const { return ( BUFFER::IsValid()) ; }
|
||||
//
|
||||
// Checks and returns TRUE if this string has no valid data else FALSE
|
||||
//
|
||||
BOOL IsEmpty( VOID) const { return ( *QueryStr() == L'\0'); }
|
||||
|
||||
BOOL Append( const CHAR * pchInit ) {
|
||||
return ((pchInit != NULL) ? (AuxAppend( pchInit,
|
||||
(DWORD) (::strlen(pchInit)) * sizeof(CHAR)
|
||||
)) :
|
||||
TRUE);
|
||||
}
|
||||
|
||||
|
||||
BOOL Append( const CHAR * pchInit, DWORD cchLen ) {
|
||||
return ((pchInit != NULL) ? (AuxAppend( pchInit,
|
||||
cchLen * sizeof(CHAR))) :
|
||||
TRUE);
|
||||
}
|
||||
|
||||
BOOL Append( STRA & str )
|
||||
{ return AuxAppend( str.QueryStr(),
|
||||
(str.QueryCCH()) * sizeof(CHAR)); }
|
||||
|
||||
// Resets the internal string to be NULL string. Buffer remains cached.
|
||||
VOID Reset( VOID)
|
||||
{ DBG_ASSERT( QueryPtr() != NULL);
|
||||
QueryStr()[0] = L'\0';
|
||||
QueryStr()[1] = L'\0';
|
||||
m_cchLen = 2;
|
||||
m_cStrings = 0;
|
||||
}
|
||||
|
||||
BOOL Copy( const CHAR * pchInit, IN DWORD cbLen ) {
|
||||
if ( QueryPtr() ) { Reset(); }
|
||||
return ( (pchInit != NULL) ?
|
||||
AuxAppend( pchInit, cbLen, FALSE ):
|
||||
TRUE);
|
||||
}
|
||||
|
||||
BOOL Copy( const MULTISZA & str )
|
||||
{ return ( Copy(str.QueryStr(), str.QueryCB())); }
|
||||
|
||||
//
|
||||
// Returns the number of bytes in the string including the terminating
|
||||
// NULLs
|
||||
//
|
||||
UINT QueryCB( VOID ) const
|
||||
{ return ( m_cchLen * sizeof(CHAR)); }
|
||||
|
||||
//
|
||||
// Returns # of characters in the string including the terminating NULLs
|
||||
//
|
||||
UINT QueryCCH( VOID ) const { return (m_cchLen); }
|
||||
|
||||
//
|
||||
// Returns # of strings in the MULTISZA.
|
||||
//
|
||||
|
||||
DWORD QueryStringCount( VOID ) const { return m_cStrings; }
|
||||
|
||||
//
|
||||
// Makes a copy of the stored string in given buffer
|
||||
//
|
||||
BOOL CopyToBuffer( __out_ecount_opt(*lpcch) CHAR * lpszBuffer, LPDWORD lpcch) const;
|
||||
|
||||
//
|
||||
// Return the string buffer
|
||||
//
|
||||
CHAR * QueryStrA( VOID ) const { return ( QueryStr()); }
|
||||
CHAR * QueryStr( VOID ) const { return ((CHAR *) QueryPtr()); }
|
||||
|
||||
//
|
||||
// Makes a clone of the current string in the string pointer passed in.
|
||||
//
|
||||
BOOL
|
||||
Clone( OUT MULTISZA * pstrClone) const
|
||||
{
|
||||
return ((pstrClone == NULL) ?
|
||||
(SetLastError(ERROR_INVALID_PARAMETER), FALSE) :
|
||||
(pstrClone->Copy( *this))
|
||||
);
|
||||
} // MULTISZA::Clone()
|
||||
|
||||
//
|
||||
// Recalculates the length of *this because we've modified the buffers
|
||||
// directly
|
||||
//
|
||||
|
||||
VOID RecalcLen( VOID )
|
||||
{ m_cchLen = MULTISZA::CalcLength( QueryStr(), &m_cStrings ); }
|
||||
|
||||
//
|
||||
// Calculate total character length of a MULTI_SZ, including the
|
||||
// terminating NULLs.
|
||||
//
|
||||
|
||||
static DWORD CalcLength( const CHAR * str,
|
||||
LPDWORD pcStrings = NULL );
|
||||
|
||||
//
|
||||
// Determine if the MULTISZA contains a specific string.
|
||||
//
|
||||
|
||||
BOOL FindString( const CHAR * str );
|
||||
|
||||
BOOL FindString( STRA & str )
|
||||
{ return FindString( str.QueryStr() ); }
|
||||
|
||||
//
|
||||
// Determine if the MULTISZA contains a specific string - case-insensitive
|
||||
//
|
||||
|
||||
BOOL FindStringNoCase( const CHAR * str );
|
||||
|
||||
BOOL FindStringNoCase( STRA & str )
|
||||
{ return FindStringNoCase( str.QueryStr() ); }
|
||||
|
||||
//
|
||||
// Used for scanning a MULTISZA.
|
||||
//
|
||||
|
||||
const CHAR * First( VOID ) const
|
||||
{ return *QueryStr() == L'\0' ? NULL : QueryStr(); }
|
||||
|
||||
const CHAR * Next( const CHAR * Current ) const
|
||||
{ Current += ::strlen( Current ) + 1;
|
||||
return *Current == L'\0' ? NULL : Current; }
|
||||
|
||||
BOOL
|
||||
Equals(
|
||||
MULTISZA* pmszRhs
|
||||
);
|
||||
|
||||
private:
|
||||
|
||||
DWORD m_cchLen;
|
||||
DWORD m_cStrings;
|
||||
VOID AuxInit( const CHAR * pInit );
|
||||
BOOL AuxAppend( const CHAR * pInit,
|
||||
UINT cbStr, BOOL fAddSlop = TRUE );
|
||||
|
||||
};
|
||||
|
||||
//
|
||||
// Quick macro for declaring a MULTISZA that will use stack memory of <size>
|
||||
// bytes. If the buffer overflows then a heap buffer will be allocated
|
||||
//
|
||||
|
||||
#define STACK_MULTISZA( name, size ) CHAR __ach##name[size]; \
|
||||
MULTISZA name( __ach##name, sizeof( __ach##name ))
|
||||
|
||||
HRESULT
|
||||
SplitCommaDelimitedString(
|
||||
PCSTR pszList,
|
||||
BOOL fTrimEntries,
|
||||
BOOL fRemoveEmptyEntries,
|
||||
MULTISZA * pmszList
|
||||
);
|
||||
|
||||
#endif // !_MULTISZA_HXX_
|
||||
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef _ASSERTE
|
||||
#undef _ASSERTE
|
||||
#endif
|
||||
|
||||
#ifdef ASSERT
|
||||
#undef ASSERT
|
||||
#endif
|
||||
|
||||
#if defined( DBG ) && DBG
|
||||
#define SX_ASSERT( _x ) ( (VOID)( ( ( _x ) ) ? TRUE : ( __annotation( L"Debug", L"AssertFail", L#_x ), DbgRaiseAssertionFailure(), FALSE ) ) )
|
||||
#define SX_ASSERTMSG( _m, _x ) ( (VOID)( ( ( _x ) ) ? TRUE : ( __annotation( L"Debug", L"AssertFail", L##_m ), DbgRaiseAssertionFailure(), FALSE ) ) )
|
||||
#define SX_VERIFY( _x ) SX_ASSERT( _x )
|
||||
#define _ASSERTE( _x ) SX_ASSERT( _x )
|
||||
#define ASSERT( _x ) SX_ASSERT( _x )
|
||||
#define assert( _x ) SX_ASSERT( _x )
|
||||
#define DBG_ASSERT( _x ) SX_ASSERT( _x )
|
||||
#define DBG_REQUIRE( _x ) SX_ASSERT( _x )
|
||||
#else
|
||||
#define SX_ASSERT( _x ) ( (VOID)0 )
|
||||
#define SX_ASSERTMSG( _m, _x ) ( (VOID)0 )
|
||||
#define SX_VERIFY( _x ) ( (VOID)( ( _x ) ? TRUE : FALSE ) )
|
||||
#define _ASSERTE( _x ) ( (VOID)0 )
|
||||
#define assert( _x ) ( (VOID)0 )
|
||||
#define DBG_ASSERT( _x ) ( (VOID)0 )
|
||||
#define DBG_REQUIRE( _x ) ((VOID)(_x))
|
||||
#endif
|
||||
|
||||
|
|
@ -0,0 +1,305 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
template<typename T>
|
||||
class PER_CPU
|
||||
{
|
||||
public:
|
||||
|
||||
template<typename FunctionInitializer>
|
||||
inline
|
||||
static
|
||||
HRESULT
|
||||
Create(
|
||||
FunctionInitializer Initializer,
|
||||
__deref_out PER_CPU<T> ** ppInstance
|
||||
);
|
||||
|
||||
inline
|
||||
T *
|
||||
GetLocal(
|
||||
VOID
|
||||
);
|
||||
|
||||
template<typename FunctionForEach>
|
||||
inline
|
||||
VOID
|
||||
ForEach(
|
||||
FunctionForEach Function
|
||||
);
|
||||
|
||||
inline
|
||||
VOID
|
||||
Dispose(
|
||||
VOID
|
||||
);
|
||||
|
||||
private:
|
||||
|
||||
PER_CPU(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
//
|
||||
// Don't perform any operation during constructor.
|
||||
// Constructor will never be called.
|
||||
//
|
||||
}
|
||||
|
||||
~PER_CPU(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
//
|
||||
// Don't perform any operation during destructor.
|
||||
// Constructor will never be called.
|
||||
//
|
||||
}
|
||||
|
||||
template<typename FunctionInitializer>
|
||||
HRESULT
|
||||
Initialize(
|
||||
FunctionInitializer Initializer,
|
||||
DWORD NumberOfVariables,
|
||||
DWORD Alignment
|
||||
);
|
||||
|
||||
T *
|
||||
GetObject(
|
||||
DWORD Index
|
||||
);
|
||||
|
||||
static
|
||||
HRESULT
|
||||
GetProcessorInformation(
|
||||
__out DWORD * pCacheLineSize,
|
||||
__out DWORD * pNumberOfProcessors
|
||||
);
|
||||
|
||||
//
|
||||
// Pointer to the begining of the inlined array.
|
||||
//
|
||||
PVOID m_pVariables;
|
||||
SIZE_T m_Alignment;
|
||||
SIZE_T m_VariablesCount;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
template<typename FunctionInitializer>
|
||||
inline
|
||||
// static
|
||||
HRESULT
|
||||
PER_CPU<T>::Create(
|
||||
FunctionInitializer Initializer,
|
||||
__deref_out PER_CPU<T> ** ppInstance
|
||||
)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
DWORD CacheLineSize = 0;
|
||||
DWORD ObjectCacheLineSize = 0;
|
||||
DWORD NumberOfProcessors = 0;
|
||||
PER_CPU<T> * pInstance = NULL;
|
||||
|
||||
hr = GetProcessorInformation(&CacheLineSize,
|
||||
&NumberOfProcessors);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
if (sizeof(T) > CacheLineSize)
|
||||
{
|
||||
//
|
||||
// Round to the next multiple of the cache line size.
|
||||
//
|
||||
ObjectCacheLineSize = (sizeof(T) + CacheLineSize-1) & (CacheLineSize-1);
|
||||
}
|
||||
else
|
||||
{
|
||||
ObjectCacheLineSize = CacheLineSize;
|
||||
}
|
||||
|
||||
//
|
||||
// Calculate the size of the PER_CPU<T> object, including the array.
|
||||
// The first cache line is for the member variables and the array
|
||||
// starts in the next cache line.
|
||||
//
|
||||
SIZE_T Size = CacheLineSize + NumberOfProcessors * ObjectCacheLineSize;
|
||||
|
||||
pInstance = (PER_CPU<T>*) _aligned_malloc(Size, CacheLineSize);
|
||||
if (pInstance == NULL)
|
||||
{
|
||||
hr = E_OUTOFMEMORY;
|
||||
goto Finished;
|
||||
}
|
||||
ZeroMemory(pInstance, Size);
|
||||
|
||||
//
|
||||
// The array start in the 2nd cache line.
|
||||
//
|
||||
pInstance->m_pVariables = reinterpret_cast<PBYTE>(pInstance) + CacheLineSize;
|
||||
|
||||
//
|
||||
// Pass a disposer for disposing initialized items in case of failure.
|
||||
//
|
||||
hr = pInstance->Initialize(Initializer,
|
||||
NumberOfProcessors,
|
||||
ObjectCacheLineSize);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
*ppInstance = pInstance;
|
||||
pInstance = NULL;
|
||||
|
||||
Finished:
|
||||
|
||||
if (pInstance != NULL)
|
||||
{
|
||||
//
|
||||
// Free the instance without disposing it.
|
||||
//
|
||||
pInstance->Dispose();
|
||||
pInstance = NULL;
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline
|
||||
T *
|
||||
PER_CPU<T>::GetLocal(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
// Use GetCurrentProcessorNumber (up to 64 logical processors) instead of
|
||||
// GetCurrentProcessorNumberEx (more than 64 logical processors) because
|
||||
// the number of processors are not densely packed per group.
|
||||
// The idea of distributing variables per CPU is to have
|
||||
// a scalability multiplier (could be NUMA node instead).
|
||||
//
|
||||
// Make sure the index don't go beyond the array size, if that happens,
|
||||
// there won't be even distribution, but still better
|
||||
// than one single variable.
|
||||
//
|
||||
return GetObject(GetCurrentProcessorNumber());
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline
|
||||
T *
|
||||
PER_CPU<T>::GetObject(
|
||||
DWORD Index
|
||||
)
|
||||
{
|
||||
return reinterpret_cast<T*>(static_cast<PBYTE>(m_pVariables) + Index * m_Alignment);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
template<typename FunctionForEach>
|
||||
inline
|
||||
VOID
|
||||
PER_CPU<T>::ForEach(
|
||||
FunctionForEach Function
|
||||
)
|
||||
{
|
||||
for(DWORD Index = 0; Index < m_VariablesCount; ++Index)
|
||||
{
|
||||
T * pObject = GetObject(Index);
|
||||
Function(pObject);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
VOID
|
||||
PER_CPU<T>::Dispose(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
_aligned_free(this);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
template<typename FunctionInitializer>
|
||||
inline
|
||||
HRESULT
|
||||
PER_CPU<T>::Initialize(
|
||||
FunctionInitializer Initializer,
|
||||
DWORD NumberOfVariables,
|
||||
DWORD Alignment
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Initialize each object using the initializer function.
|
||||
If initialization for any object fails, it dispose the
|
||||
objects that were successfully initialized.
|
||||
|
||||
Arguments:
|
||||
|
||||
Initializer - Function for initialize one object.
|
||||
Signature: HRESULT Func(T*)
|
||||
Dispose - Function for disposing initialized objects in case of failure.
|
||||
Signature: void Func(T*)
|
||||
NumberOfVariables - The length of the array of variables.
|
||||
Alignment - Alignment to use for avoiding false sharing.
|
||||
|
||||
Return:
|
||||
|
||||
HRESULT - E_OUTOFMEMORY
|
||||
|
||||
--*/
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
DWORD Index = 0;
|
||||
|
||||
m_VariablesCount = NumberOfVariables;
|
||||
m_Alignment = Alignment;
|
||||
|
||||
for (; Index < m_VariablesCount; ++Index)
|
||||
{
|
||||
T * pObject = GetObject(Index);
|
||||
Initializer(pObject);
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
// static
|
||||
HRESULT
|
||||
PER_CPU<T>::GetProcessorInformation(
|
||||
__out DWORD * pCacheLineSize,
|
||||
__out DWORD * pNumberOfProcessors
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Gets the CPU cache-line size for the current system.
|
||||
This information is used for avoiding CPU false sharing.
|
||||
|
||||
Arguments:
|
||||
|
||||
pCacheLineSize - The processor cache-line size.
|
||||
pNumberOfProcessors - Maximum number of processors per group.
|
||||
|
||||
Return:
|
||||
|
||||
HRESULT - E_OUTOFMEMORY
|
||||
|
||||
--*/
|
||||
{
|
||||
SYSTEM_INFO SystemInfo = { };
|
||||
|
||||
GetSystemInfo(&SystemInfo);
|
||||
*pNumberOfProcessors = SystemInfo.dwNumberOfProcessors;
|
||||
*pCacheLineSize = SYSTEM_CACHE_ALIGNMENT_SIZE;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
#include <windows.h>
|
||||
#include <ahadmin.h>
|
||||
#pragma warning( disable:4127 )
|
||||
#include <atlcomcli.h>
|
||||
#include <strsafe.h>
|
||||
#include <intsafe.h>
|
||||
|
||||
#include "macros.h"
|
||||
#include "stringu.h"
|
||||
#include "stringa.h"
|
||||
#include "dbgutil.h"
|
||||
#include "ntassert.h"
|
||||
#include "ahutil.h"
|
||||
#include "acache.h"
|
||||
//#include "base64.hxx"
|
||||
|
|
@ -0,0 +1,85 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
//
|
||||
// Pre-calculated prime numbers (up to 10,049,369).
|
||||
//
|
||||
extern __declspec(selectany) const DWORD g_Primes [] = {
|
||||
3, 7, 11, 17, 23, 29, 37, 47, 59, 71, 89, 107, 131, 163, 197, 239, 293, 353, 431, 521, 631,
|
||||
761, 919, 1103, 1327, 1597, 1931, 2333, 2801, 3371, 4049, 4861, 5839, 7013, 8419, 10103,
|
||||
12143, 14591, 17519, 21023, 25229, 30293, 36353, 43627, 52361, 62851, 75431, 90523, 108631,
|
||||
130363, 156437, 187751, 225307, 270371, 324449, 389357, 467237, 560689, 672827, 807403,
|
||||
968897, 1162687, 1395263, 1674319, 2009191, 2411033, 2893249, 3471899, 4166287, 4999559,
|
||||
5999471, 7199369, 7849369, 8649369, 9249369, 10049369
|
||||
};
|
||||
|
||||
class PRIME
|
||||
{
|
||||
public:
|
||||
|
||||
static
|
||||
DWORD
|
||||
GetPrime(
|
||||
DWORD dwMinimum
|
||||
)
|
||||
{
|
||||
//
|
||||
// Try to use the precalculated numbers.
|
||||
//
|
||||
for ( DWORD Index = 0; Index < _countof( g_Primes ); Index++ )
|
||||
{
|
||||
DWORD dwCandidate = g_Primes[Index];
|
||||
if ( dwCandidate >= dwMinimum )
|
||||
{
|
||||
return dwCandidate;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Do calculation.
|
||||
//
|
||||
for ( DWORD dwCandidate = dwMinimum | 1;
|
||||
dwCandidate < MAXDWORD;
|
||||
dwCandidate += 2 )
|
||||
{
|
||||
if ( IsPrime( dwCandidate ) )
|
||||
{
|
||||
return dwCandidate;
|
||||
}
|
||||
}
|
||||
return dwMinimum;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
static
|
||||
BOOL
|
||||
IsPrime(
|
||||
DWORD dwCandidate
|
||||
)
|
||||
{
|
||||
if ((dwCandidate & 1) == 0)
|
||||
{
|
||||
return ( dwCandidate == 2 );
|
||||
}
|
||||
|
||||
DWORD dwMax = static_cast<DWORD>(sqrt(static_cast<double>(dwCandidate)));
|
||||
|
||||
for ( DWORD Index = 3; Index <= dwMax; Index += 2 )
|
||||
{
|
||||
if ( (dwCandidate % Index) == 0 )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
PRIME() {}
|
||||
~PRIME() {}
|
||||
};
|
||||
|
|
@ -0,0 +1,736 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
# ifndef _PUDEBUG_H_
|
||||
# define _PUDEBUG_H_
|
||||
|
||||
#ifndef _NO_TRACING_
|
||||
# define _NO_TRACING_
|
||||
#endif // _NO_TRACING_
|
||||
|
||||
/************************************************************
|
||||
* Include Headers
|
||||
************************************************************/
|
||||
|
||||
# ifdef __cplusplus
|
||||
extern "C" {
|
||||
# endif // __cplusplus
|
||||
|
||||
# include <windows.h>
|
||||
|
||||
# ifndef dllexp
|
||||
# define dllexp __declspec( dllexport)
|
||||
# endif // dllexp
|
||||
|
||||
#include <specstrings.h>
|
||||
|
||||
#ifndef IN_OUT
|
||||
#define IN_OUT __inout
|
||||
#endif
|
||||
|
||||
/***********************************************************
|
||||
* Macros
|
||||
************************************************************/
|
||||
|
||||
enum PRINT_REASONS {
|
||||
PrintNone = 0x0, // Nothing to be printed
|
||||
PrintError = 0x1, // An error message
|
||||
PrintWarning = 0x2, // A warning message
|
||||
PrintLog = 0x3, // Just logging. Indicates a trace of where ...
|
||||
PrintMsg = 0x4, // Echo input message
|
||||
PrintCritical = 0x5, // Print and Exit
|
||||
PrintAssertion= 0x6 // Printing for an assertion failure
|
||||
};
|
||||
|
||||
|
||||
enum DEBUG_OUTPUT_FLAGS {
|
||||
DbgOutputNone = 0x0, // None
|
||||
DbgOutputKdb = 0x1, // Output to Kernel Debugger
|
||||
DbgOutputLogFile = 0x2, // Output to LogFile
|
||||
DbgOutputTruncate = 0x4, // Truncate Log File if necessary
|
||||
DbgOutputStderr = 0x8, // Send output to std error
|
||||
DbgOutputBackup = 0x10, // Make backup of debug file ?
|
||||
DbgOutputMemory = 0x20, // Dump to memory buffer
|
||||
DbgOutputAll = 0xFFFFFFFF // All the bits set.
|
||||
};
|
||||
|
||||
|
||||
# define MAX_LABEL_LENGTH ( 100)
|
||||
|
||||
|
||||
// The following flags are used internally to track what level of tracing we
|
||||
// are currently using. Bitmapped for extensibility.
|
||||
#define DEBUG_FLAG_ODS 0x00000001
|
||||
//#define DEBUG_FLAG_INFO 0x00000002
|
||||
//#define DEBUG_FLAG_WARN 0x00000004
|
||||
//#define DEBUG_FLAG_ERROR 0x00000008
|
||||
// The following are used internally to determine whether to log or not based
|
||||
// on what the current state is
|
||||
//#define DEBUG_FLAGS_INFO (DEBUG_FLAG_ODS | DEBUG_FLAG_INFO)
|
||||
//#define DEBUG_FLAGS_WARN (DEBUG_FLAG_ODS | DEBUG_FLAG_INFO | DEBUG_FLAG_WARN)
|
||||
//#define DEBUG_FLAGS_ERROR (DEBUG_FLAG_ODS | DEBUG_FLAG_INFO | DEBUG_FLAG_WARN | DEBUG_FLAG_ERROR)
|
||||
|
||||
#define DEBUG_FLAGS_ANY (DEBUG_FLAG_INFO | DEBUG_FLAG_WARN | DEBUG_FLAG_ERROR)
|
||||
|
||||
//
|
||||
// user of DEBUG infrastructure may choose unique variable name for DEBUG_FLAGS
|
||||
// that's specially useful for cases where DEBUG infrastructure is used within
|
||||
// static library (static library may prefer to maintain it's own DebugFlags independent
|
||||
// on the main program it links to
|
||||
//
|
||||
#ifndef DEBUG_FLAGS_VAR
|
||||
#define DEBUG_FLAGS_VAR g_dwDebugFlags
|
||||
#endif
|
||||
|
||||
extern
|
||||
#ifdef __cplusplus
|
||||
"C"
|
||||
# endif // _cplusplus
|
||||
DWORD DEBUG_FLAGS_VAR ; // Debugging Flags
|
||||
|
||||
# define DECLARE_DEBUG_VARIABLE()
|
||||
|
||||
# define SET_DEBUG_FLAGS( dwFlags) DEBUG_FLAGS_VAR = dwFlags
|
||||
# define GET_DEBUG_FLAGS() ( DEBUG_FLAGS_VAR )
|
||||
|
||||
# define LOAD_DEBUG_FLAGS_FROM_REG(hkey, dwDefault) \
|
||||
DEBUG_FLAGS_VAR = PuLoadDebugFlagsFromReg((hkey), (dwDefault))
|
||||
|
||||
# define LOAD_DEBUG_FLAGS_FROM_REG_STR(pszRegKey, dwDefault) \
|
||||
DEBUG_FLAGS_VAR = PuLoadDebugFlagsFromRegStr((pszRegKey), (dwDefault))
|
||||
|
||||
# define SAVE_DEBUG_FLAGS_IN_REG(hkey, dwDbg) \
|
||||
PuSaveDebugFlagsInReg((hkey), (dwDbg))
|
||||
|
||||
# define DEBUG_IF( arg, s) if ( DEBUG_ ## arg & GET_DEBUG_FLAGS()) { \
|
||||
s \
|
||||
} else {}
|
||||
|
||||
# define IF_DEBUG( arg) if ( DEBUG_## arg & GET_DEBUG_FLAGS())
|
||||
|
||||
|
||||
/*++
|
||||
class DEBUG_PRINTS
|
||||
|
||||
This class is responsible for printing messages to log file / kernel debugger
|
||||
|
||||
Currently the class supports only member functions for <ANSI> char.
|
||||
( not unicode-strings).
|
||||
|
||||
--*/
|
||||
|
||||
|
||||
typedef struct _DEBUG_PRINTS {
|
||||
|
||||
CHAR m_rgchLabel[MAX_LABEL_LENGTH];
|
||||
CHAR m_rgchLogFilePath[MAX_PATH];
|
||||
CHAR m_rgchLogFileName[MAX_PATH];
|
||||
HANDLE m_LogFileHandle;
|
||||
HANDLE m_StdErrHandle;
|
||||
BOOL m_fInitialized;
|
||||
BOOL m_fBreakOnAssert;
|
||||
DWORD m_dwOutputFlags;
|
||||
VOID *m_pMemoryLog;
|
||||
} DEBUG_PRINTS, FAR * LPDEBUG_PRINTS;
|
||||
|
||||
|
||||
LPDEBUG_PRINTS
|
||||
PuCreateDebugPrintsObject(
|
||||
IN const char * pszPrintLabel,
|
||||
IN DWORD dwOutputFlags);
|
||||
|
||||
//
|
||||
// frees the debug prints object and closes any file if necessary.
|
||||
// Returns NULL on success or returns pDebugPrints on failure.
|
||||
//
|
||||
LPDEBUG_PRINTS
|
||||
PuDeleteDebugPrintsObject(
|
||||
IN_OUT LPDEBUG_PRINTS pDebugPrints);
|
||||
|
||||
|
||||
VOID
|
||||
PuDbgPrint(
|
||||
IN_OUT LPDEBUG_PRINTS pDebugPrints,
|
||||
IN const char * pszFilePath,
|
||||
IN int nLineNum,
|
||||
IN const char * pszFunctionName,
|
||||
IN const char * pszFormat,
|
||||
...);
|
||||
// arglist
|
||||
VOID
|
||||
PuDbgPrintW(
|
||||
IN_OUT LPDEBUG_PRINTS pDebugPrints,
|
||||
IN const char * pszFilePath,
|
||||
IN int nLineNum,
|
||||
IN const char * pszFunctionName,
|
||||
IN const WCHAR * pszFormat,
|
||||
...); // arglist
|
||||
|
||||
// PuDbgPrintError is similar to PuDbgPrint() but allows
|
||||
// one to print error code in friendly manner
|
||||
VOID
|
||||
PuDbgPrintError(
|
||||
IN_OUT LPDEBUG_PRINTS pDebugPrints,
|
||||
IN const char * pszFilePath,
|
||||
IN int nLineNum,
|
||||
IN const char * pszFunctionName,
|
||||
IN DWORD dwError,
|
||||
IN const char * pszFormat,
|
||||
...); // arglist
|
||||
|
||||
/*++
|
||||
PuDbgDump() does not do any formatting of output.
|
||||
It just dumps the given message onto the debug destinations.
|
||||
--*/
|
||||
VOID
|
||||
PuDbgDump(
|
||||
IN_OUT LPDEBUG_PRINTS pDebugPrints,
|
||||
IN const char * pszFilePath,
|
||||
IN int nLineNum,
|
||||
IN const char * pszFunctionName,
|
||||
IN const char * pszDump
|
||||
);
|
||||
|
||||
//
|
||||
// PuDbgAssertFailed() *must* be __cdecl to properly capture the
|
||||
// thread context at the time of the failure.
|
||||
//
|
||||
|
||||
INT
|
||||
__cdecl
|
||||
PuDbgAssertFailed(
|
||||
IN_OUT LPDEBUG_PRINTS pDebugPrints,
|
||||
IN const char * pszFilePath,
|
||||
IN int nLineNum,
|
||||
IN const char * pszFunctionName,
|
||||
IN const char * pszExpression,
|
||||
IN const char * pszMessage);
|
||||
|
||||
INT
|
||||
WINAPI
|
||||
PuDbgPrintAssertFailed(
|
||||
IN_OUT LPDEBUG_PRINTS pDebugPrints,
|
||||
IN const char * pszFilePath,
|
||||
IN int nLineNum,
|
||||
IN const char * pszFunctionName,
|
||||
IN const char * pszExpression,
|
||||
IN const char * pszMessage);
|
||||
|
||||
VOID
|
||||
PuDbgCaptureContext (
|
||||
OUT PCONTEXT ContextRecord
|
||||
);
|
||||
|
||||
VOID
|
||||
PuDbgPrintCurrentTime(
|
||||
IN_OUT LPDEBUG_PRINTS pDebugPrints,
|
||||
IN const char * pszFilePath,
|
||||
IN int nLineNum,
|
||||
IN const char * pszFunctionName
|
||||
);
|
||||
|
||||
VOID
|
||||
PuSetDbgOutputFlags(
|
||||
IN_OUT LPDEBUG_PRINTS pDebugPrints,
|
||||
IN DWORD dwFlags);
|
||||
|
||||
DWORD
|
||||
PuGetDbgOutputFlags(
|
||||
IN const LPDEBUG_PRINTS pDebugPrints);
|
||||
|
||||
|
||||
//
|
||||
// Following functions return Win32 error codes.
|
||||
// NO_ERROR if success
|
||||
//
|
||||
|
||||
DWORD
|
||||
PuOpenDbgPrintFile(
|
||||
IN_OUT LPDEBUG_PRINTS pDebugPrints,
|
||||
IN const char * pszFileName,
|
||||
IN const char * pszPathForFile);
|
||||
|
||||
DWORD
|
||||
PuReOpenDbgPrintFile(
|
||||
IN_OUT LPDEBUG_PRINTS pDebugPrints);
|
||||
|
||||
DWORD
|
||||
PuCloseDbgPrintFile(
|
||||
IN_OUT LPDEBUG_PRINTS pDebugPrints);
|
||||
|
||||
DWORD
|
||||
PuOpenDbgMemoryLog(
|
||||
IN_OUT LPDEBUG_PRINTS pDebugPrints);
|
||||
|
||||
DWORD
|
||||
PuCloseDbgMemoryLog(
|
||||
IN_OUT LPDEBUG_PRINTS pDebugPrints);
|
||||
|
||||
DWORD
|
||||
PuLoadDebugFlagsFromReg(IN HKEY hkey, IN DWORD dwDefault);
|
||||
|
||||
DWORD
|
||||
PuLoadDebugFlagsFromRegStr(IN LPCSTR pszRegKey, IN DWORD dwDefault);
|
||||
|
||||
DWORD
|
||||
PuSaveDebugFlagsInReg(IN HKEY hkey, IN DWORD dwDbg);
|
||||
|
||||
|
||||
# define PuPrintToKdb( pszOutput) \
|
||||
if ( pszOutput != NULL) { \
|
||||
OutputDebugString( pszOutput); \
|
||||
} else {}
|
||||
|
||||
|
||||
|
||||
# ifdef __cplusplus
|
||||
};
|
||||
# endif // __cplusplus
|
||||
|
||||
// begin_user_unmodifiable
|
||||
|
||||
|
||||
|
||||
/***********************************************************
|
||||
* Macros
|
||||
************************************************************/
|
||||
|
||||
|
||||
extern
|
||||
#ifdef __cplusplus
|
||||
"C"
|
||||
# endif // _cplusplus
|
||||
DEBUG_PRINTS * g_pDebug; // define a global debug variable
|
||||
|
||||
# if DBG
|
||||
|
||||
// For the CHK build we want ODS enabled. For an explanation of these flags see
|
||||
// the comment just after the definition of DBG_CONTEXT
|
||||
# define DECLARE_DEBUG_PRINTS_OBJECT() \
|
||||
DEBUG_PRINTS * g_pDebug = NULL; \
|
||||
DWORD DEBUG_FLAGS_VAR = DEBUG_FLAG_ERROR;
|
||||
|
||||
#else // !DBG
|
||||
|
||||
# define DECLARE_DEBUG_PRINTS_OBJECT() \
|
||||
DEBUG_PRINTS * g_pDebug = NULL; \
|
||||
DWORD DEBUG_FLAGS_VAR = 0;
|
||||
|
||||
#endif // !DBG
|
||||
|
||||
|
||||
//
|
||||
// Call the following macro as part of your initialization for program
|
||||
// planning to use the debugging class.
|
||||
//
|
||||
/** DEBUGDEBUG
|
||||
# define CREATE_DEBUG_PRINT_OBJECT( pszLabel) \
|
||||
g_pDebug = PuCreateDebugPrintsObject( pszLabel, DEFAULT_OUTPUT_FLAGS);\
|
||||
if ( g_pDebug == NULL) { \
|
||||
OutputDebugStringA( "Unable to Create Debug Print Object \n"); \
|
||||
}
|
||||
*/
|
||||
|
||||
//
|
||||
// Call the following macro once as part of the termination of program
|
||||
// which uses the debugging class.
|
||||
//
|
||||
# define DELETE_DEBUG_PRINT_OBJECT( ) \
|
||||
g_pDebug = PuDeleteDebugPrintsObject( g_pDebug);
|
||||
|
||||
|
||||
# define VALID_DEBUG_PRINT_OBJECT() \
|
||||
( ( g_pDebug != NULL) && g_pDebug->m_fInitialized)
|
||||
|
||||
|
||||
//
|
||||
// Use the DBG_CONTEXT without any surrounding braces.
|
||||
// This is used to pass the values for global DebugPrintObject
|
||||
// and File/Line information
|
||||
//
|
||||
//# define DBG_CONTEXT g_pDebug, __FILE__, __LINE__, __FUNCTION__
|
||||
|
||||
// The 3 main tracing macros, each one corresponds to a different level of
|
||||
// tracing
|
||||
|
||||
// The 3 main tracing macros, each one corresponds to a different level of
|
||||
// tracing
|
||||
//# define DBGINFO(args) {if (DEBUG_FLAGS_VAR & DEBUG_FLAGS_INFO) { PuDbgPrint args; }}
|
||||
//# define DBGWARN(args) {if (DEBUG_FLAGS_VAR & DEBUG_FLAGS_WARN) { PuDbgPrint args; }}
|
||||
//# define DBGERROR(args) {if (DEBUG_FLAGS_VAR & DEBUG_FLAGS_ERROR) { PuDbgPrint args; }}
|
||||
|
||||
# define DBGINFOW(args) {if (DEBUG_FLAGS_VAR & DEBUG_FLAGS_INFO) { PuDbgPrintW args; }}
|
||||
# define DBGWARNW(args) {if (DEBUG_FLAGS_VAR & DEBUG_FLAGS_WARN) { PuDbgPrintW args; }}
|
||||
# define DBGERRORW(args) {if (DEBUG_FLAGS_VAR & DEBUG_FLAGS_ERROR) { PuDbgPrintW args; }}
|
||||
|
||||
|
||||
//
|
||||
// DBGPRINTF() is printing function ( much like printf) but always called
|
||||
// with the DBG_CONTEXT as follows
|
||||
// DBGPRINTF( ( DBG_CONTEXT, format-string, arguments for format list));
|
||||
//
|
||||
# define DBGPRINTF DBGINFO
|
||||
|
||||
//
|
||||
// DPERROR() is printing function ( much like printf) but always called
|
||||
// with the DBG_CONTEXT as follows
|
||||
// DPERROR( ( DBG_CONTEXT, error, format-string,
|
||||
// arguments for format list));
|
||||
//
|
||||
# define DPERROR( args) {if (DEBUG_FLAGS_VAR & DEBUG_FLAGS_ERROR) { PuDbgPrintError args; }}
|
||||
|
||||
# if DBG
|
||||
|
||||
# define DBG_CODE(s) s /* echoes code in debugging mode */
|
||||
|
||||
// The same 3 main tracing macros however in this case the macros are only compiled
|
||||
// into the CHK build. This is necessary because some tracing info used functions or
|
||||
// variables which are not compiled into the FRE build.
|
||||
# define CHKINFO(args) { PuDbgPrint args; }
|
||||
# define CHKWARN(args) { PuDbgPrint args; }
|
||||
# define CHKERROR(args) { PuDbgPrint args; }
|
||||
|
||||
# define CHKINFOW(args) { PuDbgPrintW args; }
|
||||
# define CHKWARNW(args) { PuDbgPrintW args; }
|
||||
# define CHKERRORW(args) { PuDbgPrintW args; }
|
||||
|
||||
|
||||
#ifndef DBG_ASSERT
|
||||
# ifdef _PREFAST_
|
||||
# define DBG_ASSERT(exp) ((void)0) /* Do Nothing */
|
||||
# define DBG_ASSERT_MSG(exp, pszMsg) ((void)0) /* Do Nothing */
|
||||
# define DBG_REQUIRE( exp) ((void) (exp))
|
||||
# else // !_PREFAST_
|
||||
# define DBG_ASSERT( exp ) \
|
||||
( (VOID)( ( exp ) || ( DebugBreak(), \
|
||||
PuDbgPrintAssertFailed( DBG_CONTEXT, #exp, "" ) ) ) )
|
||||
|
||||
# define DBG_ASSERT_MSG( exp, pszMsg) \
|
||||
( (VOID)( ( exp ) || ( DebugBreak(), \
|
||||
PuDbgPrintAssertFailed( DBG_CONTEXT, #exp, pszMsg ) ) ) )
|
||||
|
||||
# define DBG_REQUIRE( exp ) \
|
||||
DBG_ASSERT( exp )
|
||||
# endif // !_PREFAST_
|
||||
#endif
|
||||
|
||||
|
||||
# define DBG_LOG() PuDbgPrint( DBG_CONTEXT, "\n" )
|
||||
|
||||
# define DBG_OPEN_LOG_FILE( pszFile, pszPath ) \
|
||||
PuOpenDbgPrintFile( g_pDebug, (pszFile), (pszPath) )
|
||||
|
||||
# define DBG_CLOSE_LOG_FILE( ) \
|
||||
PuCloseDbgPrintFile( g_pDebug )
|
||||
|
||||
# define DBG_OPEN_MEMORY_LOG( ) \
|
||||
PuOpenDbgMemoryLog( g_pDebug )
|
||||
|
||||
|
||||
# define DBGDUMP( args ) PuDbgDump args
|
||||
|
||||
# define DBGPRINT_CURRENT_TIME() PuDbgPrintCurrentTime( DBG_CONTEXT )
|
||||
|
||||
# else // !DBG
|
||||
|
||||
# define DBG_CODE(s) ((void)0) /* Do Nothing */
|
||||
|
||||
# define CHKINFO(args) ((void)0) /* Do Nothing */
|
||||
# define CHKWARN(args) ((void)0) /* Do Nothing */
|
||||
# define CHKERROR(args) ((void)0) /* Do Nothing */
|
||||
|
||||
# define CHKINFOW(args) ((void)0) /* Do Nothing */
|
||||
# define CHKWARNW(args) ((void)0) /* Do Nothing */
|
||||
# define CHKERRORW(args) ((void)0) /* Do Nothing */
|
||||
|
||||
#ifndef DBG_ASSERT
|
||||
# define DBG_ASSERT(exp) ((void)0) /* Do Nothing */
|
||||
|
||||
# define DBG_ASSERT_MSG(exp, pszMsg) ((void)0) /* Do Nothing */
|
||||
|
||||
# define DBG_REQUIRE( exp) ((void) (exp))
|
||||
#endif // !DBG_ASSERT
|
||||
|
||||
# define DBGDUMP( args) ((void)0) /* Do nothing */
|
||||
|
||||
# define DBG_LOG() ((void)0) /* Do Nothing */
|
||||
|
||||
# define DBG_OPEN_LOG_FILE( pszFile, pszPath) ((void)0) /* Do Nothing */
|
||||
|
||||
# define DBG_OPEN_MEMORY_LOG() ((void)0) /* Do Nothing */
|
||||
|
||||
# define DBG_CLOSE_LOG_FILE() ((void)0) /* Do Nothing */
|
||||
|
||||
# define DBGPRINT_CURRENT_TIME() ((void)0) /* Do Nothing */
|
||||
|
||||
# endif // !DBG
|
||||
|
||||
|
||||
// end_user_unmodifiable
|
||||
|
||||
// begin_user_unmodifiable
|
||||
|
||||
|
||||
#ifdef ASSERT
|
||||
# undef ASSERT
|
||||
#endif
|
||||
|
||||
|
||||
# define ASSERT( exp) DBG_ASSERT( exp)
|
||||
|
||||
|
||||
// end_user_unmodifiable
|
||||
|
||||
// begin_user_modifiable
|
||||
|
||||
//
|
||||
// Debugging constants consist of two pieces.
|
||||
// All constants in the range 0x0 to 0x8000 are reserved
|
||||
// User extensions may include additional constants (bit flags)
|
||||
//
|
||||
|
||||
# define DEBUG_API_ENTRY 0x00000001L
|
||||
# define DEBUG_API_EXIT 0x00000002L
|
||||
# define DEBUG_INIT_CLEAN 0x00000004L
|
||||
# define DEBUG_ERROR 0x00000008L
|
||||
|
||||
// End of Reserved Range
|
||||
# define DEBUG_RESERVED 0x00000FFFL
|
||||
|
||||
// end_user_modifiable
|
||||
|
||||
|
||||
|
||||
/***********************************************************
|
||||
* Platform Type related variables and macros
|
||||
************************************************************/
|
||||
|
||||
//
|
||||
// Enum for product types
|
||||
//
|
||||
|
||||
typedef enum _PLATFORM_TYPE {
|
||||
|
||||
PtInvalid = 0, // Invalid
|
||||
PtNtWorkstation = 1, // NT Workstation
|
||||
PtNtServer = 2, // NT Server
|
||||
|
||||
} PLATFORM_TYPE;
|
||||
|
||||
//
|
||||
// IISGetPlatformType is the function used to the platform type
|
||||
//
|
||||
|
||||
extern
|
||||
#ifdef __cplusplus
|
||||
"C"
|
||||
# endif // _cplusplus
|
||||
PLATFORM_TYPE
|
||||
IISGetPlatformType(
|
||||
VOID
|
||||
);
|
||||
|
||||
//
|
||||
// External Macros
|
||||
//
|
||||
|
||||
#define InetIsNtServer( _pt ) ((_pt) == PtNtServer)
|
||||
#define InetIsNtWksta( _pt ) ((_pt) == PtNtWorkstation)
|
||||
#define InetIsValidPT(_pt) ((_pt) != PtInvalid)
|
||||
|
||||
extern
|
||||
#ifdef __cplusplus
|
||||
"C"
|
||||
# endif // _cplusplus
|
||||
PLATFORM_TYPE g_PlatformType;
|
||||
|
||||
|
||||
// Use the DECLARE_PLATFORM_TYPE macro to declare the platform type
|
||||
#define DECLARE_PLATFORM_TYPE() \
|
||||
PLATFORM_TYPE g_PlatformType = PtInvalid;
|
||||
|
||||
// Use the INITIALIZE_PLATFORM_TYPE to init the platform type
|
||||
// This should typically go inside the DLLInit or equivalent place.
|
||||
#define INITIALIZE_PLATFORM_TYPE() \
|
||||
g_PlatformType = IISGetPlatformType();
|
||||
|
||||
//
|
||||
// Additional Macros to use the Platform Type
|
||||
//
|
||||
|
||||
#define TsIsNtServer( ) InetIsNtServer(g_PlatformType)
|
||||
#define TsIsNtWksta( ) InetIsNtWksta(g_PlatformType)
|
||||
#define IISIsValidPlatform() InetIsValidPT(g_PlatformType)
|
||||
#define IISPlatformType() (g_PlatformType)
|
||||
|
||||
|
||||
/***********************************************************
|
||||
* Some utility functions for Critical Sections
|
||||
************************************************************/
|
||||
|
||||
//
|
||||
// IISSetCriticalSectionSpinCount() provides a thunk for the
|
||||
// original NT4.0sp3 API SetCriticalSectionSpinCount() for CS with Spin counts
|
||||
// Users of this function should definitely dynlink with kernel32.dll,
|
||||
// Otherwise errors will surface to a large extent
|
||||
//
|
||||
extern
|
||||
# ifdef __cplusplus
|
||||
"C"
|
||||
# endif // _cplusplus
|
||||
DWORD
|
||||
IISSetCriticalSectionSpinCount(
|
||||
LPCRITICAL_SECTION lpCriticalSection,
|
||||
DWORD dwSpinCount
|
||||
);
|
||||
|
||||
|
||||
//
|
||||
// Macro for the calls to SetCriticalSectionSpinCount()
|
||||
//
|
||||
# define SET_CRITICAL_SECTION_SPIN_COUNT( lpCS, dwSpins) \
|
||||
IISSetCriticalSectionSpinCount( (lpCS), (dwSpins))
|
||||
|
||||
//
|
||||
// IIS_DEFAULT_CS_SPIN_COUNT is the default value of spins used by
|
||||
// Critical sections defined within IIS.
|
||||
// NYI: We should have to switch the individual values based on experiments!
|
||||
// Current value is an arbitrary choice
|
||||
//
|
||||
# define IIS_DEFAULT_CS_SPIN_COUNT (1000)
|
||||
|
||||
//
|
||||
// Initializes a critical section and sets its spin count
|
||||
// to IIS_DEFAULT_CS_SPIN_COUNT. Equivalent to
|
||||
// InitializeCriticalSectionAndSpinCount(lpCS, IIS_DEFAULT_CS_SPIN_COUNT),
|
||||
// but provides a safe thunking layer for older systems that don't provide
|
||||
// this API.
|
||||
//
|
||||
extern
|
||||
# ifdef __cplusplus
|
||||
"C"
|
||||
# endif // _cplusplus
|
||||
BOOL
|
||||
IISInitializeCriticalSection(
|
||||
LPCRITICAL_SECTION lpCriticalSection
|
||||
);
|
||||
|
||||
//
|
||||
// Macro for the calls to InitializeCriticalSection()
|
||||
//
|
||||
# define INITIALIZE_CRITICAL_SECTION(lpCS) IISInitializeCriticalSection(lpCS)
|
||||
|
||||
# endif /* _DEBUG_HXX_ */
|
||||
|
||||
//
|
||||
// The following macros allow the automatic naming of certain Win32 objects.
|
||||
// See IIS\SVCS\IISRTL\WIN32OBJ.C for details on the naming convention.
|
||||
//
|
||||
// Set IIS_NAMED_WIN32_OBJECTS to a non-zero value to enable named events,
|
||||
// semaphores, and mutexes.
|
||||
//
|
||||
|
||||
#if DBG
|
||||
#define IIS_NAMED_WIN32_OBJECTS 1
|
||||
#else
|
||||
#define IIS_NAMED_WIN32_OBJECTS 0
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
HANDLE
|
||||
PuDbgCreateEvent(
|
||||
__in LPSTR FileName,
|
||||
IN ULONG LineNumber,
|
||||
__in LPSTR MemberName,
|
||||
IN PVOID Address,
|
||||
IN BOOL ManualReset,
|
||||
IN BOOL InitialState
|
||||
);
|
||||
|
||||
HANDLE
|
||||
PuDbgCreateSemaphore(
|
||||
__in LPSTR FileName,
|
||||
IN ULONG LineNumber,
|
||||
__in LPSTR MemberName,
|
||||
IN PVOID Address,
|
||||
IN LONG InitialCount,
|
||||
IN LONG MaximumCount
|
||||
);
|
||||
|
||||
HANDLE
|
||||
PuDbgCreateMutex(
|
||||
__in LPSTR FileName,
|
||||
IN ULONG LineNumber,
|
||||
__in LPSTR MemberName,
|
||||
IN PVOID Address,
|
||||
IN BOOL InitialOwner
|
||||
);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#if IIS_NAMED_WIN32_OBJECTS
|
||||
|
||||
#define IIS_CREATE_EVENT( membername, address, manual, state ) \
|
||||
PuDbgCreateEvent( \
|
||||
(LPSTR)__FILE__, \
|
||||
(ULONG)__LINE__, \
|
||||
(membername), \
|
||||
(PVOID)(address), \
|
||||
(manual), \
|
||||
(state) \
|
||||
)
|
||||
|
||||
#define IIS_CREATE_SEMAPHORE( membername, address, initial, maximum ) \
|
||||
PuDbgCreateSemaphore( \
|
||||
(LPSTR)__FILE__, \
|
||||
(ULONG)__LINE__, \
|
||||
(membername), \
|
||||
(PVOID)(address), \
|
||||
(initial), \
|
||||
(maximum) \
|
||||
)
|
||||
|
||||
#define IIS_CREATE_MUTEX( membername, address, initial ) \
|
||||
PuDbgCreateMutex( \
|
||||
(LPSTR)__FILE__, \
|
||||
(ULONG)__LINE__, \
|
||||
(membername), \
|
||||
(PVOID)(address), \
|
||||
(initial) \
|
||||
)
|
||||
|
||||
#else // !IIS_NAMED_WIN32_OBJECTS
|
||||
|
||||
#define IIS_CREATE_EVENT( membername, address, manual, state ) \
|
||||
CreateEventA( \
|
||||
NULL, \
|
||||
(manual), \
|
||||
(state), \
|
||||
NULL \
|
||||
)
|
||||
|
||||
#define IIS_CREATE_SEMAPHORE( membername, address, initial, maximum ) \
|
||||
CreateSemaphoreA( \
|
||||
NULL, \
|
||||
(initial), \
|
||||
(maximum), \
|
||||
NULL \
|
||||
)
|
||||
|
||||
#define IIS_CREATE_MUTEX( membername, address, initial ) \
|
||||
CreateMutexA( \
|
||||
NULL, \
|
||||
(initial), \
|
||||
NULL \
|
||||
)
|
||||
|
||||
#endif // IIS_NAMED_WIN32_OBJECTS
|
||||
|
||||
|
||||
/************************ End of File ***********************/
|
||||
|
||||
|
|
@ -0,0 +1,229 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
#include <windows.h>
|
||||
#include "dbgutil.h"
|
||||
#include "pudebug.h"
|
||||
#include "reftrace.h"
|
||||
|
||||
|
||||
PTRACE_LOG
|
||||
CreateRefTraceLog(
|
||||
IN LONG LogSize,
|
||||
IN LONG ExtraBytesInHeader
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Creates a new (empty) ref count trace log buffer.
|
||||
|
||||
Arguments:
|
||||
|
||||
LogSize - The number of entries in the log.
|
||||
|
||||
ExtraBytesInHeader - The number of extra bytes to include in the
|
||||
log header. This is useful for adding application-specific
|
||||
data to the log.
|
||||
|
||||
Return Value:
|
||||
|
||||
PTRACE_LOG - Pointer to the newly created log if successful,
|
||||
NULL otherwise.
|
||||
|
||||
--*/
|
||||
{
|
||||
|
||||
return CreateTraceLog(
|
||||
LogSize,
|
||||
ExtraBytesInHeader,
|
||||
sizeof(REF_TRACE_LOG_ENTRY)
|
||||
);
|
||||
|
||||
} // CreateRefTraceLog
|
||||
|
||||
|
||||
VOID
|
||||
DestroyRefTraceLog(
|
||||
IN PTRACE_LOG Log
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Destroys a ref count trace log buffer created with CreateRefTraceLog().
|
||||
|
||||
Arguments:
|
||||
|
||||
Log - The ref count trace log buffer to destroy.
|
||||
|
||||
Return Value:
|
||||
|
||||
None.
|
||||
|
||||
--*/
|
||||
{
|
||||
|
||||
DestroyTraceLog( Log );
|
||||
|
||||
} // DestroyRefTraceLog
|
||||
|
||||
|
||||
//
|
||||
// N.B. For RtlCaptureBacktrace() to work properly, the calling function
|
||||
// *must* be __cdecl, and must have a "normal" stack frame. So, we decorate
|
||||
// WriteRefTraceLog[Ex]() with the __cdecl modifier and disable the frame
|
||||
// pointer omission (FPO) optimization.
|
||||
//
|
||||
|
||||
//#pragma optimize( "y", off ) // disable frame pointer omission (FPO)
|
||||
#pragma optimize( "", off ) // disable frame pointer omission (FPO)
|
||||
|
||||
LONG
|
||||
__cdecl
|
||||
WriteRefTraceLog(
|
||||
IN PTRACE_LOG Log,
|
||||
IN LONG NewRefCount,
|
||||
IN CONST VOID * Context
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Writes a new entry to the specified ref count trace log. The entry
|
||||
written contains the updated reference count and a stack backtrace
|
||||
leading up to the current caller.
|
||||
|
||||
Arguments:
|
||||
|
||||
Log - The log to write to.
|
||||
|
||||
NewRefCount - The updated reference count.
|
||||
|
||||
Context - An uninterpreted context to associate with the log entry.
|
||||
|
||||
Return Value:
|
||||
|
||||
Index of entry in log.
|
||||
|
||||
--*/
|
||||
{
|
||||
|
||||
return WriteRefTraceLogEx(
|
||||
Log,
|
||||
NewRefCount,
|
||||
Context,
|
||||
REF_TRACE_EMPTY_CONTEXT, // suppress use of optional extra contexts
|
||||
REF_TRACE_EMPTY_CONTEXT,
|
||||
REF_TRACE_EMPTY_CONTEXT
|
||||
);
|
||||
|
||||
} // WriteRefTraceLog
|
||||
|
||||
|
||||
|
||||
|
||||
LONG
|
||||
__cdecl
|
||||
WriteRefTraceLogEx(
|
||||
IN PTRACE_LOG Log,
|
||||
IN LONG NewRefCount,
|
||||
IN CONST VOID * Context,
|
||||
IN CONST VOID * Context1, // optional extra context
|
||||
IN CONST VOID * Context2, // optional extra context
|
||||
IN CONST VOID * Context3 // optional extra context
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Writes a new "extended" entry to the specified ref count trace log.
|
||||
The entry written contains the updated reference count, stack backtrace
|
||||
leading up to the current caller and extra context information.
|
||||
|
||||
Arguments:
|
||||
|
||||
Log - The log to write to.
|
||||
|
||||
NewRefCount - The updated reference count.
|
||||
|
||||
Context - An uninterpreted context to associate with the log entry.
|
||||
Context1 - An uninterpreted context to associate with the log entry.
|
||||
Context2 - An uninterpreted context to associate with the log entry.
|
||||
Context3 - An uninterpreted context to associate with the log entry.
|
||||
|
||||
NOTE Context1/2/3 are "optional" in that the caller may suppress
|
||||
debug display of these values by passing REF_TRACE_EMPTY_CONTEXT
|
||||
for each of them.
|
||||
|
||||
Return Value:
|
||||
|
||||
Index of entry in log.
|
||||
|
||||
--*/
|
||||
{
|
||||
|
||||
REF_TRACE_LOG_ENTRY entry;
|
||||
ULONG hash;
|
||||
DWORD cStackFramesSkipped;
|
||||
|
||||
//
|
||||
// Initialize the entry.
|
||||
//
|
||||
|
||||
RtlZeroMemory(
|
||||
&entry,
|
||||
sizeof(entry)
|
||||
);
|
||||
|
||||
//
|
||||
// Set log entry members.
|
||||
//
|
||||
|
||||
entry.NewRefCount = NewRefCount;
|
||||
entry.Context = Context;
|
||||
entry.Thread = GetCurrentThreadId();
|
||||
entry.Context1 = Context1;
|
||||
entry.Context2 = Context2;
|
||||
entry.Context3 = Context3;
|
||||
|
||||
//
|
||||
// Capture the stack backtrace. Normally, we skip two stack frames:
|
||||
// one for this routine, and one for RtlCaptureBacktrace() itself.
|
||||
// For non-Ex callers who come in via WriteRefTraceLog,
|
||||
// we skip three stack frames.
|
||||
//
|
||||
|
||||
if ( entry.Context1 == REF_TRACE_EMPTY_CONTEXT
|
||||
&& entry.Context2 == REF_TRACE_EMPTY_CONTEXT
|
||||
&& entry.Context3 == REF_TRACE_EMPTY_CONTEXT
|
||||
) {
|
||||
|
||||
cStackFramesSkipped = 2;
|
||||
|
||||
} else {
|
||||
|
||||
cStackFramesSkipped = 1;
|
||||
|
||||
}
|
||||
|
||||
RtlCaptureStackBackTrace(
|
||||
cStackFramesSkipped,
|
||||
REF_TRACE_LOG_STACK_DEPTH,
|
||||
entry.Stack,
|
||||
&hash
|
||||
);
|
||||
|
||||
//
|
||||
// Write it to the log.
|
||||
//
|
||||
|
||||
return WriteTraceLog(
|
||||
Log,
|
||||
&entry
|
||||
);
|
||||
|
||||
} // WriteRefTraceLogEx
|
||||
|
||||
#pragma optimize( "", on ) // restore frame pointer omission (FPO)
|
||||
|
||||
|
|
@ -0,0 +1,87 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
#ifndef _REFTRACE_H_
|
||||
#define _REFTRACE_H_
|
||||
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
#include <Windows.h>
|
||||
#include "tracelog.h"
|
||||
|
||||
//
|
||||
// This is the number of stack backtrace values captured in each
|
||||
// trace log entry. This value is chosen to make the log entry
|
||||
// exactly twelve dwords long, making it a bit easier to interpret
|
||||
// from within the debugger without the debugger extension.
|
||||
//
|
||||
|
||||
#define REF_TRACE_LOG_STACK_DEPTH 9
|
||||
|
||||
// No-op value for the Context1,2,3 parameters of WriteRefTraceLogEx
|
||||
//#define REF_TRACE_EMPTY_CONTEXT ((PVOID) -1)
|
||||
#define REF_TRACE_EMPTY_CONTEXT NULL
|
||||
|
||||
|
||||
//
|
||||
// This defines the entry written to the trace log.
|
||||
//
|
||||
|
||||
typedef struct _REF_TRACE_LOG_ENTRY {
|
||||
|
||||
LONG NewRefCount;
|
||||
CONST VOID * Context;
|
||||
CONST VOID * Context1;
|
||||
CONST VOID * Context2;
|
||||
CONST VOID * Context3;
|
||||
DWORD Thread;
|
||||
PVOID Stack[REF_TRACE_LOG_STACK_DEPTH];
|
||||
|
||||
} REF_TRACE_LOG_ENTRY, *PREF_TRACE_LOG_ENTRY;
|
||||
|
||||
|
||||
//
|
||||
// Manipulators.
|
||||
//
|
||||
|
||||
PTRACE_LOG
|
||||
CreateRefTraceLog(
|
||||
IN LONG LogSize,
|
||||
IN LONG ExtraBytesInHeader
|
||||
);
|
||||
|
||||
VOID
|
||||
DestroyRefTraceLog(
|
||||
IN PTRACE_LOG Log
|
||||
);
|
||||
|
||||
LONG
|
||||
__cdecl
|
||||
WriteRefTraceLog(
|
||||
IN PTRACE_LOG Log,
|
||||
IN LONG NewRefCount,
|
||||
IN CONST VOID * Context
|
||||
);
|
||||
|
||||
LONG
|
||||
__cdecl
|
||||
WriteRefTraceLogEx(
|
||||
IN PTRACE_LOG Log,
|
||||
IN LONG NewRefCount,
|
||||
IN CONST VOID * Context,
|
||||
IN CONST VOID * Context1,
|
||||
IN CONST VOID * Context2,
|
||||
IN CONST VOID * Context3
|
||||
);
|
||||
|
||||
|
||||
#if defined(__cplusplus)
|
||||
} // extern "C"
|
||||
#endif // __cplusplus
|
||||
|
||||
|
||||
#endif // _REFTRACE_H_
|
||||
|
||||
|
|
@ -0,0 +1,193 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
#if (_WIN32_WINNT < 0x600)
|
||||
|
||||
//
|
||||
// XP implementation.
|
||||
//
|
||||
class CWSDRWLock
|
||||
{
|
||||
public:
|
||||
|
||||
CWSDRWLock()
|
||||
: m_bInited(FALSE)
|
||||
{
|
||||
}
|
||||
|
||||
~CWSDRWLock()
|
||||
{
|
||||
if (m_bInited)
|
||||
{
|
||||
DeleteCriticalSection(&m_rwLock.critsec);
|
||||
CloseHandle(m_rwLock.ReadersDoneEvent);
|
||||
}
|
||||
}
|
||||
|
||||
BOOL QueryInited() const
|
||||
{
|
||||
return m_bInited;
|
||||
}
|
||||
|
||||
HRESULT Init()
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
if (FALSE == m_bInited)
|
||||
{
|
||||
m_rwLock.fWriterWaiting = FALSE;
|
||||
m_rwLock.LockCount = 0;
|
||||
if ( !InitializeCriticalSectionAndSpinCount( &m_rwLock.critsec, 0 ))
|
||||
{
|
||||
DWORD dwError = GetLastError();
|
||||
hr = HRESULT_FROM_WIN32(dwError);
|
||||
return hr;
|
||||
}
|
||||
|
||||
m_rwLock.ReadersDoneEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||
if( NULL == m_rwLock.ReadersDoneEvent )
|
||||
{
|
||||
DWORD dwError = GetLastError();
|
||||
hr = HRESULT_FROM_WIN32(dwError);
|
||||
DeleteCriticalSection(&m_rwLock.critsec);
|
||||
return hr;
|
||||
}
|
||||
m_bInited = TRUE;
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
void SharedAcquire()
|
||||
{
|
||||
EnterCriticalSection(&m_rwLock.critsec);
|
||||
InterlockedIncrement(&m_rwLock.LockCount);
|
||||
LeaveCriticalSection(&m_rwLock.critsec);
|
||||
}
|
||||
|
||||
void SharedRelease()
|
||||
{
|
||||
ReleaseRWLock();
|
||||
}
|
||||
|
||||
void ExclusiveAcquire()
|
||||
{
|
||||
EnterCriticalSection( &m_rwLock.critsec );
|
||||
|
||||
m_rwLock.fWriterWaiting = TRUE;
|
||||
|
||||
// check if there are any readers active
|
||||
if ( InterlockedExchangeAdd( &m_rwLock.LockCount, 0 ) > 0 )
|
||||
{
|
||||
//
|
||||
// Wait for all the readers to get done..
|
||||
//
|
||||
WaitForSingleObject( m_rwLock.ReadersDoneEvent, INFINITE );
|
||||
}
|
||||
m_rwLock.LockCount = -1;
|
||||
}
|
||||
|
||||
void ExclusiveRelease()
|
||||
{
|
||||
ReleaseRWLock();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
BOOL m_bInited;
|
||||
|
||||
typedef struct _RW_LOCK
|
||||
{
|
||||
BOOL fWriterWaiting; // Is a writer waiting on the lock?
|
||||
LONG LockCount;
|
||||
CRITICAL_SECTION critsec;
|
||||
HANDLE ReadersDoneEvent;
|
||||
} RW_LOCK, *PRW_LOCK;
|
||||
|
||||
RW_LOCK m_rwLock;
|
||||
|
||||
private:
|
||||
|
||||
void ReleaseRWLock()
|
||||
{
|
||||
LONG Count = InterlockedDecrement( &m_rwLock.LockCount );
|
||||
|
||||
if ( 0 <= Count )
|
||||
{
|
||||
// releasing a read lock
|
||||
if (( m_rwLock.fWriterWaiting ) && ( 0 == Count ))
|
||||
{
|
||||
SetEvent( m_rwLock.ReadersDoneEvent );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Releasing a write lock
|
||||
m_rwLock.LockCount = 0;
|
||||
m_rwLock.fWriterWaiting = FALSE;
|
||||
LeaveCriticalSection(&m_rwLock.critsec);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
//
|
||||
// Implementation for Windows Vista or greater.
|
||||
//
|
||||
class CWSDRWLock
|
||||
{
|
||||
public:
|
||||
|
||||
CWSDRWLock()
|
||||
{
|
||||
InitializeSRWLock(&m_rwLock);
|
||||
}
|
||||
|
||||
BOOL QueryInited()
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
HRESULT Init()
|
||||
{
|
||||
//
|
||||
// Method defined to keep compatibility with CWSDRWLock class for XP.
|
||||
//
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
void SharedAcquire()
|
||||
{
|
||||
AcquireSRWLockShared(&m_rwLock);
|
||||
}
|
||||
|
||||
void SharedRelease()
|
||||
{
|
||||
ReleaseSRWLockShared(&m_rwLock);
|
||||
}
|
||||
|
||||
void ExclusiveAcquire()
|
||||
{
|
||||
AcquireSRWLockExclusive(&m_rwLock);
|
||||
}
|
||||
|
||||
void ExclusiveRelease()
|
||||
{
|
||||
ReleaseSRWLockExclusive(&m_rwLock);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
SRWLOCK m_rwLock;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
//
|
||||
// Rename the lock class to a more clear name.
|
||||
//
|
||||
typedef CWSDRWLock READ_WRITE_LOCK;
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,515 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "buffer.h"
|
||||
#include "macros.h"
|
||||
#include <strsafe.h>
|
||||
|
||||
class STRA
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
STRA(
|
||||
VOID
|
||||
);
|
||||
|
||||
STRA(
|
||||
__inout_ecount(cchInit) CHAR* pbInit,
|
||||
__in DWORD cchInit
|
||||
);
|
||||
|
||||
BOOL
|
||||
IsEmpty(
|
||||
VOID
|
||||
) const;
|
||||
|
||||
BOOL
|
||||
Equals(
|
||||
__in PCSTR pszRhs,
|
||||
__in BOOL fIgnoreCase = FALSE
|
||||
) const;
|
||||
|
||||
BOOL
|
||||
Equals(
|
||||
__in const STRA * pstrRhs,
|
||||
__in BOOL fIgnoreCase = FALSE
|
||||
) const;
|
||||
|
||||
BOOL
|
||||
Equals(
|
||||
__in const STRA & strRhs,
|
||||
__in BOOL fIgnoreCase = FALSE
|
||||
) const;
|
||||
|
||||
static
|
||||
BOOL
|
||||
Equals(
|
||||
__in PCSTR pszLhs,
|
||||
__in PCSTR pszRhs,
|
||||
__in bool fIgnoreCase = false
|
||||
)
|
||||
{
|
||||
// Return FALSE if either or both strings are NULL.
|
||||
if (!pszLhs || !pszRhs) return FALSE;
|
||||
|
||||
if( fIgnoreCase )
|
||||
{
|
||||
return ( 0 == _stricmp( pszLhs, pszRhs ) );
|
||||
}
|
||||
|
||||
return ( 0 == strcmp( pszLhs, pszRhs ) );
|
||||
}
|
||||
|
||||
VOID
|
||||
Trim();
|
||||
|
||||
BOOL
|
||||
StartsWith(
|
||||
__in const STRA * pStraPrefix,
|
||||
__in bool fIgnoreCase = FALSE
|
||||
) const;
|
||||
|
||||
BOOL
|
||||
StartsWith(
|
||||
__in const STRA & straPrefix,
|
||||
__in bool fIgnoreCase = FALSE
|
||||
) const;
|
||||
|
||||
BOOL
|
||||
StartsWith(
|
||||
__in PCSTR pszPrefix,
|
||||
__in bool fIgnoreCase = FALSE
|
||||
) const;
|
||||
|
||||
BOOL
|
||||
EndsWith(
|
||||
__in const STRA * pStraSuffix,
|
||||
__in bool fIgnoreCase = FALSE
|
||||
) const;
|
||||
|
||||
BOOL
|
||||
EndsWith(
|
||||
__in const STRA & straSuffix,
|
||||
__in bool fIgnoreCase = FALSE
|
||||
) const;
|
||||
|
||||
BOOL
|
||||
EndsWith(
|
||||
__in PCSTR pszSuffix,
|
||||
__in bool fIgnoreCase = FALSE
|
||||
) const;
|
||||
|
||||
INT
|
||||
IndexOf(
|
||||
__in CHAR charValue,
|
||||
__in DWORD dwStartIndex = 0
|
||||
) const;
|
||||
|
||||
INT
|
||||
IndexOf(
|
||||
__in PCSTR pszValue,
|
||||
__in DWORD dwStartIndex = 0
|
||||
) const;
|
||||
|
||||
INT
|
||||
LastIndexOf(
|
||||
__in CHAR charValue,
|
||||
__in DWORD dwStartIndex = 0
|
||||
) const;
|
||||
|
||||
DWORD
|
||||
QueryCB(
|
||||
VOID
|
||||
) const;
|
||||
|
||||
DWORD
|
||||
QueryCCH(
|
||||
VOID
|
||||
) const;
|
||||
|
||||
DWORD
|
||||
QuerySizeCCH(
|
||||
VOID
|
||||
) const;
|
||||
|
||||
DWORD
|
||||
QuerySize(
|
||||
VOID
|
||||
) const;
|
||||
|
||||
__nullterminated
|
||||
__bcount(this->m_cchLen)
|
||||
CHAR *
|
||||
QueryStr(
|
||||
VOID
|
||||
) const;
|
||||
|
||||
VOID
|
||||
Reset(
|
||||
VOID
|
||||
);
|
||||
|
||||
HRESULT
|
||||
Resize(
|
||||
__in DWORD cchSize
|
||||
);
|
||||
|
||||
HRESULT
|
||||
SyncWithBuffer(
|
||||
VOID
|
||||
);
|
||||
|
||||
HRESULT
|
||||
Copy(
|
||||
__in PCSTR pszCopy
|
||||
);
|
||||
|
||||
HRESULT
|
||||
Copy(
|
||||
__in_ecount(cbLen)
|
||||
PCSTR pszCopy,
|
||||
__in SIZE_T cbLen
|
||||
);
|
||||
|
||||
HRESULT
|
||||
Copy(
|
||||
__in const STRA * pstrRhs
|
||||
);
|
||||
|
||||
HRESULT
|
||||
Copy(
|
||||
__in const STRA & strRhs
|
||||
);
|
||||
|
||||
HRESULT
|
||||
CopyW(
|
||||
__in PCWSTR pszCopyW
|
||||
);
|
||||
|
||||
HRESULT
|
||||
CopyW(
|
||||
__in_ecount(cchLen)
|
||||
PCWSTR pszCopyW,
|
||||
__in SIZE_T cchLen,
|
||||
__in UINT CodePage = CP_UTF8,
|
||||
__in BOOL fFailIfNoTranslation = FALSE
|
||||
)
|
||||
{
|
||||
_ASSERTE( cchLen <= MAXDWORD );
|
||||
|
||||
return AuxAppendW(
|
||||
pszCopyW,
|
||||
static_cast<DWORD>(cchLen),
|
||||
0,
|
||||
CodePage,
|
||||
fFailIfNoTranslation
|
||||
);
|
||||
}
|
||||
|
||||
HRESULT
|
||||
CopyWTruncate(
|
||||
__in PCWSTR pszCopyWTruncate
|
||||
);
|
||||
|
||||
HRESULT
|
||||
CopyWTruncate(
|
||||
__in_ecount(cchLen)
|
||||
PCWSTR pszCopyWTruncate,
|
||||
__in SIZE_T cchLen
|
||||
);
|
||||
|
||||
HRESULT
|
||||
Append(
|
||||
__in PCSTR pszAppend
|
||||
);
|
||||
|
||||
HRESULT
|
||||
Append(
|
||||
__in_ecount(cbLen)
|
||||
PCSTR pszAppend,
|
||||
__in SIZE_T cbLen
|
||||
);
|
||||
|
||||
HRESULT
|
||||
Append(
|
||||
__in const STRA * pstrRhs
|
||||
);
|
||||
|
||||
HRESULT
|
||||
Append(
|
||||
__in const STRA & strRhs
|
||||
);
|
||||
|
||||
HRESULT
|
||||
AppendW(
|
||||
__in PCWSTR pszAppendW
|
||||
)
|
||||
{
|
||||
HRESULT hr;
|
||||
size_t cchLen;
|
||||
hr = StringCchLengthW( pszAppendW,
|
||||
STRSAFE_MAX_CCH,
|
||||
&cchLen );
|
||||
if ( FAILED( hr ) )
|
||||
{
|
||||
return hr;
|
||||
}
|
||||
return AppendW( pszAppendW, cchLen );
|
||||
}
|
||||
|
||||
HRESULT
|
||||
AppendW(
|
||||
__in_ecount(cchLen)
|
||||
PCWSTR pszAppendW,
|
||||
__in SIZE_T cchLen,
|
||||
__in UINT CodePage = CP_UTF8,
|
||||
__in BOOL fFailIfNoTranslation = FALSE
|
||||
)
|
||||
{
|
||||
_ASSERTE( cchLen <= MAXDWORD );
|
||||
if ( cchLen == 0 )
|
||||
{
|
||||
return S_OK;
|
||||
}
|
||||
return AuxAppendW(
|
||||
pszAppendW,
|
||||
static_cast<DWORD>(cchLen),
|
||||
QueryCB(),
|
||||
CodePage,
|
||||
fFailIfNoTranslation
|
||||
);
|
||||
}
|
||||
|
||||
HRESULT
|
||||
AppendWTruncate(
|
||||
__in PCWSTR pszAppendWTruncate
|
||||
);
|
||||
|
||||
HRESULT
|
||||
AppendWTruncate(
|
||||
__in_ecount(cchLen)
|
||||
PCWSTR pszAppendWTruncate,
|
||||
__in SIZE_T cchLen
|
||||
);
|
||||
|
||||
HRESULT
|
||||
CopyToBuffer(
|
||||
__out_bcount(*pcb) CHAR* pszBuffer,
|
||||
__inout DWORD * pcb
|
||||
) const;
|
||||
|
||||
HRESULT
|
||||
SetLen(
|
||||
__in DWORD cchLen
|
||||
);
|
||||
|
||||
HRESULT
|
||||
SafeSnprintf(
|
||||
__in __format_string
|
||||
PCSTR pszFormatString,
|
||||
...
|
||||
);
|
||||
|
||||
HRESULT
|
||||
SafeVsnprintf(
|
||||
__in __format_string
|
||||
PCSTR pszFormatString,
|
||||
va_list argsList
|
||||
);
|
||||
|
||||
HRESULT
|
||||
Escape(
|
||||
VOID
|
||||
);
|
||||
|
||||
HRESULT
|
||||
EscapeUtf8(
|
||||
VOID
|
||||
);
|
||||
|
||||
VOID
|
||||
Unescape(
|
||||
VOID
|
||||
);
|
||||
|
||||
HRESULT
|
||||
CopyWToUTF8Unescaped(
|
||||
__in LPCWSTR cpchStr
|
||||
);
|
||||
|
||||
HRESULT
|
||||
CopyWToUTF8Unescaped(
|
||||
__in_ecount(cch)
|
||||
LPCWSTR cpchStr,
|
||||
__in DWORD cch
|
||||
);
|
||||
|
||||
HRESULT
|
||||
CopyWToUTF8Escaped(
|
||||
__in LPCWSTR cpchStr
|
||||
);
|
||||
|
||||
HRESULT
|
||||
CopyWToUTF8Escaped(
|
||||
__in_ecount(cch)
|
||||
LPCWSTR cpchStr,
|
||||
__in DWORD cch
|
||||
);
|
||||
|
||||
private:
|
||||
|
||||
//
|
||||
// Avoid C++ errors. This object should never go through a copy
|
||||
// constructor, unintended cast or assignment.
|
||||
//
|
||||
STRA( const STRA &);
|
||||
STRA & operator = (const STRA &);
|
||||
|
||||
HRESULT
|
||||
AuxAppend(
|
||||
__in_ecount(cbLen)
|
||||
LPCSTR pStr,
|
||||
__in DWORD cbLen,
|
||||
__in DWORD cbOffset
|
||||
);
|
||||
|
||||
HRESULT
|
||||
AuxAppendW(
|
||||
__in_ecount(cchAppendW)
|
||||
PCWSTR pszAppendW,
|
||||
__in DWORD cchAppendW,
|
||||
__in DWORD cbOffset,
|
||||
__in UINT CodePage,
|
||||
__in BOOL fFailIfNoTranslation
|
||||
)
|
||||
{
|
||||
DWORD dwFlags = 0;
|
||||
|
||||
if( CP_ACP == CodePage )
|
||||
{
|
||||
dwFlags = WC_NO_BEST_FIT_CHARS;
|
||||
}
|
||||
else if( fFailIfNoTranslation && CodePage == CP_UTF8 )
|
||||
{
|
||||
//
|
||||
// WC_ERR_INVALID_CHARS is only supported in Longhorn or greater.
|
||||
//
|
||||
#if defined( NTDDI_VERSION ) && NTDDI_VERSION >= NTDDI_LONGHORN
|
||||
dwFlags |= WC_ERR_INVALID_CHARS;
|
||||
#else
|
||||
UNREFERENCED_PARAMETER(fFailIfNoTranslation);
|
||||
#endif
|
||||
}
|
||||
|
||||
return AuxAppendW( pszAppendW,
|
||||
cchAppendW,
|
||||
cbOffset,
|
||||
CodePage,
|
||||
fFailIfNoTranslation,
|
||||
dwFlags );
|
||||
}
|
||||
|
||||
HRESULT
|
||||
AuxAppendW(
|
||||
__in_ecount(cchAppendW)
|
||||
PCWSTR pszAppendW,
|
||||
__in DWORD cchAppendW,
|
||||
__in DWORD cbOffset,
|
||||
__in UINT CodePage,
|
||||
__in BOOL fFailIfNoTranslation,
|
||||
__in DWORD dwFlags
|
||||
);
|
||||
|
||||
HRESULT
|
||||
AuxAppendWTruncate(
|
||||
__in_ecount(cchAppendW)
|
||||
__in PCWSTR pszAppendW,
|
||||
__in DWORD cchAppendW,
|
||||
__in DWORD cbOffset
|
||||
);
|
||||
|
||||
static
|
||||
int
|
||||
ConvertUnicodeToCodePage(
|
||||
__in_ecount(dwStringLen)
|
||||
LPCWSTR pszSrcUnicodeString,
|
||||
__inout BUFFER_T<CHAR,1> * pbufDstAnsiString,
|
||||
__in DWORD dwStringLen,
|
||||
__in UINT uCodePage
|
||||
);
|
||||
|
||||
static
|
||||
HRESULT
|
||||
ConvertUnicodeToMultiByte(
|
||||
__in_ecount(dwStringLen)
|
||||
LPCWSTR pszSrcUnicodeString,
|
||||
__in BUFFER_T<CHAR,1> * pbufDstAnsiString,
|
||||
__in DWORD dwStringLen
|
||||
);
|
||||
|
||||
static
|
||||
HRESULT
|
||||
ConvertUnicodeToUTF8(
|
||||
__in_ecount(dwStringLen)
|
||||
LPCWSTR pszSrcUnicodeString,
|
||||
__in BUFFER_T<CHAR,1> * pbufDstAnsiString,
|
||||
__in DWORD dwStringLen
|
||||
);
|
||||
|
||||
typedef bool (* PFN_F_SHOULD_ESCAPE)(BYTE ch);
|
||||
|
||||
HRESULT
|
||||
EscapeInternal(
|
||||
PFN_F_SHOULD_ESCAPE pfnFShouldEscape
|
||||
);
|
||||
|
||||
//
|
||||
// Buffer with an inline buffer of 1,
|
||||
// enough to hold null-terminating character.
|
||||
//
|
||||
BUFFER_T<CHAR,1> m_Buff;
|
||||
DWORD m_cchLen;
|
||||
};
|
||||
|
||||
inline
|
||||
HRESULT
|
||||
AppendToString(
|
||||
ULONGLONG Number,
|
||||
STRA & String
|
||||
)
|
||||
{
|
||||
// prefast complains Append requires input
|
||||
// to be null terminated, so zero initialize
|
||||
// and pass the size of the buffer minus one
|
||||
// to _ui64toa_s
|
||||
CHAR chNumber[32] = {0};
|
||||
if (_ui64toa_s(Number,
|
||||
chNumber,
|
||||
sizeof(chNumber) - sizeof(CHAR),
|
||||
10) != 0)
|
||||
{
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
return String.Append(chNumber);
|
||||
}
|
||||
|
||||
template<DWORD size>
|
||||
CHAR* InitHelper(__out CHAR (&psz)[size])
|
||||
{
|
||||
psz[0] = '\0';
|
||||
return psz;
|
||||
}
|
||||
|
||||
//
|
||||
// Heap operation reduction macros
|
||||
//
|
||||
#define STACK_STRA(name, size) CHAR __ach##name[size];\
|
||||
STRA name(InitHelper(__ach##name), sizeof(__ach##name))
|
||||
|
||||
#define INLINE_STRA(name, size) CHAR __ach##name[size];\
|
||||
STRA name;
|
||||
|
||||
#define INLINE_STRA_INIT(name) name(InitHelper(__ach##name), sizeof(__ach##name))
|
||||
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue