Adds RequestHandler dll and hostfxr changes from ANCM (#497)

This commit is contained in:
Justin Kotalik 2018-01-04 10:07:00 -08:00 committed by GitHub
parent 8cedb4eff3
commit c3bc6fed9c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 554 additions and 552 deletions

View File

@ -30,8 +30,15 @@
<PackageId>Microsoft.AspNetCore.AspNetCoreModule</PackageId>
<Version>$(PackageVersion)</Version>
<RepositoryRoot>$(RepositoryRoot)</RepositoryRoot>
</ArtifactInfo>
<ArtifactInfo Include="$(BuildDir)Microsoft.AspNetCore.AspNetCoreModule.RequestHandler.$(PackageVersion).nupkg">
<ArtifactType>NuGetPackage</ArtifactType>
<PackageId>Microsoft.AspNetCore.AspNetCoreModule.RequestHandler</PackageId>
<Version>$(PackageVersion)</Version>
<RepositoryRoot>$(RepositoryRoot)</RepositoryRoot>
</ArtifactInfo>
<FilesToExcludeFromSigning Include="$(BuildDir)Microsoft.AspNetCore.AspNetCoreModule.$(PackageVersion).nupkg" />
<FilesToExcludeFromSigning Include="$(BuildDir)Microsoft.AspNetCore.AspNetCoreModule.RequestHandler.$(PackageVersion).nupkg" />
<ArtifactInfo Include="$(AncmZipOutputPath)">
<ArtifactType>ZipArchive</ArtifactType>
@ -69,6 +76,11 @@
Overwrite="true"
SourceFiles="@(AncmFiles)"
WorkingDirectory="$(RepositoryRoot)" />
<PackNuspec NuspecPath="$(MSBuildThisFileDirectory)..\nuget\AspNetCoreRequestHandler.nuspec"
DestinationFolder="$(BuildDir)"
Properties="version=$(PackageVersion);Configuration=$(Configuration)"
BasePath="$(RepositoryRoot)" />
</Target>
</Project>

View File

@ -9,6 +9,7 @@
<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>
<iconUrl>http://go.microsoft.com/fwlink/?LinkID=288859</iconUrl>
<requireLicenseAcceptance>true</requireLicenseAcceptance>
<description>ASP.NET Core Module</description>
<language>en-US</language>

View File

@ -0,0 +1,23 @@
<?xml version="1.0"?>
<package xmlns="http://schemas.microsoft.com/packaging/2013/05/nuspec.xsd">
<metadata>
<id>Microsoft.AspNetCore.AspNetCoreModule.RequestHandler</id>
<title>Microsoft ASP.NET Core Module Request Handler</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>
<iconUrl>http://go.microsoft.com/fwlink/?LinkID=288859</iconUrl>
<requireLicenseAcceptance>true</requireLicenseAcceptance>
<description>ASP.NET Core Module Request Handler</description>
<language>en-US</language>
<tags>Microsoft.AspNetCore.AspNetCoreModule.RequestHandler</tags>
</metadata>
<files>
<!-- TODO make build output outside of content files. -->
<file src="src\RequestHandler\bin\$Configuration$\Win32\aspnetcorerh.dll" target="runtimes\win-x86\nativeassets\netcoreapp2.1\aspnetcorerh.dll" />
<file src="src\RequestHandler\bin\$Configuration$\x64\aspnetcorerh.dll" target="runtimes\win-x64\nativeassets\netcoreapp2.1\aspnetcorerh.dll" />
</files>
</package>

View File

@ -2,6 +2,7 @@
// Licensed under the MIT License. See License.txt in the project root for license information.
#pragma once
#define API_BUFFER_TOO_SMALL 0x80008098
typedef
HRESULT
@ -145,8 +146,7 @@ public:
private:
HRESULT FindRequestHandlerAssembly();
HRESULT FindNativeAssemblyFromGlobalLocation(STRU* struFilename);
HRESULT FindNativeAssemblyFromLocalBin(STRU* struFilename);
HRESULT GetRequestHandlerFromRuntimeStore(STRU* struFilename);
HRESULT FindNativeAssemblyFromHostfxr(STRU* struFilename);
mutable LONG m_cRefs;
APPLICATION_INFO_KEY m_applicationInfoKey;

View File

@ -45,7 +45,7 @@ public:
if (handle == INVALID_HANDLE_VALUE)
{
if (GetLastError() == ERROR_FILE_NOT_FOUND)
if (HRESULT_FROM_WIN32(GetLastError()) == ERROR_FILE_NOT_FOUND)
{
fResult = FALSE;
}

View File

@ -145,11 +145,11 @@ APPLICATION_INFO::UpdateAppOfflineFileHandle()
HRESULT
APPLICATION_INFO::EnsureApplicationCreated()
{
HRESULT hr = S_OK;
BOOL fLocked = FALSE;
APPLICATION* pApplication = NULL;
HRESULT hr = S_OK;
BOOL fLocked = FALSE;
APPLICATION* pApplication = NULL;
STACK_STRU(struFileName, 300); // >MAX_PATH
STRU hostFxrDllLocation;
STRU hostFxrDllLocation;
if (m_pApplication != NULL)
{
@ -184,7 +184,6 @@ APPLICATION_INFO::EnsureApplicationCreated()
}
m_pApplication = pApplication;
}
Finished:
if (fLocked)
{
@ -196,9 +195,9 @@ Finished:
HRESULT
APPLICATION_INFO::FindRequestHandlerAssembly()
{
HRESULT hr = S_OK;
BOOL fLocked = FALSE;
STACK_STRU(struFileName, 300); // >MAX_PATH
HRESULT hr = S_OK;
BOOL fLocked = FALSE;
STACK_STRU(struFileName, 256);
if (g_fAspnetcoreRHLoadedError)
{
@ -219,19 +218,10 @@ APPLICATION_INFO::FindRequestHandlerAssembly()
goto Finished;
}
// load assembly and create the application
if (m_pConfiguration->QueryHostingModel() == APP_HOSTING_MODEL::HOSTING_IN_PROCESS)
{
// Look at inetsvr only for now. TODO add in functionality
hr = FindNativeAssemblyFromGlobalLocation(&struFileName);
if (FAILED(hr))
{
goto Finished;
}
}
else
if (FAILED(hr = HOSTFXR_UTILITY::GetHostFxrParameters(m_pConfiguration)) ||
FAILED(hr = FindNativeAssemblyFromHostfxr(&struFileName)))
{
// TODO eventually make this fail for in process loading.
hr = FindNativeAssemblyFromGlobalLocation(&struFileName);
if (FAILED(hr))
{
@ -294,6 +284,11 @@ APPLICATION_INFO::FindNativeAssemblyFromGlobalLocation(STRU* struFilename)
// Though we could call LoadLibrary(L"aspnetcorerh.dll") relying the OS to solve
// the path (the targeted dll is the same folder of w3wp.exe/iisexpress)
// let's still load with full path to avoid security issue
if (FAILED(hr = struFilename->Resize(dwSize + 20)))
{
goto Finished;
}
while (!fDone)
{
DWORD dwReturnedSize = GetModuleFileNameW(g_hModule, struFilename->QueryStr(), dwSize);
@ -306,7 +301,10 @@ APPLICATION_INFO::FindNativeAssemblyFromGlobalLocation(STRU* struFilename)
else if ((dwReturnedSize == dwSize) && (GetLastError() == ERROR_INSUFFICIENT_BUFFER))
{
dwSize *= 2; // smaller buffer. increase the buffer and retry
struFilename->Resize(dwSize + 20); // aspnetcorerh.dll
if (FAILED(hr = struFilename->Resize(dwSize + 20))) // + 20 for aspnetcorerh.dll
{
goto Finished;
}
}
else
{
@ -322,6 +320,7 @@ APPLICATION_INFO::FindNativeAssemblyFromGlobalLocation(STRU* struFilename)
struFilename->QueryStr()[dwPosition] = L'\0';
if (FAILED(hr = struFilename->SyncWithBuffer()) ||
FAILED(hr = struFilename->Append(L"\\")) ||
FAILED(hr = struFilename->Append(g_pwzAspnetcoreRequestHandlerName)))
{
goto Finished;
@ -330,3 +329,137 @@ APPLICATION_INFO::FindNativeAssemblyFromGlobalLocation(STRU* struFilename)
Finished:
return hr;
}
//
// Tries to find aspnetcorerh.dll from the application
// Calls into hostfxr.dll to find it.
// Will leave hostfxr.dll loaded as it will be used again to call hostfxr_main.
//
HRESULT
APPLICATION_INFO::FindNativeAssemblyFromHostfxr(
STRU* struFilename
)
{
HRESULT hr = S_OK;
STRU struApplicationFullPath;
STRU struNativeSearchPaths;
STRU struNativeDllLocation;
HMODULE hmHostFxrDll = NULL;
INT intHostFxrExitCode = 0;
INT intIndex = -1;
INT intPrevIndex = 0;
BOOL fFound = FALSE;
DWORD dwBufferSize = 1024 * 10;
DBG_ASSERT(struFileName != NULL);
hmHostFxrDll = LoadLibraryW(m_pConfiguration->QueryHostFxrFullPath());
if (hmHostFxrDll == NULL)
{
// Could not load hostfxr
hr = HRESULT_FROM_WIN32(GetLastError());
goto Finished;
}
hostfxr_get_native_search_directories_fn pFnHostFxrSearchDirectories = (hostfxr_get_native_search_directories_fn)
GetProcAddress(hmHostFxrDll, "hostfxr_get_native_search_directories");
if (pFnHostFxrSearchDirectories == NULL)
{
// Host fxr version is incorrect (need a higher version).
// TODO log error
hr = E_FAIL;
goto Finished;
}
if (FAILED(hr = struNativeSearchPaths.Resize(dwBufferSize)))
{
goto Finished;
}
while (TRUE)
{
intHostFxrExitCode = pFnHostFxrSearchDirectories(
m_pConfiguration->QueryHostFxrArgCount(),
m_pConfiguration->QueryHostFxrArguments(),
struNativeSearchPaths.QueryStr(),
dwBufferSize
);
if (intHostFxrExitCode == 0)
{
break;
}
else if (intHostFxrExitCode == API_BUFFER_TOO_SMALL)
{
dwBufferSize *= 2; // smaller buffer. increase the buffer and retry
if (FAILED(hr = struNativeSearchPaths.Resize(dwBufferSize)))
{
goto Finished;
}
}
else
{
hr = E_FAIL;
// Log "Error finding native search directories from aspnetcore application.
goto Finished;
}
}
if (FAILED(hr = struNativeSearchPaths.SyncWithBuffer()))
{
goto Finished;
}
fFound = FALSE;
// The native search directories are semicolon delimited.
// Split on semicolons, append aspnetcorerh.dll, and check if the file exists.
while ((intIndex = struNativeSearchPaths.IndexOf(L";", intPrevIndex)) != -1)
{
if (FAILED(hr = struNativeDllLocation.Copy(struNativeSearchPaths.QueryStr(), intIndex - intPrevIndex)))
{
goto Finished;
}
if (!struNativeDllLocation.EndsWith(L"\\"))
{
if (FAILED(hr = struNativeDllLocation.Append(L"\\")))
{
goto Finished;
}
}
if (FAILED(hr = struNativeDllLocation.Append(g_pwzAspnetcoreRequestHandlerName)))
{
goto Finished;
}
if (UTILITY::CheckIfFileExists(struNativeDllLocation.QueryStr()))
{
if (FAILED(hr = struFilename->Copy(struNativeDllLocation)))
{
goto Finished;
}
fFound = TRUE;
break;
}
intPrevIndex = intIndex + 1;
}
if (!fFound)
{
hr = E_FAIL;
goto Finished;
}
Finished:
if (FAILED(hr) && hmHostFxrDll != NULL)
{
FreeLibrary(hmHostFxrDll);
}
return hr;
}

View File

@ -17,7 +17,7 @@ DWORD g_dwActiveServerProcesses = 0;
SRWLOCK g_srwLock;
DWORD g_dwDebugFlags = 0;
PCSTR g_szDebugLabel = "ASPNET_CORE_MODULE";
PCWSTR g_pwzAspnetcoreRequestHandlerName = L"\\aspnetcorerh.dll";
PCWSTR g_pwzAspnetcoreRequestHandlerName = L"aspnetcorerh.dll";
PFN_ASPNETCORE_CREATE_APPLICATION g_pfnAspNetCoreCreateApplication;
PFN_ASPNETCORE_CREATE_REQUEST_HANDLER g_pfnAspNetCoreCreateRequestHandler;

View File

@ -103,6 +103,7 @@ inline bool IsSpace(char ch)
#include "..\..\CommonLib\environmentvariablehash.h"
#include "..\..\CommonLib\aspnetcoreconfig.h"
#include "..\..\CommonLib\hostfxr_utility.h"
#include "..\..\CommonLib\application.h"
#include "..\..\CommonLib\utility.h"
#include "..\..\CommonLib\debugutil.h"
@ -116,6 +117,7 @@ inline bool IsSpace(char ch)
#include "globalmodule.h"
#include "resource.h"
#include "proxymodule.h"
#include "applicationinfo.h"
FORCEINLINE

View File

@ -151,8 +151,8 @@ ASPNET_CORE_PROXY_MODULE::OnExecuteRequestHandler(
// cannot recreate the application as we cannot reload clr for inprocess
if (pApplication->QueryStatus() != APPLICATION_STATUS::RUNNING)
{
hr = HRESULT_FROM_WIN32(ERROR_SERVER_DISABLED);
goto Finished;
hr = HRESULT_FROM_WIN32(ERROR_SERVER_DISABLED);
goto Finished;
}
// Create RequestHandler and process the request

View File

@ -6,6 +6,12 @@
ASPNETCORE_CONFIG::~ASPNETCORE_CONFIG()
{
if (m_ppStrArguments != NULL)
{
delete[] m_ppStrArguments;
m_ppStrArguments = NULL;
}
if (m_pEnvironmentVariables != NULL)
{
m_pEnvironmentVariables->Clear();
@ -22,7 +28,6 @@ ASPNETCORE_CONFIG::ReferenceConfiguration(
InterlockedIncrement(&m_cRefs);
}
VOID
ASPNETCORE_CONFIG::DereferenceConfiguration(
VOID
@ -132,6 +137,7 @@ ASPNETCORE_CONFIG::Populate(
IHttpContext *pHttpContext
)
{
STACK_STRU(strHostingModel, 300);
HRESULT hr = S_OK;
STRU strEnvName;
STRU strEnvValue;
@ -308,7 +314,7 @@ ASPNETCORE_CONFIG::Populate(
hr = GetElementStringProperty(pAspNetCoreElement,
CS_ASPNETCORE_HOSTING_MODEL,
&m_strHostingModel);
&strHostingModel);
if (FAILED(hr))
{
// Swallow this error for backward compatability
@ -316,11 +322,11 @@ ASPNETCORE_CONFIG::Populate(
hr = S_OK;
}
if (m_strHostingModel.IsEmpty() || m_strHostingModel.Equals(L"outofprocess", TRUE))
if (strHostingModel.IsEmpty() || strHostingModel.Equals(L"outofprocess", TRUE))
{
m_hostingModel = HOSTING_OUT_PROCESS;
}
else if (m_strHostingModel.Equals(L"inprocess", TRUE))
else if (strHostingModel.Equals(L"inprocess", TRUE))
{
m_hostingModel = HOSTING_IN_PROCESS;
}

View File

@ -68,7 +68,7 @@ public:
_In_ IHttpServer *pHttpServer,
_In_ HTTP_MODULE_ID pModuleId,
_In_ IHttpContext *pHttpContext,
_Out_ ASPNETCORE_CONFIG **ppAspNetCoreConfig
_Out_ ASPNETCORE_CONFIG **ppAspNetCoreConfig
);
ENVIRONMENT_VAR_HASH*
@ -215,18 +215,54 @@ public:
return &m_struConfigPath;
}
STRU*
QueryHostfxrPath()
{
return &m_struHostFxrPath;
}
BOOL
QueryIsStandAloneApplication(
CONST
PCWSTR*
QueryHostFxrArguments(
VOID
)
{
return m_fIsStandAloneApplication;
return m_ppStrArguments;
}
CONST
DWORD
QueryHostFxrArgCount(
VOID
)
{
return m_dwArgc;
}
CONST
PCWSTR
QueryHostFxrFullPath(
VOID
)
{
return m_struHostFxrLocation.QueryStr();
}
HRESULT
SetHostFxrFullPath(
PCWSTR pStrHostFxrFullPath
)
{
return m_struHostFxrLocation.Copy(pStrHostFxrFullPath);
}
VOID
SetHostFxrArguments(
DWORD dwArgc,
PCWSTR* ppStrArguments
)
{
if (m_ppStrArguments != NULL)
{
delete[] m_ppStrArguments;
}
m_dwArgc = dwArgc;
m_ppStrArguments = ppStrArguments;
}
VOID
@ -248,7 +284,8 @@ private:
m_fStdoutLogEnabled( FALSE ),
m_pEnvironmentVariables( NULL ),
m_cRefs( 1 ),
m_hostingModel( HOSTING_UNKNOWN )
m_hostingModel( HOSTING_UNKNOWN ),
m_ppStrArguments(NULL)
{
}
@ -272,8 +309,6 @@ private:
STRU m_struApplicationPhysicalPath;
STRU m_struApplicationVirtualPath;
STRU m_struConfigPath;
STRU m_strHostingModel;
STRU m_struHostFxrPath;
BOOL m_fStdoutLogEnabled;
BOOL m_fForwardWindowsAuthToken;
BOOL m_fDisableStartUpErrorPage;
@ -283,4 +318,7 @@ private:
BOOL m_fIsStandAloneApplication;
APP_HOSTING_MODEL m_hostingModel;
ENVIRONMENT_VAR_HASH* m_pEnvironmentVariables;
STRU m_struHostFxrLocation;
PCWSTR* m_ppStrArguments;
DWORD m_dwArgc;
};

View File

@ -7,40 +7,10 @@ HOSTFXR_UTILITY::HOSTFXR_UTILITY()
{
}
HOSTFXR_UTILITY::~HOSTFXR_UTILITY()
{
}
HRESULT
HOSTFXR_UTILITY::FindHostFxrDll(
ASPNETCORE_CONFIG *pConfig,
STRU* struHostFxrDllLocation,
BOOL* fStandAlone
)
{
HRESULT hr = S_OK;
// If the process path isn't dotnet, assume we are a standalone appliction.
// TODO: this should be a path equivalent check
if (!(pConfig->QueryProcessPath()->Equals(L".\\dotnet")
|| pConfig->QueryProcessPath()->Equals(L"dotnet")
|| pConfig->QueryProcessPath()->Equals(L".\\dotnet.exe")
|| pConfig->QueryProcessPath()->Equals(L"dotnet.exe")))
{
// hostfxr is in the same folder, parse and use it.
hr = GetStandaloneHostfxrLocation(struHostFxrDllLocation, pConfig);
*fStandAlone = TRUE;
}
else
{
hr = GetPortableHostfxrLocation(struHostFxrDllLocation);
fStandAlone = FALSE;
}
return hr;
}
//
// Runs a standalone appliction.
// The folder structure looks like this:
@ -54,160 +24,183 @@ HOSTFXR_UTILITY::FindHostFxrDll(
// Assuming we don't need Application.exe as the dll is the actual application.
//
HRESULT
HOSTFXR_UTILITY::GetStandaloneHostfxrLocation(
STRU* struHostfxrPath,
HOSTFXR_UTILITY::GetStandaloneHostfxrParameters(
ASPNETCORE_CONFIG *pConfig
)
{
HRESULT hr = S_OK;
HANDLE hFileHandle = INVALID_HANDLE_VALUE;
SECURITY_ATTRIBUTES saAttr;
HRESULT hr = S_OK;
STRU struExePath;
STRU struDllPath;
STRU struArguments;
DWORD dwPosition;
// Get the full path to the exe and check if it exists
if (FAILED(hr = UTILITY::ConvertPathToFullPath(L"\\hostfxr.dll",
hr = UTILITY::ConvertPathToFullPath(pConfig->QueryProcessPath()->QueryStr(),
pConfig->QueryApplicationPhysicalPath()->QueryStr(),
struHostfxrPath)))
{
goto Finished;
}
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
saAttr.bInheritHandle = TRUE;
saAttr.lpSecurityDescriptor = NULL;
hFileHandle = CreateFile(struHostfxrPath->QueryStr(),
GENERIC_READ,
FILE_SHARE_READ,
&saAttr,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (hFileHandle == INVALID_HANDLE_VALUE)
{
// Treat access isseu as File not found
hr = ERROR_FILE_NOT_FOUND;
goto Finished;
}
else
{
CloseHandle(hFileHandle);
}
Finished:
return hr;
}
HRESULT
HOSTFXR_UTILITY::GetPortableHostfxrLocation(
STRU* struHostfxrPath
)
{
HRESULT hr = S_OK;
STRU struSystemPathVariable;
STRU strDotnetExeLocation;
STRU strHostFxrSearchExpression;
STRU strHighestDotnetVersion;
PWSTR pwzDelimeterContext = NULL;
PCWSTR pszDotnetLocation = NULL;
PCWSTR pszDotnetExeString(L"dotnet.exe");
DWORD dwCopyLength;
BOOL fFound = FALSE;
HANDLE hFileHandle = INVALID_HANDLE_VALUE;
SECURITY_ATTRIBUTES saAttr;
std::vector<std::wstring> vVersionFolders;
&struExePath);
if (FAILED(hr))
{
goto Finished;
}
// Get the System PATH value.
if (!UTILITY::GetSystemPathVariable(L"PATH", &struSystemPathVariable))
if (FAILED(hr = struDllPath.Copy(struExePath)))
{
hr = ERROR_BAD_ENVIRONMENT;
goto Finished;
}
// Split on ';', checking to see if dotnet.exe exists in any folders.
pszDotnetLocation = wcstok_s(struSystemPathVariable.QueryStr(), L";", &pwzDelimeterContext);
while (pszDotnetLocation != NULL)
dwPosition = struDllPath.LastIndexOf(L'.', 0);
if (dwPosition == -1)
{
dwCopyLength = (DWORD) wcsnlen_s(pszDotnetLocation, 260);
hr = E_FAIL;
goto Finished;
}
// We store both the exe and folder locations as we eventually need to check inside of host\\fxr
// which doesn't need the dotnet.exe portion of the string
hr = strDotnetExeLocation.Copy(pszDotnetLocation, dwCopyLength);
struDllPath.QueryStr()[dwPosition] = L'\0';
if (FAILED(hr = struDllPath.SyncWithBuffer()) ||
FAILED(hr = struDllPath.Append(L".dll")))
{
goto Finished;
}
if (!UTILITY::CheckIfFileExists(struDllPath.QueryStr()))
{
// Treat access issue as File not found
hr = ERROR_FILE_NOT_FOUND;
goto Finished;
}
if (FAILED(hr = struArguments.Copy(struDllPath)) ||
FAILED(hr = struArguments.Append(L" ")) ||
FAILED(hr = struArguments.Append(pConfig->QueryArguments())))
{
goto Finished;
}
if (FAILED(hr = SetHostFxrArguments(&struArguments, &struExePath, pConfig)))
{
goto Finished;
}
Finished:
return hr;
}
HRESULT
HOSTFXR_UTILITY::GetHostFxrParameters(
ASPNETCORE_CONFIG *pConfig
)
{
HRESULT hr = S_OK;
STRU struSystemPathVariable;
STRU struHostFxrPath;
STRU strDotnetExeLocation;
STRU strHostFxrSearchExpression;
STRU strHighestDotnetVersion;
std::vector<std::wstring> vVersionFolders;
DWORD dwPosition;
DWORD dwPathLength = MAX_PATH;
DWORD dwDotnetLength = 0;
BOOL fFound = FALSE;
if (UTILITY::CheckIfFileExists(pConfig->QueryProcessPath()->QueryStr()))
{
hr = UTILITY::ConvertPathToFullPath(L"hostfxr.dll", pConfig->QueryApplicationPath()->QueryStr(), &struHostFxrPath);
if (FAILED(hr))
{
goto Finished;
}
if (dwCopyLength > 0 && pszDotnetLocation[dwCopyLength - 1] != L'\\')
if (UTILITY::CheckIfFileExists(struHostFxrPath.QueryStr()))
{
hr = strDotnetExeLocation.Append(L"\\");
// Standalone application
if (FAILED(hr = pConfig->SetHostFxrFullPath(struHostFxrPath.QueryStr())))
{
goto Finished;
}
hr = GetStandaloneHostfxrParameters(pConfig);
goto Finished;
}
else
{
hr = UTILITY::ConvertPathToFullPath(
pConfig->QueryProcessPath()->QueryStr(),
pConfig->QueryApplicationPath()->QueryStr(),
&strDotnetExeLocation
);
if (FAILED(hr))
{
goto Finished;
}
}
hr = struHostfxrPath->Copy(strDotnetExeLocation);
if (FAILED(hr))
{
goto Finished;
}
hr = strDotnetExeLocation.Append(pszDotnetExeString);
if (FAILED(hr))
{
goto Finished;
}
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
saAttr.bInheritHandle = TRUE;
saAttr.lpSecurityDescriptor = NULL;
hFileHandle = CreateFile(strDotnetExeLocation.QueryStr(),
GENERIC_READ,
FILE_SHARE_READ,
&saAttr,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (hFileHandle != INVALID_HANDLE_VALUE)
{
// means we found the folder with a dotnet.exe inside of it.
fFound = TRUE;
CloseHandle(hFileHandle);
break;
}
pszDotnetLocation = wcstok_s(NULL, L";", &pwzDelimeterContext);
}
if (!fFound)
if (FAILED(hr = strDotnetExeLocation.Resize(MAX_PATH)))
{
// could not find dotnet.exe, error out
hr = ERROR_BAD_ENVIRONMENT;
goto Finished;
}
hr = struHostfxrPath->Append(L"host\\fxr");
while (!fFound)
{
dwDotnetLength = SearchPath(NULL, L"dotnet", L".exe", dwPathLength, strDotnetExeLocation.QueryStr(), NULL);
if (dwDotnetLength == 0)
{
hr = GetLastError();
// Could not find dotnet
goto Finished;
}
else if (dwDotnetLength == dwPathLength)
{
// Increase size
dwPathLength *= 2;
if (FAILED(hr = strDotnetExeLocation.Resize(dwPathLength)))
{
goto Finished;
}
}
else
{
fFound = TRUE;
}
}
if (FAILED(hr = strDotnetExeLocation.SyncWithBuffer())
|| FAILED(hr = struHostFxrPath.Copy(strDotnetExeLocation)))
{
goto Finished;
}
dwPosition = struHostFxrPath.LastIndexOf(L'\\', 0);
if (dwPosition == -1)
{
hr = E_FAIL;
goto Finished;
}
struHostFxrPath.QueryStr()[dwPosition] = L'\0';
if (FAILED(hr = struHostFxrPath.SyncWithBuffer())
|| FAILED(hr = struHostFxrPath.Append(L"\\")))
{
goto Finished;
}
hr = struHostFxrPath.Append(L"host\\fxr");
if (FAILED(hr))
{
goto Finished;
}
if (!UTILITY::DirectoryExists(struHostfxrPath))
if (!UTILITY::DirectoryExists(&struHostFxrPath))
{
// error, not found the folder
// error, not found in folder
hr = ERROR_BAD_ENVIRONMENT;
goto Finished;
}
// Find all folders under host\\fxr\\ for version numbers.
hr = strHostFxrSearchExpression.Copy(struHostfxrPath);
hr = strHostFxrSearchExpression.Copy(struHostFxrPath);
if (FAILED(hr))
{
goto Finished;
@ -235,25 +228,84 @@ HOSTFXR_UTILITY::GetPortableHostfxrLocation(
{
goto Finished;
}
hr = struHostfxrPath->Append(L"\\");
if (FAILED(hr))
if (FAILED(hr = struHostFxrPath.Append(L"\\"))
|| FAILED(hr = struHostFxrPath.Append(strHighestDotnetVersion.QueryStr()))
|| FAILED(hr = struHostFxrPath.Append(L"\\hostfxr.dll")))
{
goto Finished;
}
hr = struHostfxrPath->Append(strHighestDotnetVersion.QueryStr());
if (FAILED(hr))
if (!UTILITY::CheckIfFileExists(struHostFxrPath.QueryStr()))
{
hr = ERROR_FILE_INVALID;
goto Finished;
}
if (FAILED(hr = SetHostFxrArguments(pConfig->QueryArguments(), &strDotnetExeLocation, pConfig)))
{
goto Finished;
}
hr = struHostfxrPath->Append(L"\\hostfxr.dll");
if (FAILED(hr))
if (FAILED(hr = pConfig->SetHostFxrFullPath(struHostFxrPath.QueryStr())))
{
goto Finished;
}
Finished:
return hr;
}
//
// Forms the argument list in HOSTFXR_PARAMETERS.
// Sets the ArgCount and Arguments.
// Arg structure:
// argv[0] = Path to exe activating hostfxr.
// argv[1] = L"exec"
// argv[2] = first argument specified in the arguments portion of aspnetcore config.
//
HRESULT
HOSTFXR_UTILITY::SetHostFxrArguments(
STRU* struArgumentsFromConfig,
STRU* pstruExePath,
ASPNETCORE_CONFIG* pConfig
)
{
HRESULT hr = S_OK;
INT argc = 0;
PCWSTR* argv = NULL;
LPWSTR* pwzArgs = NULL;
pwzArgs = CommandLineToArgvW(struArgumentsFromConfig->QueryStr(), &argc);
if (pwzArgs == NULL)
{
goto Finished;
}
argv = new PCWSTR[argc + 2];
if (argv == NULL)
{
hr = E_OUTOFMEMORY;
goto Finished;
}
argv[0] = SysAllocString(pstruExePath->QueryStr());
argv[1] = SysAllocString(L"exec");
for (INT i = 0; i < argc; i++)
{
argv[i + 2] = SysAllocString(pwzArgs[i]);
}
pConfig->SetHostFxrArguments(argc + 2, argv);
Finished:
if (pwzArgs != NULL)
{
LocalFree(pwzArgs);
DBG_ASSERT(pwzArgs == NULL);
}
return hr;
}

View File

@ -3,6 +3,10 @@
#pragma once
typedef INT(*hostfxr_get_native_search_directories_fn) (const int argc, const PCWSTR argv[], PCWSTR dest, size_t dest_size);
typedef INT(*hostfxr_main_fn) (CONST DWORD argc, CONST PCWSTR argv[]);
class HOSTFXR_UTILITY
{
public:
@ -11,23 +15,23 @@ public:
static
HRESULT
FindHostFxrDll(
ASPNETCORE_CONFIG *pConfig,
STRU* struHostFxrDllLocation,
BOOL* fStandAlone
GetHostFxrParameters(
ASPNETCORE_CONFIG *pConfig
);
private:
static
HRESULT
GetStandaloneHostfxrLocation(
STRU* struHostfxrPath,
GetStandaloneHostfxrParameters(
ASPNETCORE_CONFIG *pConfig
);
static
HRESULT
GetPortableHostfxrLocation(
STRU* struHostfxrPath
SetHostFxrArguments(
STRU * struArguments,
STRU * pstruExePath,
ASPNETCORE_CONFIG *pConfig
);
};

View File

@ -11,6 +11,7 @@
#include <httpserv.h>
#include <wchar.h>
#include <vector>
#include <shellapi.h>
#include <sstream>
#include "..\IISLib\hashtable.h"
#include "..\IISLib\stringu.h"

View File

@ -545,45 +545,6 @@ UTILITY::DirectoryExists(
return GetFileAttributesExW(pstrPath->QueryStr(), GetFileExInfoStandard, &data);
}
BOOL
UTILITY::GetSystemPathVariable(
_In_ PCWSTR pszEnvironmentVariable,
_Out_ STRU *pstrResult
)
{
DWORD dwLength;
PWSTR pszBuffer = NULL;
BOOL fSucceeded = FALSE;
if (pszEnvironmentVariable == NULL)
{
goto Finished;
}
pstrResult->Reset();
dwLength = GetEnvironmentVariableW(pszEnvironmentVariable, NULL, 0);
if (dwLength == 0)
{
goto Finished;
}
pszBuffer = new WCHAR[dwLength];
if (GetEnvironmentVariableW(pszEnvironmentVariable, pszBuffer, dwLength) == 0)
{
goto Finished;
}
pstrResult->Copy(pszBuffer);
fSucceeded = TRUE;
Finished:
if (pszBuffer != NULL) {
delete[] pszBuffer;
}
return fSucceeded;
}
VOID
UTILITY::FindDotNetFolders(
_In_ PCWSTR pszPath,
@ -606,4 +567,35 @@ UTILITY::FindDotNetFolders(
} while (FindNextFileW(handle, &data));
FindClose(handle);
}
}
BOOL
UTILITY::CheckIfFileExists(
_In_ PCWSTR pszFilePath
)
{
HANDLE hFileHandle = INVALID_HANDLE_VALUE;
SECURITY_ATTRIBUTES saAttr;
BOOL fFileExists = FALSE;
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
saAttr.bInheritHandle = TRUE;
saAttr.lpSecurityDescriptor = NULL;
hFileHandle = CreateFile(pszFilePath,
GENERIC_READ,
FILE_SHARE_READ,
&saAttr,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
fFileExists = hFileHandle != INVALID_HANDLE_VALUE || GetLastError() == ERROR_SHARING_VIOLATION;
if (fFileExists)
{
CloseHandle(hFileHandle);
}
return fFileExists;
}

View File

@ -91,13 +91,6 @@ public:
_In_ STRU *pstrPath
);
static
BOOL
GetSystemPathVariable(
_In_ PCWSTR pszEnvironmentVariable,
_Out_ STRU *pstrResult
);
static
VOID
FindDotNetFolders(
@ -112,6 +105,12 @@ public:
_Out_ STRU *pstrResult
);
static
BOOL
CheckIfFileExists(
PCWSTR pszFilePath
);
private:
UTILITY() {}

View File

@ -1,7 +1,5 @@
#include "..\precomp.hxx"
typedef DWORD(*hostfxr_main_fn) (CONST DWORD argc, CONST WCHAR* argv[]);
IN_PROCESS_APPLICATION* IN_PROCESS_APPLICATION::s_Application = NULL;
IN_PROCESS_APPLICATION::IN_PROCESS_APPLICATION(
@ -180,84 +178,6 @@ IN_PROCESS_APPLICATION::OnExecuteRequest(
return RQ_NOTIFICATION_FINISH_REQUEST;
}
BOOL
IN_PROCESS_APPLICATION::DirectoryExists(
_In_ STRU *pstrPath
)
{
WIN32_FILE_ATTRIBUTE_DATA data;
if (pstrPath->IsEmpty())
{
return false;
}
return GetFileAttributesExW(pstrPath->QueryStr(), GetFileExInfoStandard, &data);
}
BOOL
IN_PROCESS_APPLICATION::GetEnv(
_In_ PCWSTR pszEnvironmentVariable,
_Out_ STRU *pstrResult
)
{
DWORD dwLength;
PWSTR pszBuffer = NULL;
BOOL fSucceeded = FALSE;
if (pszEnvironmentVariable == NULL)
{
goto Finished;
}
pstrResult->Reset();
dwLength = GetEnvironmentVariableW(pszEnvironmentVariable, NULL, 0);
if (dwLength == 0)
{
goto Finished;
}
pszBuffer = new WCHAR[dwLength];
if (GetEnvironmentVariableW(pszEnvironmentVariable, pszBuffer, dwLength) == 0)
{
goto Finished;
}
pstrResult->Copy(pszBuffer);
fSucceeded = TRUE;
Finished:
if (pszBuffer != NULL) {
delete[] pszBuffer;
}
return fSucceeded;
}
VOID
IN_PROCESS_APPLICATION::FindDotNetFolders(
_In_ PCWSTR pszPath,
_Out_ std::vector<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,
@ -277,30 +197,6 @@ IN_PROCESS_APPLICATION::SetCallbackHandles(
SetEvent(m_pInitalizeEvent);
}
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))
{
// TODO using max instead of std::max works
max_ver = max(max_ver, fx_ver);
}
}
hr = pstrResult->Copy(max_ver.as_str().c_str());
// we check FAILED(hr) outside of function
return hr;
}
VOID
IN_PROCESS_APPLICATION::SetStdOut(
VOID
@ -495,6 +391,11 @@ IN_PROCESS_APPLICATION::LoadManagedApplication
{
// Core CLR has already been loaded.
// Cannot load more than once even there was a failure
if (m_fLoadManagedAppError)
{
hr = E_APPLICATION_ACTIVATION_EXEC_FAILURE;
}
goto Finished;
}
@ -505,6 +406,11 @@ IN_PROCESS_APPLICATION::LoadManagedApplication
fLocked = TRUE;
if (m_fManagedAppLoaded || m_fLoadManagedAppError)
{
if (m_fLoadManagedAppError)
{
hr = E_APPLICATION_ACTIVATION_EXEC_FAILURE;
}
goto Finished;
}
@ -572,16 +478,12 @@ IN_PROCESS_APPLICATION::LoadManagedApplication
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 ?
m_fLoadManagedAppError = TRUE; // m_hThread != NULL ?
// TODO
//if (SUCCEEDED(strEventMsg.SafeSnwprintf(
@ -610,6 +512,12 @@ Finished:
// }
//}
}
if (fLocked)
{
ReleaseSRWLockExclusive(&m_srwLock);
}
return hr;
}
@ -619,166 +527,29 @@ IN_PROCESS_APPLICATION::ExecuteAspNetCoreProcess(
_In_ LPVOID pContext
)
{
HRESULT hr = S_OK;
IN_PROCESS_APPLICATION *pApplication = (IN_PROCESS_APPLICATION*)pContext;
DBG_ASSERT(pApplication != NULL);
pApplication->ExecuteApplication();
hr = pApplication->ExecuteApplication();
//
// no need to log the error here as if error happened, the thread will exit
// the error will ba catched by caller LoadManagedApplication which will log an error
//
}
}
HRESULT
IN_PROCESS_APPLICATION::ExecuteApplication(
VOID
)
{
HRESULT hr = S_OK;
HRESULT hr = S_OK;
HMODULE hModule;
hostfxr_main_fn pProc;
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 = (DWORD) wcsnlen_s(pszDotnetExeLocation, 260);
if (dwCopyLength == 0)
{
continue;
}
// We store both the exe and folder locations as we eventually need to check inside of host\\fxr
// which doesn't need the dotnet.exe portion of the string
// TODO consider reducing allocations.
strDotnetExeLocation.Reset();
strDotnetFolderLocation.Reset();
hr = strDotnetExeLocation.Copy(pszDotnetExeLocation, dwCopyLength);
if (FAILED(hr))
{
goto Finished;
}
hr = strDotnetFolderLocation.Copy(pszDotnetExeLocation, dwCopyLength);
if (FAILED(hr))
{
goto Finished;
}
if (dwCopyLength > 0 && pszDotnetExeLocation[dwCopyLength - 1] != L'\\')
{
hr = strDotnetExeLocation.Append(L"\\");
if (FAILED(hr))
{
goto Finished;
}
}
hr = strDotnetExeLocation.Append(pszDotnetExeString);
if (FAILED(hr))
{
goto Finished;
}
if (PathFileExists(strDotnetExeLocation.QueryStr()))
{
// means we found the folder with a dotnet.exe inside of it.
fFound = TRUE;
break;
}
pszDotnetExeLocation = wcstok_s(NULL, L";", &strDelimeterContext);
}
if (!fFound)
{
// could not find dotnet.exe, error out
hr = ERROR_BAD_ENVIRONMENT;
}
hr = strDotnetFolderLocation.Append(L"\\host\\fxr");
if (FAILED(hr))
{
goto Finished;
}
if (!DirectoryExists(&strDotnetFolderLocation))
{
// error, not found the folder
hr = ERROR_BAD_ENVIRONMENT;
goto Finished;
}
// Find all folders under host\\fxr\\ for version numbers.
hr = strHostFxrSearchExpression.Copy(strDotnetFolderLocation);
if (FAILED(hr))
{
goto Finished;
}
hr = strHostFxrSearchExpression.Append(L"\\*");
if (FAILED(hr))
{
goto Finished;
}
// As we use the logic from core-setup, we are opting to use std here.
// TODO remove all uses of std?
FindDotNetFolders(strHostFxrSearchExpression.QueryStr(), &vVersionFolders);
if (vVersionFolders.size() == 0)
{
// no core framework was found
hr = ERROR_BAD_ENVIRONMENT;
goto Finished;
}
hr = FindHighestDotNetVersion(vVersionFolders, &strHighestDotnetVersion);
if (FAILED(hr))
{
goto Finished;
}
hr = strDotnetFolderLocation.Append(L"\\");
if (FAILED(hr))
{
goto Finished;
}
hr = strDotnetFolderLocation.Append(strHighestDotnetVersion.QueryStr());
if (FAILED(hr))
{
goto Finished;
}
hr = strDotnetFolderLocation.Append(L"\\hostfxr.dll");
if (FAILED(hr))
{
goto Finished;
}
hModule = LoadLibraryW(strDotnetFolderLocation.QueryStr());
// should be a redudant call here, but we will be safe and call it twice.
// TODO AV here on m_pHostFxrParameters being null
hModule = LoadLibraryW(m_pConfig->QueryHostFxrFullPath());
if (hModule == NULL)
{
@ -791,17 +562,10 @@ IN_PROCESS_APPLICATION::ExecuteApplication(
pProc = (hostfxr_main_fn)GetProcAddress(hModule, "hostfxr_main");
if (pProc == NULL)
{
hr = ERROR_BAD_ENVIRONMENT; // better hrresult?
hr = ERROR_BAD_ENVIRONMENT;
goto Finished;
}
// The first argument is mostly ignored
argv[0] = strDotnetExeLocation.QueryStr();
UTILITY::ConvertPathToFullPath(m_pConfig->QueryArguments()->QueryStr(),
m_pConfig->QueryApplicationPhysicalPath()->QueryStr(),
&strApplicationFullPath);
argv[1] = strApplicationFullPath.QueryStr();
// There can only ever be a single instance of .NET Core
// loaded in the process but we need to get config information to boot it up in the
// first place. This is happening in an execute request handler and everyone waits
@ -811,7 +575,7 @@ IN_PROCESS_APPLICATION::ExecuteApplication(
// set the callbacks
s_Application = this;
RunDotnetApplication(argv, pProc);
RunDotnetApplication(m_pConfig->QueryHostFxrArgCount(), m_pConfig->QueryHostFxrArguments(), pProc);
Finished:
//
@ -862,19 +626,20 @@ Finished:
// Calls hostfxr_main with the hostfxr and application as arguments.
// Method should be called with only
// Need to have __try / __except in methods that require unwinding.
// Note, this will not
//
HRESULT
IN_PROCESS_APPLICATION::RunDotnetApplication(PCWSTR* argv, hostfxr_main_fn pProc)
IN_PROCESS_APPLICATION::RunDotnetApplication(DWORD argc, CONST PCWSTR* argv, hostfxr_main_fn pProc)
{
HRESULT hr = S_OK;
__try
{
m_ProcessExitCode = pProc(2, argv);
m_ProcessExitCode = pProc(argc, argv);
}
__except (FilterException(GetExceptionCode(), GetExceptionInformation()))
{
// TODO Log error message here.
hr = E_FAIL;
hr = E_APPLICATION_ACTIVATION_EXEC_FAILURE;
}
return hr;
}

View File

@ -7,12 +7,11 @@ typedef void(*request_handler_cb) (int error, IHttpContext* pHttpContext, void*
typedef REQUEST_NOTIFICATION_STATUS(*PFN_REQUEST_HANDLER) (IN_PROCESS_HANDLER* pInProcessHandler, void* pvRequestHandlerContext);
typedef BOOL(*PFN_SHUTDOWN_HANDLER) (void* pvShutdownHandlerContext);
typedef REQUEST_NOTIFICATION_STATUS(*PFN_MANAGED_CONTEXT_HANDLER)(void *pvManagedHttpContext, HRESULT hrCompletionStatus, DWORD cbCompletion);
typedef DWORD(*hostfxr_main_fn) (CONST DWORD argc, CONST WCHAR* argv[]);
class IN_PROCESS_APPLICATION : public APPLICATION
{
public:
IN_PROCESS_APPLICATION(IHttpServer* pHttpServer, ASPNETCORE_CONFIG *pConfig);
IN_PROCESS_APPLICATION(IHttpServer* pHttpServer, ASPNETCORE_CONFIG* pConfig);
~IN_PROCESS_APPLICATION();
@ -59,16 +58,6 @@ public:
IN_PROCESS_HANDLER* pInProcessHandler
);
static
INT
FilterException(unsigned int code, struct _EXCEPTION_POINTERS *ep);
HRESULT
RunDotnetApplication(
PCWSTR* argv,
hostfxr_main_fn pProc
);
static
IN_PROCESS_APPLICATION*
GetInstance(
@ -120,35 +109,20 @@ private:
VOID
);
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
);
static
INT
FilterException(unsigned int code, struct _EXCEPTION_POINTERS *ep);
HRESULT
RunDotnetApplication(
DWORD argc,
CONST PCWSTR* argv,
hostfxr_main_fn pProc
);
};

View File

@ -127,7 +127,7 @@ struct IISConfigurationData
};
EXTERN_C __MIDL_DECLSPEC_DLLEXPORT
HRESULT // TODO probably should make this a wide string
HRESULT
http_get_application_properties(
_In_ IISConfigurationData* pIISCofigurationData
)