Skip to content

Commit 9d97ff3

Browse files
authored
Load ANCM out of process via global versioning (#895)
1 parent f00d7b3 commit 9d97ff3

24 files changed

+863
-69
lines changed

build/testsite.props

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@
2929

3030
</PropertyGroup>
3131
<ItemGroup Condition="'$(OS)' == 'Windows_NT'">
32-
<None Include="$(MSBuildThisFileDirectory)..\src\AspNetCoreModuleV2\OutOfProcessRequestHandler\bin\$(Configuration)\$(NativeFolder)\aspnetcorev2_outofprocess.dll" CopyToOutputDirectory="PreserveNewest" Visible="true" Link="$(BasePathForRequestHandler)%(FileName)%(Extension)" />
33-
<None Include="$(MSBuildThisFileDirectory)..\src\AspNetCoreModuleV2\OutOfProcessRequestHandler\bin\$(Configuration)\$(NativeFolder)\aspnetcorev2_outofprocess.pdb" CopyToOutputDirectory="PreserveNewest" Visible="true" Link="$(BasePathForRequestHandler)%(FileName)%(Extension)" />
32+
<None Include="$(MSBuildThisFileDirectory)..\src\AspNetCoreModuleV2\OutOfProcessRequestHandler\bin\$(Configuration)\$(NativeFolder)\aspnetcorev2_outofprocess.dll" CopyToOutputDirectory="PreserveNewest" Visible="true" Link="$(BasePathForRequestHandler)\$(AspNetCoreModuleOutOfProcessVersion)\%(FileName)%(Extension)" />
33+
<None Include="$(MSBuildThisFileDirectory)..\src\AspNetCoreModuleV2\OutOfProcessRequestHandler\bin\$(Configuration)\$(NativeFolder)\aspnetcorev2_outofprocess.pdb" CopyToOutputDirectory="PreserveNewest" Visible="true" Link="$(BasePathForRequestHandler)\$(AspNetCoreModuleOutOfProcessVersion)\%(FileName)%(Extension)" />
3434
<None Include="$(MSBuildThisFileDirectory)..\src\AspNetCoreModuleV2\InProcessRequestHandler\bin\$(Configuration)\$(NativeFolder)\aspnetcorev2_inprocess.dll" CopyToOutputDirectory="PreserveNewest" Visible="true" Link="$(BasePathForRequestHandler)%(FileName)%(Extension)" />
3535
<None Include="$(MSBuildThisFileDirectory)..\src\AspNetCoreModuleV2\InProcessRequestHandler\bin\$(Configuration)\$(NativeFolder)\aspnetcorev2_inprocess.pdb" CopyToOutputDirectory="PreserveNewest" Visible="true" Link="$(BasePathForRequestHandler)%(FileName)%(Extension)" />
3636
<None Include="$(MSBuildThisFileDirectory)..\src\AspNetCoreModuleV2\AspNetCore\bin\$(Configuration)\$(NativeFolder)\aspnetcorev2.dll" CopyToOutputDirectory="PreserveNewest" Visible="true" Link="$(BasePathForRequestHandler)%(FileName)%(Extension)" />

nuget/AspNetCoreV2.nuspec

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@
2121
<files>
2222
<file src="src\AspNetCoreModuleV2\AspNetCore\bin\$Configuration$\Win32\aspnetcorev2.dll" target="contentFiles\any\any\x86\aspnetcorev2.dll" />
2323
<file src="src\AspNetCoreModuleV2\AspNetCore\bin\$Configuration$\x64\aspnetcorev2.dll" target="contentFiles\any\any\x64\aspnetcorev2.dll" />
24-
<file src="src\AspNetCoreModuleV2\OutOfProcessRequestHandler\bin\$Configuration$\Win32\aspnetcorev2_outofprocess.dll" target="contentFiles\any\any\x86\aspnetcorev2_outofprocess.dll" />
25-
<file src="src\AspNetCoreModuleV2\OutOfProcessRequestHandler\bin\$Configuration$\x64\aspnetcorev2_outofprocess.dll" target="contentFiles\any\any\x64\aspnetcorev2_outofprocess.dll" />
24+
<file src="src\AspNetCoreModuleV2\OutOfProcessRequestHandler\bin\$Configuration$\Win32\aspnetcorev2_outofprocess.dll" target="contentFiles\any\any\x86\$(AspNetCoreModuleOutOfProcessVersion)\aspnetcorev2_outofprocess.dll" />
25+
<file src="src\AspNetCoreModuleV2\OutOfProcessRequestHandler\bin\$Configuration$\x64\aspnetcorev2_outofprocess.dll" target="contentFiles\any\any\x64\$(AspNetCoreModuleOutOfProcessVersion)\aspnetcorev2_outofprocess.dll" />
2626
<file src="src\AspNetCoreModuleV2\InProcessRequestHandler\bin\$Configuration$\Win32\aspnetcorev2_inprocess.dll" target="contentFiles\any\any\x86\aspnetcorev2_inprocess.dll" />
2727
<file src="src\AspNetCoreModuleV2\InProcessRequestHandler\bin\$Configuration$\x64\aspnetcorev2_inprocess.dll" target="contentFiles\any\any\x64\aspnetcorev2_inprocess.dll" />
2828
<file src="src\AspNetCoreModuleV2\AspNetCore\bin\$Configuration$\x64\*.xml"/>

nuget/Microsoft.AspNetCore.AspNetCoreModule.props

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
<AspNetCoreModuleX86Location>$(MSBuildThisFileDirectory)..\contentFiles\any\any\x86\aspnetcore.dll</AspNetCoreModuleX86Location>
66
<InProcessRequestHandlerX64Location>$(MSBuildThisFileDirectory)..\contentFiles\any\any\x64\aspnetcorev2_inprocess.dll</InProcessRequestHandlerX64Location>
77
<InProcessRequestHandlerX86Location>$(MSBuildThisFileDirectory)..\contentFiles\any\any\x86\aspnetcorev2_inprocess.dll</InProcessRequestHandlerX86Location>
8-
<OutOfProcessRequestHandlerX64Location>$(MSBuildThisFileDirectory)..\contentFiles\any\any\x64\aspnetcorev2_outofprocess.dll</OutOfProcessRequestHandlerX64Location>
9-
<OutOfProcessRequestHandlerX86Location>$(MSBuildThisFileDirectory)..\contentFiles\any\any\x86\aspnetcorev2_outofprocess.dll</OutOfProcessRequestHandlerX86Location>
8+
<OutOfProcessRequestHandlerX64Location>$(MSBuildThisFileDirectory)..\contentFiles\any\any\x64\$(AspNetCoreModuleOutOfProcessVersion)\aspnetcorev2_outofprocess.dll</OutOfProcessRequestHandlerX64Location>
9+
<OutOfProcessRequestHandlerX86Location>$(MSBuildThisFileDirectory)..\contentFiles\any\any\x86\$(AspNetCoreModuleOutOfProcessVersion)\aspnetcorev2_outofprocess.dll</OutOfProcessRequestHandlerX86Location>
1010
</PropertyGroup>
1111

1212
</Project>

src/AspNetCoreModuleV2/AspNetCore/Inc/aspnetcore_shim_config.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#pragma once
55

66
#include "precomp.hxx"
7+
#include <map>
78

89
#define CS_ASPNETCORE_SECTION L"system.webServer/aspNetCore"
910
#define CS_ASPNETCORE_PROCESS_EXE_PATH L"processPath"
@@ -105,6 +106,14 @@ class ASPNETCORE_SHIM_CONFIG : IHttpStoredContext
105106
return m_hostingModel;
106107
}
107108

109+
STRU*
110+
QueryHandlerVersion(
111+
VOID
112+
)
113+
{
114+
return &m_struHandlerVersion;
115+
}
116+
108117
private:
109118
ASPNETCORE_SHIM_CONFIG() :
110119
m_cRefs(1),
@@ -120,5 +129,6 @@ class ASPNETCORE_SHIM_CONFIG : IHttpStoredContext
120129
STRU m_struConfigPath;
121130
APP_HOSTING_MODEL m_hostingModel;
122131
STRU m_struHostFxrLocation;
132+
STRU m_struHandlerVersion;
123133
};
124134

src/AspNetCoreModuleV2/AspNetCore/src/applicationinfo.cpp

Lines changed: 29 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -358,60 +358,47 @@ APPLICATION_INFO::FindRequestHandlerAssembly(STRU& location)
358358

359359
HRESULT
360360
APPLICATION_INFO::FindNativeAssemblyFromGlobalLocation(
361-
PCWSTR libraryName,
362-
STRU* struFilename)
361+
PCWSTR pstrHandlerDllName,
362+
STRU* struFilename
363+
)
363364
{
364365
HRESULT hr = S_OK;
365-
DWORD dwSize = MAX_PATH;
366-
BOOL fDone = FALSE;
367-
DWORD dwPosition = 0;
368-
369-
// Though we could call LoadLibrary(L"aspnetcorerh.dll") relying the OS to solve
370-
// the path (the targeted dll is the same folder of w3wp.exe/iisexpress)
371-
// let's still load with full path to avoid security issue
372-
if (FAILED(hr = struFilename->Resize(dwSize + 20)))
373-
{
374-
goto Finished;
375-
}
376366

377-
while (!fDone)
367+
try
378368
{
379-
DWORD dwReturnedSize = GetModuleFileNameW(g_hModule, struFilename->QueryStr(), dwSize);
380-
if (dwReturnedSize == 0)
381-
{
382-
hr = HRESULT_FROM_WIN32(GetLastError());
383-
fDone = TRUE;
384-
goto Finished;
385-
}
386-
else if ((dwReturnedSize == dwSize) && (GetLastError() == ERROR_INSUFFICIENT_BUFFER))
387-
{
388-
dwSize *= 2; // smaller buffer. increase the buffer and retry
389-
if (FAILED(hr = struFilename->Resize(dwSize + 40))) // + 40 for aspnetcorerh.dll
390-
{
391-
goto Finished;
392-
}
393-
}
394-
else
369+
std::wstring modulePath = GlobalVersionUtility::GetModuleName(g_hModule);
370+
371+
modulePath = GlobalVersionUtility::RemoveFileNameFromFolderPath(modulePath);
372+
373+
std::wstring retval = GlobalVersionUtility::GetGlobalRequestHandlerPath(modulePath.c_str(),
374+
m_pConfiguration->QueryHandlerVersion()->QueryStr(),
375+
pstrHandlerDllName
376+
);
377+
378+
if (FAILED(hr = struFilename->Copy(retval.c_str())))
395379
{
396-
fDone = TRUE;
380+
return hr;
397381
}
398382
}
399-
400-
if (FAILED(hr = struFilename->SyncWithBuffer()))
383+
catch (std::exception& e)
401384
{
402-
goto Finished;
385+
STRU struEvent;
386+
if (SUCCEEDED(struEvent.Copy(ASPNETCORE_EVENT_OUT_OF_PROCESS_RH_MISSING_MSG))
387+
&& SUCCEEDED(struEvent.AppendA(e.what())))
388+
{
389+
UTILITY::LogEvent(g_hEventLog,
390+
EVENTLOG_INFORMATION_TYPE,
391+
ASPNETCORE_EVENT_OUT_OF_PROCESS_RH_MISSING,
392+
struEvent.QueryStr());
393+
}
394+
395+
hr = E_FAIL;
403396
}
404-
dwPosition = struFilename->LastIndexOf(L'\\', 0);
405-
struFilename->QueryStr()[dwPosition] = L'\0';
406-
407-
if (FAILED(hr = struFilename->SyncWithBuffer()) ||
408-
FAILED(hr = struFilename->Append(L"\\")) ||
409-
FAILED(hr = struFilename->Append(libraryName)))
397+
catch (...)
410398
{
411-
goto Finished;
399+
hr = E_FAIL;
412400
}
413401

414-
Finished:
415402
return hr;
416403
}
417404

src/AspNetCoreModuleV2/AspNetCore/src/aspnetcore_shim_config.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
#include "aspnetcore_shim_config.h"
55

6+
#include "config_utility.h"
67
#include "hostfxr_utility.h"
78
#include "debugutil.h"
89
#include "ahutil.h"
@@ -192,6 +193,8 @@ ASPNETCORE_SHIM_CONFIG::Populate(
192193
goto Finished;
193194
}
194195

196+
hr = ConfigUtility::FindHandlerVersion(pAspNetCoreElement, &m_struHandlerVersion);
197+
195198
Finished:
196199

197200
if (pAspNetCoreElement != NULL)

src/AspNetCoreModuleV2/CommonLib/CommonLib.vcxproj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,8 @@
181181
</ItemDefinitionGroup>
182182
<ItemGroup>
183183
<ClInclude Include="application.h" />
184+
<ClInclude Include="config_utility.h" />
185+
<ClInclude Include="GlobalVersionUtility.h" />
184186
<ClInclude Include="NullOutputManager.h" />
185187
<ClInclude Include="FileOutputManager.h" />
186188
<ClInclude Include="fx_ver.h" />
@@ -205,6 +207,7 @@
205207
<ItemGroup>
206208
<ClCompile Include="FileOutputManager.cpp" />
207209
<ClCompile Include="fx_ver.cxx" />
210+
<ClCompile Include="GlobalVersionUtility.cpp" />
208211
<ClCompile Include="hostfxr_utility.cpp" />
209212
<ClCompile Include="hostfxroptions.cpp" />
210213
<ClCompile Include="requesthandler_config.cpp" />
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
// Copyright (c) .NET Foundation and contributors. All rights reserved.
2+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
3+
4+
#include "stdafx.h"
5+
#include <experimental/filesystem>
6+
7+
namespace fs = std::experimental::filesystem;
8+
9+
// throws runtime error if no request handler versions are installed.
10+
// Throw invalid_argument if any argument is null
11+
std::wstring
12+
GlobalVersionUtility::GetGlobalRequestHandlerPath(PCWSTR pwzAspNetCoreFolderPath, PCWSTR pwzHandlerVersion, PCWSTR pwzHandlerName)
13+
{
14+
if (pwzAspNetCoreFolderPath == NULL)
15+
{
16+
throw new std::invalid_argument("pwzAspNetCoreFolderPath is NULL");
17+
}
18+
19+
if (pwzHandlerVersion == NULL)
20+
{
21+
throw new std::invalid_argument("pwzHandlerVersion is NULL");
22+
}
23+
24+
if (pwzHandlerName == NULL)
25+
{
26+
throw new std::invalid_argument("pwzHandlerName is NULL");
27+
}
28+
29+
std::wstring folderVersion(pwzHandlerVersion);
30+
fs::path aspNetCoreFolderPath(pwzAspNetCoreFolderPath);
31+
32+
if (folderVersion.empty())
33+
{
34+
folderVersion = FindHighestGlobalVersion(pwzAspNetCoreFolderPath);
35+
}
36+
37+
aspNetCoreFolderPath = aspNetCoreFolderPath
38+
.append(folderVersion)
39+
.append(pwzHandlerName);
40+
return aspNetCoreFolderPath;
41+
}
42+
43+
// Throw filesystem_error if directory_iterator can't iterate over the directory
44+
// Throw invalid_argument if any argument is null
45+
std::vector<fx_ver_t>
46+
GlobalVersionUtility::GetRequestHandlerVersions(PCWSTR pwzAspNetCoreFolderPath)
47+
{
48+
if (pwzAspNetCoreFolderPath == NULL)
49+
{
50+
throw new std::invalid_argument("pwzAspNetCoreFolderPath is NULL");
51+
}
52+
53+
std::vector<fx_ver_t> versionsInDirectory;
54+
for (auto& p : fs::directory_iterator(pwzAspNetCoreFolderPath))
55+
{
56+
if (!fs::is_directory(p))
57+
{
58+
continue;
59+
}
60+
61+
fx_ver_t requested_ver(-1, -1, -1);
62+
if (fx_ver_t::parse(p.path().filename(), &requested_ver, false))
63+
{
64+
versionsInDirectory.push_back(requested_ver);
65+
}
66+
}
67+
return versionsInDirectory;
68+
}
69+
70+
// throws runtime error if no request handler versions are installed.
71+
// Throw invalid_argument if any argument is null
72+
std::wstring
73+
GlobalVersionUtility::FindHighestGlobalVersion(PCWSTR pwzAspNetCoreFolderPath)
74+
{
75+
if (pwzAspNetCoreFolderPath == NULL)
76+
{
77+
throw new std::invalid_argument("pwzAspNetCoreFolderPath is NULL");
78+
}
79+
80+
std::vector<fx_ver_t> versionsInDirectory = GetRequestHandlerVersions(pwzAspNetCoreFolderPath);
81+
if (versionsInDirectory.empty())
82+
{
83+
throw new std::runtime_error("Cannot find request handler next to aspnetcorev2.dll. Verify a version of the request handler is installed in a version folder.");
84+
}
85+
std::sort(versionsInDirectory.begin(), versionsInDirectory.end());
86+
87+
return versionsInDirectory.back().as_str();
88+
}
89+
90+
// Throws std::out_of_range if there is an index out of range
91+
// Throw invalid_argument if any argument is null
92+
std::wstring
93+
GlobalVersionUtility::RemoveFileNameFromFolderPath(std::wstring fileName)
94+
{
95+
fs::path path(fileName);
96+
return path.parent_path();
97+
}
98+
99+
std::wstring
100+
GlobalVersionUtility::GetModuleName(HMODULE hModuleName)
101+
{
102+
DWORD dwSize = MAX_PATH;
103+
BOOL fDone = FALSE;
104+
105+
// Instead of creating a temporary buffer, use the std::wstring directly as the receive buffer.
106+
std::wstring retVal;
107+
retVal.resize(dwSize);
108+
109+
while (!fDone)
110+
{
111+
DWORD dwReturnedSize = GetModuleFileNameW(hModuleName, &retVal[0], dwSize);
112+
if (dwReturnedSize == 0)
113+
{
114+
throw new std::runtime_error("GetModuleFileNameW returned 0.");
115+
}
116+
else if ((dwReturnedSize == dwSize) && (GetLastError() == ERROR_INSUFFICIENT_BUFFER))
117+
{
118+
dwSize *= 2;
119+
retVal.resize(dwSize); // smaller buffer. increase the buffer and retry
120+
}
121+
else
122+
{
123+
// GetModuleFilename will not account for the null terminator
124+
// std::wstring auto appends one, so we don't need to subtract 1 when resizing.
125+
retVal.resize(dwReturnedSize);
126+
fDone = TRUE;
127+
}
128+
}
129+
130+
return retVal;
131+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// Copyright (c) .NET Foundation and contributors. All rights reserved.
2+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
3+
4+
#pragma once
5+
#include <experimental/filesystem>
6+
7+
class GlobalVersionUtility
8+
{
9+
public:
10+
11+
static
12+
std::wstring
13+
GetGlobalRequestHandlerPath(PCWSTR pwzAspNetCoreFolderPath, PCWSTR pwzHandlerVersion, PCWSTR pwzHandlerName);
14+
15+
static
16+
std::wstring
17+
FindHighestGlobalVersion(PCWSTR pwzAspNetCoreFolderPath);
18+
19+
static
20+
std::wstring
21+
RemoveFileNameFromFolderPath(std::wstring fileName);
22+
23+
static
24+
std::vector<fx_ver_t>
25+
GetRequestHandlerVersions(PCWSTR pwzAspNetCoreFolderPath);
26+
27+
static
28+
std::wstring
29+
GetModuleName(HMODULE hModuleName);
30+
};
31+

0 commit comments

Comments
 (0)