Merge pull request #1030 from dotnet-maestro-bot/merge/release/2.2-to-master
[automated] Merge branch 'release/2.2' => 'master'
This commit is contained in:
commit
3e16ca9c18
|
|
@ -40,7 +40,7 @@
|
|||
</ItemGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<IISExpressArguments>/config:"$(IISExpressAppHostConfig)"</IISExpressArguments>
|
||||
<IISExpressArguments>/config:"$(IISExpressAppHostConfig)" /systray:false</IISExpressArguments>
|
||||
<IISArguments>-h "$(IISAppHostConfig)"</IISArguments>
|
||||
|
||||
<AncmPath>$(NativePlatform)\aspnetcore.dll</AncmPath>
|
||||
|
|
|
|||
|
|
@ -226,11 +226,9 @@
|
|||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="Inc\applicationinfo.h" />
|
||||
<ClInclude Include="Inc\appoffline.h" />
|
||||
<ClInclude Include="Inc\aspnetcore_shim_config.h" />
|
||||
<ClInclude Include="inc\globalmodule.h" />
|
||||
<ClInclude Include="Inc\applicationmanager.h" />
|
||||
<ClInclude Include="Inc\filewatcher.h" />
|
||||
<ClInclude Include="Inc\proxymodule.h" />
|
||||
<ClInclude Include="Inc\precomp.hxx" />
|
||||
</ItemGroup>
|
||||
|
|
@ -239,7 +237,6 @@
|
|||
<ClCompile Include="Src\applicationmanager.cxx" />
|
||||
<ClCompile Include="src\aspnetcore_shim_config.cpp" />
|
||||
<ClCompile Include="Src\dllmain.cpp" />
|
||||
<ClCompile Include="Src\filewatcher.cxx" />
|
||||
<ClCompile Include="src\globalmodule.cpp" />
|
||||
<ClCompile Include="src\precomp.cpp">
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
|
||||
|
|
|
|||
|
|
@ -3,17 +3,12 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <httpserv.h>
|
||||
|
||||
#include "hostfxroptions.h"
|
||||
#include "appoffline.h"
|
||||
#include "filewatcher.h"
|
||||
#include "hashtable.h"
|
||||
#include "hashfn.h"
|
||||
#include "aspnetcore_shim_config.h"
|
||||
#include "iapplication.h"
|
||||
#include "SRWSharedLock.h"
|
||||
#include "ntassert.h"
|
||||
|
||||
#define API_BUFFER_TOO_SMALL 0x80008098
|
||||
|
||||
|
|
@ -37,11 +32,8 @@ public:
|
|||
APPLICATION_INFO() :
|
||||
m_pServer(NULL),
|
||||
m_cRefs(1),
|
||||
m_fAppOfflineFound(FALSE),
|
||||
m_fValid(FALSE),
|
||||
m_fDoneAppCreation(FALSE),
|
||||
m_pAppOfflineHtm(NULL),
|
||||
m_pFileWatcherEntry(NULL),
|
||||
m_fAppCreationAttempted(FALSE),
|
||||
m_pConfiguration(NULL),
|
||||
m_pfnAspNetCoreCreateApplication(NULL)
|
||||
{
|
||||
|
|
@ -60,8 +52,7 @@ public:
|
|||
HRESULT
|
||||
Initialize(
|
||||
_In_ IHttpServer *pServer,
|
||||
_In_ IHttpApplication *pApplication,
|
||||
_In_ FILE_WATCHER *pFileWatcher
|
||||
_In_ IHttpApplication *pApplication
|
||||
);
|
||||
|
||||
VOID
|
||||
|
|
@ -79,18 +70,6 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
APP_OFFLINE_HTM*
|
||||
QueryAppOfflineHtm()
|
||||
{
|
||||
return m_pAppOfflineHtm;
|
||||
}
|
||||
|
||||
BOOL
|
||||
AppOfflineFound()
|
||||
{
|
||||
return m_fAppOfflineFound;
|
||||
}
|
||||
|
||||
BOOL
|
||||
IsValid()
|
||||
{
|
||||
|
|
@ -103,33 +82,22 @@ public:
|
|||
m_fValid = TRUE;
|
||||
}
|
||||
|
||||
VOID
|
||||
UpdateAppOfflineFileHandle();
|
||||
|
||||
HRESULT
|
||||
StartMonitoringAppOffline();
|
||||
|
||||
ASPNETCORE_SHIM_CONFIG*
|
||||
QueryConfig()
|
||||
{
|
||||
return m_pConfiguration;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// ExtractApplication will increase the reference counter of the application
|
||||
// Caller is responsible for dereference the application.
|
||||
// Otherwise memory leak
|
||||
//
|
||||
VOID
|
||||
ExtractApplication(IAPPLICATION** ppApplication)
|
||||
std::unique_ptr<IAPPLICATION, IAPPLICATION_DELETER>
|
||||
ExtractApplication() const
|
||||
{
|
||||
SRWSharedLock lock(m_srwLock);
|
||||
if (m_pApplication != NULL)
|
||||
{
|
||||
m_pApplication->ReferenceApplication();
|
||||
}
|
||||
*ppApplication = m_pApplication;
|
||||
return ReferenceApplication(m_pApplication);
|
||||
}
|
||||
|
||||
VOID
|
||||
|
|
@ -152,11 +120,8 @@ private:
|
|||
|
||||
mutable LONG m_cRefs;
|
||||
STRU m_struInfoKey;
|
||||
BOOL m_fAppOfflineFound;
|
||||
BOOL m_fValid;
|
||||
BOOL m_fDoneAppCreation;
|
||||
APP_OFFLINE_HTM *m_pAppOfflineHtm;
|
||||
FILE_WATCHER_ENTRY *m_pFileWatcherEntry;
|
||||
BOOL m_fAppCreationAttempted;
|
||||
ASPNETCORE_SHIM_CONFIG *m_pConfiguration;
|
||||
IAPPLICATION *m_pApplication;
|
||||
SRWLOCK m_srwLock;
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
#include "applicationinfo.h"
|
||||
#include "multisz.h"
|
||||
#include "filewatcher.h"
|
||||
#include "exceptions.h"
|
||||
|
||||
#define DEFAULT_HASH_BUCKETS 17
|
||||
|
||||
|
|
@ -83,11 +83,6 @@ public:
|
|||
|
||||
~APPLICATION_MANAGER()
|
||||
{
|
||||
if (m_pFileWatcher != NULL)
|
||||
{
|
||||
delete m_pFileWatcher;
|
||||
m_pFileWatcher = NULL;
|
||||
}
|
||||
|
||||
if(m_pApplicationInfoHash != NULL)
|
||||
{
|
||||
|
|
@ -97,41 +92,18 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
FILE_WATCHER*
|
||||
GetFileWatcher()
|
||||
{
|
||||
return m_pFileWatcher;
|
||||
}
|
||||
|
||||
HRESULT Initialize()
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
if(m_pApplicationInfoHash == NULL)
|
||||
{
|
||||
m_pApplicationInfoHash = new APPLICATION_INFO_HASH();
|
||||
|
||||
hr = m_pApplicationInfoHash->Initialize(DEFAULT_HASH_BUCKETS);
|
||||
if(FAILED(hr))
|
||||
try
|
||||
{
|
||||
goto Finished;
|
||||
m_pApplicationInfoHash = new APPLICATION_INFO_HASH();
|
||||
}
|
||||
CATCH_RETURN();
|
||||
RETURN_IF_FAILED(m_pApplicationInfoHash->Initialize(DEFAULT_HASH_BUCKETS));
|
||||
}
|
||||
|
||||
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;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
|
|
@ -139,13 +111,11 @@ private:
|
|||
// we currently limit the size of m_pstrErrorInfo to 5000, be careful if you want to change its payload
|
||||
//
|
||||
APPLICATION_MANAGER() : m_pApplicationInfoHash(NULL),
|
||||
m_pFileWatcher(NULL),
|
||||
m_hostingModel(HOSTING_UNKNOWN)
|
||||
m_hostingModel(HOSTING_UNKNOWN)
|
||||
{
|
||||
InitializeSRWLock(&m_srwLock);
|
||||
}
|
||||
|
||||
FILE_WATCHER *m_pFileWatcher;
|
||||
APPLICATION_INFO_HASH *m_pApplicationInfoHash;
|
||||
static APPLICATION_MANAGER *sm_pApplicationManager;
|
||||
SRWLOCK m_srwLock;
|
||||
|
|
|
|||
|
|
@ -1,105 +0,0 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "stringa.h"
|
||||
#include "stringu.h"
|
||||
|
||||
class APP_OFFLINE_HTM
|
||||
{
|
||||
public:
|
||||
APP_OFFLINE_HTM(LPCWSTR pszPath) : m_cRefs(1)
|
||||
{
|
||||
m_Path.Copy(pszPath);
|
||||
}
|
||||
|
||||
VOID
|
||||
ReferenceAppOfflineHtm() const
|
||||
{
|
||||
InterlockedIncrement(&m_cRefs);
|
||||
}
|
||||
|
||||
VOID
|
||||
DereferenceAppOfflineHtm() const
|
||||
{
|
||||
if (InterlockedDecrement(&m_cRefs) == 0)
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
}
|
||||
|
||||
BOOL
|
||||
Load(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
BOOL fResult = TRUE;
|
||||
LARGE_INTEGER li = { 0 };
|
||||
CHAR *pszBuff = NULL;
|
||||
HANDLE handle = INVALID_HANDLE_VALUE;
|
||||
|
||||
handle = CreateFile(m_Path.QueryStr(),
|
||||
GENERIC_READ,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
FILE_ATTRIBUTE_NORMAL,
|
||||
NULL);
|
||||
|
||||
if (handle == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
if (HRESULT_FROM_WIN32(GetLastError()) == ERROR_FILE_NOT_FOUND)
|
||||
{
|
||||
fResult = FALSE;
|
||||
}
|
||||
|
||||
// This Load() member function is supposed be called only when the change notification event of file creation or file modification happens.
|
||||
// If file is currenlty locked exclusively by other processes, we might get INVALID_HANDLE_VALUE even though the file exists. In that case, we should return TRUE here.
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
if (!GetFileSizeEx(handle, &li))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
if (li.HighPart != 0)
|
||||
{
|
||||
// > 4gb file size not supported
|
||||
// todo: log a warning at event log
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
DWORD bytesRead = 0;
|
||||
|
||||
if (li.LowPart > 0)
|
||||
{
|
||||
pszBuff = new CHAR[li.LowPart + 1];
|
||||
|
||||
if (ReadFile(handle, pszBuff, li.LowPart, &bytesRead, NULL))
|
||||
{
|
||||
m_Contents.Copy(pszBuff, bytesRead);
|
||||
}
|
||||
}
|
||||
|
||||
Finished:
|
||||
if (handle != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
CloseHandle(handle);
|
||||
handle = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
if (pszBuff != NULL)
|
||||
{
|
||||
delete[] pszBuff;
|
||||
pszBuff = NULL;
|
||||
}
|
||||
|
||||
return fResult;
|
||||
}
|
||||
|
||||
mutable LONG m_cRefs;
|
||||
STRA m_Contents;
|
||||
STRU m_Path;
|
||||
};
|
||||
|
|
@ -16,8 +16,9 @@
|
|||
#include <Windows.h>
|
||||
#include <atlbase.h>
|
||||
#include <httpserv.h>
|
||||
#include <ntassert.h>
|
||||
#include "stringu.h"
|
||||
#include "stringu.h"
|
||||
#include "stringa.h"
|
||||
|
||||
extern PVOID g_pModuleId;
|
||||
extern BOOL g_fAspnetcoreRHAssemblyLoaded;
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include "applicationinfo.h"
|
||||
#include "irequesthandler.h"
|
||||
|
||||
|
|
@ -50,7 +51,7 @@ class ASPNET_CORE_PROXY_MODULE : public CHttpModule
|
|||
|
||||
APPLICATION_INFO *m_pApplicationInfo;
|
||||
IAPPLICATION *m_pApplication;
|
||||
IREQUEST_HANDLER *m_pHandler;
|
||||
std::unique_ptr<IREQUEST_HANDLER, IREQUEST_HANDLER_DELETER> m_pHandler;
|
||||
};
|
||||
|
||||
class ASPNET_CORE_PROXY_MODULE_FACTORY : public IHttpModuleFactory
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
|
||||
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||
|
||||
#define FileDescription "IIS AspNetCore Module. Commit: " CommitHash
|
||||
#define FileDescription "IIS AspNetCore Module V2. Commit: " CommitHash
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
|
|
|
|||
|
|
@ -12,29 +12,14 @@
|
|||
#include "SRWExclusiveLock.h"
|
||||
#include "GlobalVersionUtility.h"
|
||||
#include "exceptions.h"
|
||||
#include "HandleWrapper.h"
|
||||
#include "PollingAppOfflineApplication.h"
|
||||
|
||||
const PCWSTR APPLICATION_INFO::s_pwzAspnetcoreInProcessRequestHandlerName = L"aspnetcorev2_inprocess.dll";
|
||||
const PCWSTR APPLICATION_INFO::s_pwzAspnetcoreOutOfProcessRequestHandlerName = L"aspnetcorev2_outofprocess.dll";
|
||||
|
||||
APPLICATION_INFO::~APPLICATION_INFO()
|
||||
{
|
||||
if (m_pAppOfflineHtm != NULL)
|
||||
{
|
||||
m_pAppOfflineHtm->DereferenceAppOfflineHtm();
|
||||
m_pAppOfflineHtm = NULL;
|
||||
}
|
||||
|
||||
if (m_pFileWatcherEntry != NULL)
|
||||
{
|
||||
// Mark the entry as invalid,
|
||||
// StopMonitor will close the file handle and trigger a FCN
|
||||
// the entry will delete itself when processing this FCN
|
||||
m_pFileWatcherEntry->MarkEntryInValid();
|
||||
m_pFileWatcherEntry->StopMonitor();
|
||||
m_pFileWatcherEntry->DereferenceFileWatcherEntry();
|
||||
m_pFileWatcherEntry = NULL;
|
||||
}
|
||||
|
||||
if (m_pApplication != NULL)
|
||||
{
|
||||
// shutdown the application
|
||||
|
|
@ -55,118 +40,24 @@ APPLICATION_INFO::~APPLICATION_INFO()
|
|||
HRESULT
|
||||
APPLICATION_INFO::Initialize(
|
||||
_In_ IHttpServer *pServer,
|
||||
_In_ IHttpApplication *pApplication,
|
||||
_In_ FILE_WATCHER *pFileWatcher
|
||||
_In_ IHttpApplication *pApplication
|
||||
)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
DBG_ASSERT(pServer);
|
||||
DBG_ASSERT(pApplication);
|
||||
DBG_ASSERT(pFileWatcher);
|
||||
|
||||
// todo: make sure Initialize should be called only once
|
||||
m_pServer = pServer;
|
||||
FINISHED_IF_NULL_ALLOC(m_pConfiguration = new ASPNETCORE_SHIM_CONFIG());
|
||||
FINISHED_IF_FAILED(m_pConfiguration->Populate(m_pServer, pApplication));
|
||||
FINISHED_IF_FAILED(m_struInfoKey.Copy(pApplication->GetApplicationId()));
|
||||
FINISHED_IF_NULL_ALLOC(m_pFileWatcherEntry = new FILE_WATCHER_ENTRY(pFileWatcher));
|
||||
|
||||
UpdateAppOfflineFileHandle();
|
||||
|
||||
Finished:
|
||||
return hr;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
APPLICATION_INFO::StartMonitoringAppOffline()
|
||||
{
|
||||
if (m_pFileWatcherEntry != NULL)
|
||||
{
|
||||
RETURN_IF_FAILED(m_pFileWatcherEntry->Create(m_pConfiguration->QueryApplicationPhysicalPath()->QueryStr(), L"app_offline.htm", this, NULL));
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
//
|
||||
// Called by the file watcher when the app_offline.htm's file status has been changed.
|
||||
// If it finds it, we will call recycle on the application.
|
||||
//
|
||||
VOID
|
||||
APPLICATION_INFO::UpdateAppOfflineFileHandle()
|
||||
{
|
||||
STRU strFilePath;
|
||||
UTILITY::ConvertPathToFullPath(L".\\app_offline.htm",
|
||||
m_pConfiguration->QueryApplicationPhysicalPath()->QueryStr(),
|
||||
&strFilePath);
|
||||
APP_OFFLINE_HTM *pOldAppOfflineHtm = NULL;
|
||||
APP_OFFLINE_HTM *pNewAppOfflineHtm = NULL;
|
||||
|
||||
ReferenceApplicationInfo();
|
||||
|
||||
if (INVALID_FILE_ATTRIBUTES == GetFileAttributes(strFilePath.QueryStr()))
|
||||
{
|
||||
// Check if app offline was originally present.
|
||||
// if it was, log that app_offline has been dropped.
|
||||
if (m_fAppOfflineFound)
|
||||
{
|
||||
UTILITY::LogEvent(g_hEventLog,
|
||||
EVENTLOG_INFORMATION_TYPE,
|
||||
ASPNETCORE_EVENT_RECYCLE_APPOFFLINE_REMOVED,
|
||||
ASPNETCORE_EVENT_RECYCLE_APPOFFLINE_REMOVED_MSG);
|
||||
}
|
||||
|
||||
m_fAppOfflineFound = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
pNewAppOfflineHtm = new APP_OFFLINE_HTM(strFilePath.QueryStr());
|
||||
|
||||
if (pNewAppOfflineHtm != NULL)
|
||||
{
|
||||
if (pNewAppOfflineHtm->Load())
|
||||
{
|
||||
//
|
||||
// loaded the new app_offline.htm
|
||||
//
|
||||
pOldAppOfflineHtm = (APP_OFFLINE_HTM *)InterlockedExchangePointer((VOID**)&m_pAppOfflineHtm, pNewAppOfflineHtm);
|
||||
|
||||
if (pOldAppOfflineHtm != NULL)
|
||||
{
|
||||
pOldAppOfflineHtm->DereferenceAppOfflineHtm();
|
||||
pOldAppOfflineHtm = NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// ignored the new app_offline file because the file does not exist.
|
||||
pNewAppOfflineHtm->DereferenceAppOfflineHtm();
|
||||
pNewAppOfflineHtm = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
m_fAppOfflineFound = TRUE;
|
||||
|
||||
// recycle the application
|
||||
if (m_pApplication != NULL)
|
||||
{
|
||||
STACK_STRU(strEventMsg, 256);
|
||||
if (SUCCEEDED(strEventMsg.SafeSnwprintf(
|
||||
ASPNETCORE_EVENT_RECYCLE_APPOFFLINE_MSG,
|
||||
m_pConfiguration->QueryApplicationPhysicalPath()->QueryStr())))
|
||||
{
|
||||
UTILITY::LogEvent(g_hEventLog,
|
||||
EVENTLOG_INFORMATION_TYPE,
|
||||
ASPNETCORE_EVENT_RECYCLE_APPOFFLINE,
|
||||
strEventMsg.QueryStr());
|
||||
}
|
||||
|
||||
RecycleApplication();
|
||||
}
|
||||
}
|
||||
|
||||
DereferenceApplicationInfo();
|
||||
}
|
||||
|
||||
HRESULT
|
||||
APPLICATION_INFO::EnsureApplicationCreated(
|
||||
|
|
@ -179,57 +70,68 @@ APPLICATION_INFO::EnsureApplicationCreated(
|
|||
STRU struHostFxrDllLocation;
|
||||
STACK_STRU(struFileName, 300); // >MAX_PATH
|
||||
|
||||
if (m_pApplication != NULL)
|
||||
if (m_pApplication != nullptr && m_pApplication->QueryStatus() != RECYCLED)
|
||||
{
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
// one optimization for failure scenario is to reduce the lock scope
|
||||
SRWExclusiveLock lock(m_srwLock);
|
||||
|
||||
if (m_pApplication != nullptr)
|
||||
{
|
||||
if (m_pApplication != NULL)
|
||||
if (m_pApplication->QueryStatus() == RECYCLED)
|
||||
{
|
||||
// another thread created the applicaiton
|
||||
FINISHED(S_OK);
|
||||
LOG_INFO("Application went offline");
|
||||
// Application that went offline
|
||||
// are supposed to recycle themselves
|
||||
m_pApplication->DereferenceApplication();
|
||||
m_pApplication = nullptr;
|
||||
}
|
||||
else if (m_fDoneAppCreation)
|
||||
else
|
||||
{
|
||||
// previous CreateApplication failed
|
||||
FINISHED(E_APPLICATION_ACTIVATION_EXEC_FAILURE);
|
||||
// another thread created the application
|
||||
FINISHED(S_OK);
|
||||
}
|
||||
}
|
||||
else if (m_fAppCreationAttempted)
|
||||
{
|
||||
// previous CreateApplication failed
|
||||
FINISHED(E_APPLICATION_ACTIVATION_EXEC_FAILURE);
|
||||
}
|
||||
|
||||
auto& httpApplication = *pHttpContext->GetApplication();
|
||||
if (PollingAppOfflineApplication::ShouldBeStarted(httpApplication))
|
||||
{
|
||||
LOG_INFO("Detected app_ofline file, creating polling application");
|
||||
m_pApplication = new PollingAppOfflineApplication(httpApplication);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Move the request handler check inside of the lock
|
||||
// such that only one request finds and loads it.
|
||||
// FindRequestHandlerAssembly obtains a global lock, but after releasing the lock,
|
||||
// there is a period where we could call
|
||||
|
||||
m_fAppCreationAttempted = TRUE;
|
||||
FINISHED_IF_FAILED(FindRequestHandlerAssembly(struExeLocation));
|
||||
|
||||
if (m_pfnAspNetCoreCreateApplication == NULL)
|
||||
{
|
||||
FINISHED(HRESULT_FROM_WIN32(ERROR_INVALID_FUNCTION));
|
||||
}
|
||||
|
||||
//
|
||||
// in case of app offline, we don't want to create a new application now
|
||||
//
|
||||
if (!m_fAppOfflineFound)
|
||||
{
|
||||
// Move the request handler check inside of the lock
|
||||
// such that only one request finds and loads it.
|
||||
// FindRequestHandlerAssembly obtains a global lock, but after releasing the lock,
|
||||
// there is a period where we could call
|
||||
std::array<APPLICATION_PARAMETER, 1> parameters {
|
||||
{"InProcessExeLocation", struExeLocation.QueryStr()}
|
||||
};
|
||||
LOG_INFO("Creating handler application");
|
||||
FINISHED_IF_FAILED(m_pfnAspNetCoreCreateApplication(
|
||||
m_pServer,
|
||||
pHttpContext->GetApplication(),
|
||||
parameters.data(),
|
||||
static_cast<DWORD>(parameters.size()),
|
||||
&pApplication));
|
||||
|
||||
m_fDoneAppCreation = TRUE;
|
||||
FINISHED_IF_FAILED(FindRequestHandlerAssembly(struExeLocation));
|
||||
|
||||
if (m_pfnAspNetCoreCreateApplication == NULL)
|
||||
{
|
||||
FINISHED(HRESULT_FROM_WIN32(ERROR_INVALID_FUNCTION));
|
||||
}
|
||||
|
||||
std::array<APPLICATION_PARAMETER, 1> parameters {
|
||||
{"InProcessExeLocation", struExeLocation.QueryStr()}
|
||||
};
|
||||
|
||||
FINISHED_IF_FAILED(m_pfnAspNetCoreCreateApplication(
|
||||
m_pServer,
|
||||
pHttpContext->GetApplication(),
|
||||
parameters.data(),
|
||||
static_cast<DWORD>(parameters.size()),
|
||||
&pApplication));
|
||||
|
||||
m_pApplication = pApplication;
|
||||
}
|
||||
m_pApplication = pApplication;
|
||||
}
|
||||
|
||||
Finished:
|
||||
|
|
@ -426,7 +328,7 @@ APPLICATION_INFO::FindNativeAssemblyFromHostfxr(
|
|||
DWORD dwBufferSize = 1024 * 10;
|
||||
DWORD dwRequiredBufferSize = 0;
|
||||
|
||||
DBG_ASSERT(struFileName != NULL);
|
||||
DBG_ASSERT(struFilename != NULL);
|
||||
|
||||
FINISHED_LAST_ERROR_IF_NULL(hmHostFxrDll = LoadLibraryW(hostfxrOptions->GetHostFxrLocation()));
|
||||
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ APPLICATION_MANAGER::GetOrCreateApplicationInfo(
|
|||
{
|
||||
pApplicationInfo = new APPLICATION_INFO();
|
||||
|
||||
FINISHED_IF_FAILED(pApplicationInfo->Initialize(pServer, pHttpContext->GetApplication(), m_pFileWatcher));
|
||||
FINISHED_IF_FAILED(pApplicationInfo->Initialize(pServer, pHttpContext->GetApplication()));
|
||||
|
||||
SRWExclusiveLock lock(m_srwLock);
|
||||
|
||||
|
|
@ -102,10 +102,7 @@ APPLICATION_MANAGER::GetOrCreateApplicationInfo(
|
|||
|
||||
FINISHED_IF_FAILED(m_pApplicationInfoHash->InsertRecord(pApplicationInfo));
|
||||
|
||||
|
||||
*ppApplicationInfo = pApplicationInfo;
|
||||
pApplicationInfo->StartMonitoringAppOffline();
|
||||
|
||||
pApplicationInfo = NULL;
|
||||
}
|
||||
|
||||
|
|
@ -323,12 +320,6 @@ APPLICATION_MANAGER::ShutDown()
|
|||
g_fInShutdown = TRUE;
|
||||
if (m_pApplicationInfoHash != NULL)
|
||||
{
|
||||
if (m_pFileWatcher != NULL)
|
||||
{
|
||||
delete m_pFileWatcher;
|
||||
m_pFileWatcher = NULL;
|
||||
}
|
||||
|
||||
DBG_ASSERT(m_pApplicationInfoHash);
|
||||
|
||||
// During shutdown we lock until we delete the application
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
#include "resources.h"
|
||||
#include "exceptions.h"
|
||||
|
||||
DECLARE_DEBUG_PRINT_OBJECT("aspnetcore.dll");
|
||||
DECLARE_DEBUG_PRINT_OBJECT("aspnetcorev2.dll");
|
||||
|
||||
HTTP_MODULE_ID g_pModuleId = NULL;
|
||||
IHttpServer * g_pHttpServer = NULL;
|
||||
|
|
@ -120,7 +120,7 @@ HRESULT
|
|||
|
||||
// check whether the feature is disabled due to security reason
|
||||
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
||||
L"SOFTWARE\\Microsoft\\IIS Extensions\\IIS AspNetCore Module\\Parameters",
|
||||
L"SOFTWARE\\Microsoft\\IIS Extensions\\IIS AspNetCore Module V2\\Parameters",
|
||||
0,
|
||||
KEY_READ,
|
||||
&hKey) == NO_ERROR)
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ Return value:
|
|||
}
|
||||
|
||||
ASPNET_CORE_PROXY_MODULE::ASPNET_CORE_PROXY_MODULE(
|
||||
) : m_pApplicationInfo(NULL), m_pHandler(NULL)
|
||||
) : m_pApplicationInfo(nullptr), m_pApplication(nullptr), m_pHandler(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -59,12 +59,6 @@ ASPNET_CORE_PROXY_MODULE::~ASPNET_CORE_PROXY_MODULE()
|
|||
m_pApplicationInfo->DereferenceApplicationInfo();
|
||||
m_pApplicationInfo = NULL;
|
||||
}
|
||||
|
||||
if (m_pHandler != NULL)
|
||||
{
|
||||
m_pHandler->DereferenceRequestHandler();
|
||||
m_pHandler = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
__override
|
||||
|
|
@ -77,93 +71,48 @@ ASPNET_CORE_PROXY_MODULE::OnExecuteRequestHandler(
|
|||
HRESULT hr = S_OK;
|
||||
APPLICATION_MANAGER *pApplicationManager = NULL;
|
||||
REQUEST_NOTIFICATION_STATUS retVal = RQ_NOTIFICATION_CONTINUE;
|
||||
IAPPLICATION* pApplication = NULL;
|
||||
STRU struExeLocation;
|
||||
try
|
||||
{
|
||||
|
||||
if (g_fInShutdown)
|
||||
{
|
||||
hr = HRESULT_FROM_WIN32(ERROR_SERVER_SHUTDOWN_IN_PROGRESS);
|
||||
goto Finished;
|
||||
FINISHED(HRESULT_FROM_WIN32(ERROR_SERVER_SHUTDOWN_IN_PROGRESS));
|
||||
}
|
||||
|
||||
pApplicationManager = APPLICATION_MANAGER::GetInstance();
|
||||
|
||||
hr = pApplicationManager->GetOrCreateApplicationInfo(
|
||||
FINISHED_IF_FAILED(pApplicationManager->GetOrCreateApplicationInfo(
|
||||
g_pHttpServer,
|
||||
pHttpContext,
|
||||
&m_pApplicationInfo);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
&m_pApplicationInfo));
|
||||
|
||||
if (!m_pApplicationInfo->IsValid())
|
||||
{
|
||||
// Application cannot be started due to wrong hosting mode
|
||||
// the error should already been logged to window event log for the first request
|
||||
hr = E_APPLICATION_ACTIVATION_EXEC_FAILURE;
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
// app_offline check to avoid loading aspnetcorerh.dll unnecessarily
|
||||
if (m_pApplicationInfo->AppOfflineFound())
|
||||
{
|
||||
// servicing app_offline
|
||||
HTTP_DATA_CHUNK DataChunk;
|
||||
IHttpResponse *pResponse = NULL;
|
||||
APP_OFFLINE_HTM *pAppOfflineHtm = NULL;
|
||||
|
||||
pResponse = pHttpContext->GetResponse();
|
||||
pAppOfflineHtm = m_pApplicationInfo->QueryAppOfflineHtm();
|
||||
DBG_ASSERT(pAppOfflineHtm);
|
||||
DBG_ASSERT(pResponse);
|
||||
|
||||
// Ignore failure hresults as nothing we can do
|
||||
// Set fTrySkipCustomErrors to true as we want client see the offline content
|
||||
pResponse->SetStatus(503, "Service Unavailable", 0, hr, NULL, TRUE);
|
||||
pResponse->SetHeader("Content-Type",
|
||||
"text/html",
|
||||
(USHORT)strlen("text/html"),
|
||||
FALSE
|
||||
);
|
||||
|
||||
DataChunk.DataChunkType = HttpDataChunkFromMemory;
|
||||
DataChunk.FromMemory.pBuffer = (PVOID)pAppOfflineHtm->m_Contents.QueryStr();
|
||||
DataChunk.FromMemory.BufferLength = pAppOfflineHtm->m_Contents.QueryCB();
|
||||
pResponse->WriteEntityChunkByReference(&DataChunk);
|
||||
|
||||
retVal = RQ_NOTIFICATION_FINISH_REQUEST;
|
||||
goto Finished;
|
||||
FINISHED(E_APPLICATION_ACTIVATION_EXEC_FAILURE);
|
||||
}
|
||||
|
||||
// make sure assmebly is loaded and application is created
|
||||
hr = m_pApplicationInfo->EnsureApplicationCreated(pHttpContext);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
FINISHED_IF_FAILED(m_pApplicationInfo->EnsureApplicationCreated(pHttpContext));
|
||||
|
||||
m_pApplicationInfo->ExtractApplication(&pApplication);
|
||||
auto pApplication = m_pApplicationInfo->ExtractApplication();
|
||||
|
||||
// make sure application is in running state
|
||||
// cannot recreate the application as we cannot reload clr for inprocess
|
||||
if (pApplication != NULL &&
|
||||
pApplication->QueryStatus() != APPLICATION_STATUS::RUNNING &&
|
||||
DBG_ASSERT(pHttpContext);
|
||||
|
||||
// We allow OFFLINE application to serve pages
|
||||
if (pApplication->QueryStatus() != APPLICATION_STATUS::RUNNING &&
|
||||
pApplication->QueryStatus() != APPLICATION_STATUS::STARTING)
|
||||
{
|
||||
hr = HRESULT_FROM_WIN32(ERROR_SERVER_DISABLED);
|
||||
goto Finished;
|
||||
}
|
||||
// Create RequestHandler and process the request
|
||||
hr = pApplication->CreateHandler(pHttpContext,
|
||||
&m_pHandler);
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
IREQUEST_HANDLER* pHandler;
|
||||
// Create RequestHandler and process the request
|
||||
FINISHED_IF_FAILED(pApplication->CreateHandler(pHttpContext, &pHandler));
|
||||
m_pHandler.reset(pHandler);
|
||||
|
||||
retVal = m_pHandler->OnExecuteRequestHandler();
|
||||
}
|
||||
|
|
@ -186,10 +135,6 @@ Finished:
|
|||
}
|
||||
}
|
||||
|
||||
if (pApplication != NULL)
|
||||
{
|
||||
pApplication->DereferenceApplication();
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -205,6 +205,7 @@
|
|||
<ClInclude Include="debugutil.h" />
|
||||
<ClInclude Include="disconnectcontext.h" />
|
||||
<ClInclude Include="irequesthandler.h" />
|
||||
<ClInclude Include="PollingAppOfflineApplication.h" />
|
||||
<ClInclude Include="requesthandler.h" />
|
||||
<ClInclude Include="resources.h" />
|
||||
<ClInclude Include="SRWExclusiveLock.h" />
|
||||
|
|
@ -221,6 +222,7 @@
|
|||
<ClCompile Include="HandleWrapper.cpp" />
|
||||
<ClCompile Include="hostfxr_utility.cpp" />
|
||||
<ClCompile Include="hostfxroptions.cpp" />
|
||||
<ClCompile Include="PollingAppOfflineApplication.cpp" />
|
||||
<ClCompile Include="SRWExclusiveLock.cpp" />
|
||||
<ClCompile Include="SRWSharedLock.cpp" />
|
||||
<ClCompile Include="stdafx.cpp">
|
||||
|
|
|
|||
|
|
@ -0,0 +1,133 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
#include "PollingAppOfflineApplication.h"
|
||||
|
||||
#include <experimental/filesystem>
|
||||
#include "SRWExclusiveLock.h"
|
||||
#include "HandleWrapper.h"
|
||||
|
||||
HRESULT PollingAppOfflineApplication::CreateHandler(IHttpContext* pHttpContext, IREQUEST_HANDLER** pRequestHandler)
|
||||
{
|
||||
try
|
||||
{
|
||||
*pRequestHandler = new PollingAppOfflineHandler(pHttpContext, m_strAppOfflineContent);
|
||||
}
|
||||
CATCH_RETURN();
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
APPLICATION_STATUS PollingAppOfflineApplication::QueryStatus()
|
||||
{
|
||||
if (AppOfflineExists())
|
||||
{
|
||||
return APPLICATION_STATUS::RUNNING;
|
||||
}
|
||||
|
||||
return APPLICATION_STATUS::RECYCLED;
|
||||
}
|
||||
|
||||
bool
|
||||
PollingAppOfflineApplication::AppOfflineExists()
|
||||
{
|
||||
const auto ulCurrentTime = GetTickCount64();
|
||||
//
|
||||
// we only care about app offline presented. If not, it means the application has started
|
||||
// and is monitoring the app offline file
|
||||
// we cache the file exist check result for 1 second
|
||||
//
|
||||
if (ulCurrentTime - m_ulLastCheckTime > c_appOfflineRefreshIntervalMS)
|
||||
{
|
||||
SRWExclusiveLock lock(m_statusLock);
|
||||
if (ulCurrentTime - m_ulLastCheckTime > c_appOfflineRefreshIntervalMS)
|
||||
{
|
||||
m_fAppOfflineFound = is_regular_file(m_appOfflineLocation);
|
||||
if(m_fAppOfflineFound)
|
||||
{
|
||||
LOG_IF_FAILED(LoadAppOfflineContent());
|
||||
}
|
||||
m_ulLastCheckTime = ulCurrentTime;
|
||||
}
|
||||
}
|
||||
return m_fAppOfflineFound;
|
||||
}
|
||||
|
||||
HRESULT PollingAppOfflineApplication::LoadAppOfflineContent()
|
||||
{
|
||||
LARGE_INTEGER li = {};
|
||||
|
||||
HandleWrapper<InvalidHandleTraits> handle = CreateFile(m_appOfflineLocation.c_str(),
|
||||
GENERIC_READ,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||
nullptr,
|
||||
OPEN_EXISTING,
|
||||
FILE_ATTRIBUTE_NORMAL,
|
||||
nullptr);
|
||||
|
||||
RETURN_LAST_ERROR_IF(handle == INVALID_HANDLE_VALUE);
|
||||
|
||||
RETURN_LAST_ERROR_IF (!GetFileSizeEx(handle, &li));
|
||||
|
||||
if (li.HighPart != 0)
|
||||
{
|
||||
// > 4gb file size not supported
|
||||
// todo: log a warning at event log
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (li.LowPart > 0)
|
||||
{
|
||||
DWORD bytesRead = 0;
|
||||
std::string pszBuff(li.LowPart + 1, '\0');
|
||||
|
||||
RETURN_LAST_ERROR_IF(!ReadFile(handle, pszBuff.data(), li.LowPart, &bytesRead, NULL));
|
||||
pszBuff.resize(bytesRead);
|
||||
|
||||
m_strAppOfflineContent = pszBuff;
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
bool PollingAppOfflineApplication::ShouldBeStarted(IHttpApplication& pApplication)
|
||||
{
|
||||
return is_regular_file(GetAppOfflineLocation(pApplication));
|
||||
}
|
||||
|
||||
std::experimental::filesystem::path PollingAppOfflineApplication::GetAppOfflineLocation(IHttpApplication& pApplication)
|
||||
{
|
||||
return std::experimental::filesystem::path(pApplication.GetApplicationPhysicalPath()) / "app_offline.htm";
|
||||
}
|
||||
|
||||
void PollingAppOfflineApplication::ShutDown()
|
||||
{
|
||||
}
|
||||
|
||||
void PollingAppOfflineApplication::Recycle()
|
||||
{
|
||||
}
|
||||
|
||||
REQUEST_NOTIFICATION_STATUS PollingAppOfflineHandler::OnExecuteRequestHandler()
|
||||
{
|
||||
HTTP_DATA_CHUNK DataChunk;
|
||||
IHttpResponse* pResponse = m_pContext->GetResponse();
|
||||
|
||||
DBG_ASSERT(pResponse);
|
||||
|
||||
// Ignore failure hresults as nothing we can do
|
||||
// Set fTrySkipCustomErrors to true as we want client see the offline content
|
||||
pResponse->SetStatus(503, "Service Unavailable", 0, S_OK, nullptr, TRUE);
|
||||
pResponse->SetHeader("Content-Type",
|
||||
"text/html",
|
||||
static_cast<USHORT>(strlen("text/html")),
|
||||
FALSE
|
||||
);
|
||||
|
||||
DataChunk.DataChunkType = HttpDataChunkFromMemory;
|
||||
DataChunk.FromMemory.pBuffer = m_strAppOfflineContent.data();
|
||||
DataChunk.FromMemory.BufferLength = static_cast<ULONG>(m_strAppOfflineContent.size());
|
||||
pResponse->WriteEntityChunkByReference(&DataChunk);
|
||||
|
||||
return REQUEST_NOTIFICATION_STATUS::RQ_NOTIFICATION_FINISH_REQUEST;
|
||||
}
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
#pragma once
|
||||
#include <experimental/filesystem>
|
||||
#include "application.h"
|
||||
#include "requesthandler.h"
|
||||
|
||||
class PollingAppOfflineApplication: public APPLICATION
|
||||
{
|
||||
public:
|
||||
PollingAppOfflineApplication(IHttpApplication& pApplication)
|
||||
:
|
||||
m_ulLastCheckTime(0),
|
||||
m_appOfflineLocation(GetAppOfflineLocation(pApplication)),
|
||||
m_fAppOfflineFound(false)
|
||||
{
|
||||
InitializeSRWLock(&m_statusLock);
|
||||
}
|
||||
|
||||
HRESULT CreateHandler(IHttpContext* pHttpContext, IREQUEST_HANDLER** pRequestHandler) override;
|
||||
|
||||
APPLICATION_STATUS QueryStatus() override;
|
||||
bool AppOfflineExists();
|
||||
HRESULT LoadAppOfflineContent();
|
||||
static bool ShouldBeStarted(IHttpApplication& pApplication);
|
||||
void ShutDown() override;
|
||||
void Recycle() override;
|
||||
|
||||
private:
|
||||
static const int c_appOfflineRefreshIntervalMS = 200;
|
||||
static std::experimental::filesystem::path GetAppOfflineLocation(IHttpApplication& pApplication);
|
||||
std::string m_strAppOfflineContent;
|
||||
ULONGLONG m_ulLastCheckTime;
|
||||
std::experimental::filesystem::path m_appOfflineLocation;
|
||||
bool m_fAppOfflineFound;
|
||||
SRWLOCK m_statusLock {};
|
||||
};
|
||||
|
||||
|
||||
class PollingAppOfflineHandler: public REQUEST_HANDLER
|
||||
{
|
||||
public:
|
||||
PollingAppOfflineHandler(IHttpContext* pContext, const std::string appOfflineContent)
|
||||
: m_pContext(pContext),
|
||||
m_strAppOfflineContent(appOfflineContent)
|
||||
{
|
||||
}
|
||||
|
||||
REQUEST_NOTIFICATION_STATUS OnExecuteRequestHandler() override;
|
||||
|
||||
private:
|
||||
IHttpContext* m_pContext;
|
||||
std::string m_strAppOfflineContent;
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -4,12 +4,18 @@
|
|||
#pragma once
|
||||
|
||||
#include "iapplication.h"
|
||||
#include "exceptions.h"
|
||||
#include "utility.h"
|
||||
#include "ntassert.h"
|
||||
|
||||
|
||||
class APPLICATION : public IAPPLICATION
|
||||
{
|
||||
|
||||
public:
|
||||
// Non-copyable
|
||||
APPLICATION(const APPLICATION&) = delete;
|
||||
const APPLICATION& operator=(const APPLICATION&) = delete;
|
||||
|
||||
APPLICATION_STATUS
|
||||
QueryStatus() override
|
||||
|
|
@ -33,8 +39,7 @@ public:
|
|||
{
|
||||
DBG_ASSERT(m_cRefs != 0);
|
||||
|
||||
LONG cRefs = 0;
|
||||
if ((cRefs = InterlockedDecrement(&m_cRefs)) == 0)
|
||||
if (InterlockedDecrement(&m_cRefs) == 0)
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
|
|
@ -42,7 +47,7 @@ public:
|
|||
|
||||
protected:
|
||||
volatile APPLICATION_STATUS m_status = APPLICATION_STATUS::UNKNOWN;
|
||||
|
||||
private:
|
||||
|
||||
mutable LONG m_cRefs;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -171,7 +171,7 @@ Language=English
|
|||
.
|
||||
|
||||
Messageid=1024
|
||||
SymbolicName=ASPNETCORE_EVENT_RECYCLE_APPOFFLINE_REMOVED
|
||||
SymbolicName=ASPNETCORE_EVENT_MONITOR_APPOFFLINE_ERROR
|
||||
Language=English
|
||||
%1
|
||||
.
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ DebugInitialize()
|
|||
HKEY hKey;
|
||||
|
||||
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
||||
L"SOFTWARE\\Microsoft\\IIS Extensions\\IIS AspNetCore Module\\Parameters",
|
||||
L"SOFTWARE\\Microsoft\\IIS Extensions\\IIS AspNetCore Module V2\\Parameters",
|
||||
0,
|
||||
KEY_READ,
|
||||
&hKey) == NO_ERROR)
|
||||
|
|
|
|||
|
|
@ -225,8 +225,8 @@ HOSTFXR_UTILITY::ParseHostfxrArguments(
|
|||
{
|
||||
UNREFERENCED_PARAMETER(hEventLog); // TODO use event log to set errors.
|
||||
|
||||
DBG_ASSERT(dwArgCount != NULL);
|
||||
DBG_ASSERT(pwzArgv != NULL);
|
||||
DBG_ASSERT(pdwArgCount != NULL);
|
||||
DBG_ASSERT(pbstrArgv != NULL);
|
||||
DBG_ASSERT(pwzExePath != NULL);
|
||||
|
||||
HRESULT hr = S_OK;
|
||||
|
|
@ -324,7 +324,6 @@ Finished:
|
|||
if (pwzArgs != NULL)
|
||||
{
|
||||
LocalFree(pwzArgs);
|
||||
DBG_ASSERT(pwzArgs == NULL);
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include "irequesthandler.h"
|
||||
|
||||
enum APPLICATION_STATUS
|
||||
|
|
@ -11,6 +12,7 @@ enum APPLICATION_STATUS
|
|||
STARTING,
|
||||
RUNNING,
|
||||
SHUTDOWN,
|
||||
RECYCLED,
|
||||
FAIL
|
||||
};
|
||||
|
||||
|
|
@ -53,3 +55,18 @@ public:
|
|||
_In_ IHttpContext *pHttpContext,
|
||||
_Out_ IREQUEST_HANDLER **pRequestHandler) = 0;
|
||||
};
|
||||
|
||||
struct IAPPLICATION_DELETER
|
||||
{
|
||||
void operator ()(IAPPLICATION* application) const
|
||||
{
|
||||
application->DereferenceApplication();
|
||||
}
|
||||
};
|
||||
|
||||
template< class APPLICATION >
|
||||
std::unique_ptr<APPLICATION, IAPPLICATION_DELETER> ReferenceApplication(APPLICATION* application)
|
||||
{
|
||||
application->ReferenceApplication();
|
||||
return std::unique_ptr<APPLICATION, IAPPLICATION_DELETER>(application);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <httpserv.h>
|
||||
#include <memory>
|
||||
|
||||
//
|
||||
// Pure abstract class
|
||||
|
|
@ -46,3 +47,12 @@ public:
|
|||
VOID
|
||||
) = 0;
|
||||
};
|
||||
|
||||
|
||||
struct IREQUEST_HANDLER_DELETER
|
||||
{
|
||||
void operator ()(IREQUEST_HANDLER* application) const
|
||||
{
|
||||
application->DereferenceRequestHandler();
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -24,13 +24,26 @@ public:
|
|||
{
|
||||
DBG_ASSERT(m_cRefs != 0);
|
||||
|
||||
LONG cRefs = 0;
|
||||
if ((cRefs = InterlockedDecrement(&m_cRefs)) == 0)
|
||||
if (InterlockedDecrement(&m_cRefs) == 0)
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
}
|
||||
|
||||
REQUEST_NOTIFICATION_STATUS OnAsyncCompletion(DWORD cbCompletion, HRESULT hrCompletionStatus) override
|
||||
{
|
||||
UNREFERENCED_PARAMETER(cbCompletion);
|
||||
UNREFERENCED_PARAMETER(hrCompletionStatus);
|
||||
// We shouldn't get here in default implementation
|
||||
DBG_ASSERT(FALSE);
|
||||
return RQ_NOTIFICATION_FINISH_REQUEST;
|
||||
}
|
||||
|
||||
VOID TerminateRequest(bool fClientInitiated) override
|
||||
{
|
||||
UNREFERENCED_PARAMETER(fClientInitiated);
|
||||
}
|
||||
|
||||
private:
|
||||
mutable LONG m_cRefs = 1;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@
|
|||
#define ASPNETCORE_EVENT_INPROCESS_THREAD_EXIT_MSG L"Application '%s' with physical root '%s' hit unexpected managed background thread exit, ErrorCode = '0x%x. Please check the stderr logs for more information."
|
||||
#define ASPNETCORE_EVENT_APP_IN_SHUTDOWN_MSG L"Application shutting down."
|
||||
#define ASPNETCORE_EVENT_RECYCLE_APPOFFLINE_MSG L"Application '%s' was recycled after detecting the app_offline file."
|
||||
#define ASPNETCORE_EVENT_RECYCLE_APPOFFLINE_REMOVED_MSG L"App_offline.htm has been removed from the application. Application will be recycled."
|
||||
#define ASPNETCORE_EVENT_MONITOR_APPOFFLINE_ERROR_MSG L"Monitoring app_offline.htm failed for application '%s', ErrorCode '0x%x'. "
|
||||
#define ASPNETCORE_EVENT_RECYCLE_CONFIGURATION_MSG L"Application '%s' was recycled due to configuration change"
|
||||
#define ASPNETCORE_EVENT_RECYCLE_FAILURE_CONFIGURATION_MSG L"Failed to recycle application due to a configuration change at '%s'. Recycling worker process."
|
||||
#define ASPNETCORE_EVENT_MODULE_DISABLED_MSG L"AspNetCore Module is disabled"
|
||||
|
|
|
|||
|
|
@ -11,6 +11,10 @@
|
|||
#undef ASSERT
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG
|
||||
#define DBG 1
|
||||
#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 ) ) )
|
||||
|
|
|
|||
|
|
@ -7,11 +7,12 @@
|
|||
hostfxr_main_fn InProcessApplicationBase::s_fMainCallback = NULL;
|
||||
|
||||
InProcessApplicationBase::InProcessApplicationBase(
|
||||
IHttpServer *pHttpServer)
|
||||
:
|
||||
m_srwLock(),
|
||||
m_fRecycleCalled(FALSE),
|
||||
m_pHttpServer(pHttpServer)
|
||||
IHttpServer& pHttpServer,
|
||||
IHttpApplication& pHttpApplication)
|
||||
: AppOfflineTrackingApplication(pHttpApplication),
|
||||
m_fRecycleCalled(FALSE),
|
||||
m_srwLock(),
|
||||
m_pHttpServer(pHttpServer)
|
||||
{
|
||||
InitializeSRWLock(&m_srwLock);
|
||||
}
|
||||
|
|
@ -39,23 +40,19 @@ InProcessApplicationBase::Recycle(
|
|||
m_fRecycleCalled = true;
|
||||
}
|
||||
|
||||
if (!m_pHttpServer->IsCommandLineLaunch())
|
||||
if (!m_pHttpServer.IsCommandLineLaunch())
|
||||
{
|
||||
// IIS scenario.
|
||||
// We don't actually handle any shutdown logic here.
|
||||
// Instead, we notify IIS that the process needs to be recycled, which will call
|
||||
// ApplicationManager->Shutdown(). This will call shutdown on the application.
|
||||
m_pHttpServer->RecycleProcess(L"AspNetCore InProcess Recycle Process on Demand");
|
||||
m_pHttpServer.RecycleProcess(L"AspNetCore InProcess Recycle Process on Demand");
|
||||
}
|
||||
else
|
||||
{
|
||||
// IISExpress scenario
|
||||
// Try to graceful shutdown the managed application
|
||||
// and call exit to terminate current process
|
||||
ShutDown();
|
||||
// If we set a static callback, we don't want to kill the current process as
|
||||
// that will kill the test process and means we are running in hostable webcore mode.
|
||||
if (m_pHttpServer->IsCommandLineLaunch()
|
||||
if (m_pHttpServer.IsCommandLineLaunch()
|
||||
&& s_fMainCallback == NULL)
|
||||
{
|
||||
exit(0);
|
||||
|
|
|
|||
|
|
@ -3,17 +3,18 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "precomp.hxx"
|
||||
#include "application.h"
|
||||
#include "requesthandler_config.h"
|
||||
#include "AppOfflineTrackingApplication.h"
|
||||
|
||||
typedef INT(*hostfxr_main_fn) (CONST DWORD argc, CONST PCWSTR argv[]); // TODO these may need to be BSTRs
|
||||
|
||||
class InProcessApplicationBase : public APPLICATION
|
||||
class InProcessApplicationBase : public AppOfflineTrackingApplication
|
||||
{
|
||||
public:
|
||||
|
||||
InProcessApplicationBase(IHttpServer* pHttpServer);
|
||||
InProcessApplicationBase(
|
||||
IHttpServer& pHttpServer,
|
||||
IHttpApplication& pHttpApplication);
|
||||
|
||||
~InProcessApplicationBase() = default;
|
||||
|
||||
|
|
@ -22,7 +23,7 @@ public:
|
|||
protected:
|
||||
BOOL m_fRecycleCalled;
|
||||
SRWLOCK m_srwLock;
|
||||
IHttpServer* const m_pHttpServer;
|
||||
IHttpServer& m_pHttpServer;
|
||||
// Allows to override call to hostfxr_main with custome callback
|
||||
// used in testing
|
||||
static hostfxr_main_fn s_fMainCallback;
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@
|
|||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;REQUESTHANDLER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
|
|
@ -104,17 +104,20 @@
|
|||
<CompileAs>CompileAsCpp</CompileAs>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
<ForcedIncludeFiles>precomp.hxx</ForcedIncludeFiles>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
</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>
|
||||
<LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;REQUESTHANDLER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
|
|
@ -135,18 +138,21 @@
|
|||
<CompileAs>CompileAsCpp</CompileAs>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
<ForcedIncludeFiles>precomp.hxx</ForcedIncludeFiles>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
</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>
|
||||
<LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
|
|
@ -166,6 +172,8 @@
|
|||
<CompileAs>CompileAsCpp</CompileAs>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
<ForcedIncludeFiles>precomp.hxx</ForcedIncludeFiles>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
|
|
@ -174,12 +182,13 @@
|
|||
<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>
|
||||
<LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
|
|
@ -199,6 +208,8 @@
|
|||
<CompileAs>CompileAsCpp</CompileAs>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
<ForcedIncludeFiles>precomp.hxx</ForcedIncludeFiles>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
|
|
@ -207,6 +218,7 @@
|
|||
<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>
|
||||
<LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
|
|
@ -224,6 +236,12 @@
|
|||
<ClCompile Include="InProcessApplicationBase.cpp" />
|
||||
<ClCompile Include="inprocesshandler.cpp" />
|
||||
<ClCompile Include="managedexports.cxx" />
|
||||
<ClCompile Include="precomp.cpp">
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="StartupExceptionApplication.cpp" />
|
||||
<ClCompile Include="StartupExceptionHandler.cpp" />
|
||||
</ItemGroup>
|
||||
|
|
|
|||
|
|
@ -5,11 +5,10 @@
|
|||
|
||||
VOID StartupExceptionApplication::ShutDown()
|
||||
{
|
||||
exit(0);
|
||||
}
|
||||
|
||||
HRESULT StartupExceptionApplication::CreateHandler(IHttpContext *pContext, IREQUEST_HANDLER ** pRequestHandler)
|
||||
HRESULT StartupExceptionApplication::CreateHandler(IHttpContext *pHttpContext, IREQUEST_HANDLER ** pRequestHandler)
|
||||
{
|
||||
*pRequestHandler = new StartupExceptionHandler(pContext, m_disableLogs, this);
|
||||
*pRequestHandler = new StartupExceptionHandler(pHttpContext, m_disableLogs, this);
|
||||
return S_OK;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,68 +3,58 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "precomp.hxx"
|
||||
#include "InProcessApplicationBase.h"
|
||||
#include "StartupExceptionHandler.h"
|
||||
#include "SRWExclusiveLock.h"
|
||||
|
||||
class StartupExceptionApplication : public InProcessApplicationBase
|
||||
{
|
||||
public:
|
||||
StartupExceptionApplication(IHttpServer* pServer, BOOL disableLogs)
|
||||
StartupExceptionApplication(
|
||||
IHttpServer& pServer,
|
||||
IHttpApplication& pApplication,
|
||||
BOOL disableLogs)
|
||||
: m_disableLogs(disableLogs),
|
||||
m_pHttpServer(pServer),
|
||||
InProcessApplicationBase(pServer)
|
||||
InProcessApplicationBase(pServer, pApplication)
|
||||
{
|
||||
InitializeSRWLock(&m_srwLock);
|
||||
m_status = APPLICATION_STATUS::RUNNING;
|
||||
html500Page = std::string("<!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 500.30 Error </title><style type=\"text/css\"></style></head> \
|
||||
<body> <div id = \"content\"> \
|
||||
<div class = \"content-container\"><h3> HTTP Error 500.30 - ANCM In-Process Start Failure </h3></div> \
|
||||
<div class = \"content-container\"> \
|
||||
<fieldset> <h4> Common causes of this issue: </h4> \
|
||||
<ul><li> The application failed to start </li> \
|
||||
<li> The application started but then stopped </li> \
|
||||
<li> The application started but threw an exception during startup </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>");
|
||||
}
|
||||
|
||||
~StartupExceptionApplication() = default;
|
||||
|
||||
virtual VOID ShutDown() override;
|
||||
virtual HRESULT CreateHandler(IHttpContext * pHttpContext, IREQUEST_HANDLER ** pRequestHandler) override;
|
||||
VOID ShutDown() override;
|
||||
HRESULT CreateHandler(IHttpContext * pHttpContext, IREQUEST_HANDLER ** pRequestHandler) override;
|
||||
|
||||
std::string&
|
||||
GetStaticHtml500Content()
|
||||
{
|
||||
{
|
||||
SRWExclusiveLock lock(m_srwLock);
|
||||
if (html500Page.empty())
|
||||
{
|
||||
html500Page = std::string("<!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 500.30 Error </title><style type=\"text/css\"></style></head> \
|
||||
<body> <div id = \"content\"> \
|
||||
<div class = \"content-container\"><h3> HTTP Error 500.30 - ANCM In-Process Start Failure </h3></div> \
|
||||
<div class = \"content-container\"> \
|
||||
<fieldset> <h4> Common causes of this issue: </h4> \
|
||||
<ul><li> The application failed to start </li> \
|
||||
<li> The application started but then stopped </li> \
|
||||
<li> The application started but threw an exception during startup </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>");
|
||||
}
|
||||
}
|
||||
|
||||
return html500Page;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string html500Page;
|
||||
SRWLOCK m_srwLock;
|
||||
BOOL m_disableLogs;
|
||||
IHttpServer* m_pHttpServer;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
#include "StartupExceptionApplication.h"
|
||||
#include "StartupExceptionHandler.h"
|
||||
|
||||
REQUEST_NOTIFICATION_STATUS StartupExceptionHandler::OnExecuteRequestHandler()
|
||||
|
|
@ -28,15 +29,5 @@ REQUEST_NOTIFICATION_STATUS StartupExceptionHandler::OnExecuteRequestHandler()
|
|||
}
|
||||
|
||||
return REQUEST_NOTIFICATION_STATUS::RQ_NOTIFICATION_FINISH_REQUEST;
|
||||
|
||||
}
|
||||
|
||||
REQUEST_NOTIFICATION_STATUS StartupExceptionHandler::OnAsyncCompletion(DWORD , HRESULT )
|
||||
{
|
||||
return REQUEST_NOTIFICATION_STATUS::RQ_NOTIFICATION_FINISH_REQUEST;
|
||||
}
|
||||
|
||||
VOID StartupExceptionHandler::TerminateRequest(bool )
|
||||
{
|
||||
return VOID();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,21 +3,13 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "precomp.hxx"
|
||||
#include "requesthandler.h"
|
||||
#include "StartupExceptionApplication.h"
|
||||
|
||||
class StartupExceptionApplication;
|
||||
|
||||
class StartupExceptionHandler : public REQUEST_HANDLER
|
||||
{
|
||||
public:
|
||||
virtual REQUEST_NOTIFICATION_STATUS OnExecuteRequestHandler() override;
|
||||
|
||||
virtual REQUEST_NOTIFICATION_STATUS OnAsyncCompletion(DWORD cbCompletion, HRESULT hrCompletionStatus) override;
|
||||
|
||||
virtual VOID TerminateRequest(bool fClientInitiated) override;
|
||||
|
||||
StartupExceptionHandler(IHttpContext* pContext, BOOL disableLogs, StartupExceptionApplication* pApplication)
|
||||
:
|
||||
m_pContext(pContext),
|
||||
|
|
@ -26,9 +18,7 @@ public:
|
|||
{
|
||||
}
|
||||
|
||||
~StartupExceptionHandler()
|
||||
{
|
||||
}
|
||||
REQUEST_NOTIFICATION_STATUS OnExecuteRequestHandler() override;
|
||||
|
||||
private:
|
||||
IHttpContext * m_pContext;
|
||||
|
|
|
|||
|
|
@ -3,8 +3,6 @@
|
|||
|
||||
// dllmain.cpp : Defines the entry point for the DLL application.
|
||||
|
||||
#include "precomp.hxx"
|
||||
#include <IPHlpApi.h>
|
||||
#include <VersionHelpers.h>
|
||||
|
||||
#include "inprocessapplication.h"
|
||||
|
|
@ -39,7 +37,7 @@ InitializeGlobalConfiguration(
|
|||
g_pHttpServer = pServer;
|
||||
RETURN_IF_FAILED(ALLOC_CACHE_HANDLER::StaticInitialize());
|
||||
RETURN_IF_FAILED(IN_PROCESS_HANDLER::StaticInitialize());
|
||||
|
||||
|
||||
if (pServer->IsCommandLineLaunch())
|
||||
{
|
||||
g_hEventLog = RegisterEventSource(NULL, ASPNETCORE_IISEXPRESS_EVENT_PROVIDER);
|
||||
|
|
@ -89,27 +87,30 @@ CreateApplication(
|
|||
_Out_ IAPPLICATION **ppApplication
|
||||
)
|
||||
{
|
||||
REQUESTHANDLER_CONFIG *pConfig = NULL;
|
||||
|
||||
try
|
||||
{
|
||||
// Initialze some global variables here
|
||||
RETURN_IF_FAILED(InitializeGlobalConfiguration(pServer));
|
||||
|
||||
REQUESTHANDLER_CONFIG *pConfig = nullptr;
|
||||
RETURN_IF_FAILED(REQUESTHANDLER_CONFIG::CreateRequestHandlerConfig(pServer, pHttpApplication, &pConfig));
|
||||
std::unique_ptr<REQUESTHANDLER_CONFIG> pRequestHandlerConfig(pConfig);
|
||||
|
||||
BOOL disableStartupPage = pConfig->QueryDisableStartUpErrorPage();
|
||||
|
||||
auto config = std::unique_ptr<REQUESTHANDLER_CONFIG>(pConfig);
|
||||
|
||||
const bool disableStartupPage = pConfig->QueryDisableStartUpErrorPage();
|
||||
|
||||
auto pApplication = std::make_unique<IN_PROCESS_APPLICATION>(pServer, std::move(config), pParameters, nParameters);
|
||||
|
||||
auto pApplication = std::make_unique<IN_PROCESS_APPLICATION>(*pServer, *pHttpApplication, std::move(pRequestHandlerConfig), pParameters, nParameters);
|
||||
|
||||
if (FAILED_LOG(pApplication->LoadManagedApplication()))
|
||||
{
|
||||
// Set the currently running application to a fake application that returns startup exceptions.
|
||||
*ppApplication = new StartupExceptionApplication(pServer, disableStartupPage);
|
||||
auto pErrorApplication = std::make_unique<StartupExceptionApplication>(*pServer, *pHttpApplication, disableStartupPage);
|
||||
|
||||
RETURN_IF_FAILED(pErrorApplication->StartMonitoringAppOffline());
|
||||
*ppApplication = pErrorApplication.release();
|
||||
}
|
||||
else
|
||||
{
|
||||
RETURN_IF_FAILED(pApplication->StartMonitoringAppOffline());
|
||||
*ppApplication = pApplication.release();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@
|
|||
#include "hostfxroptions.h"
|
||||
#include "requesthandler_config.h"
|
||||
#include "environmentvariablehelpers.h"
|
||||
#include "aspnetcore_event.h"
|
||||
#include "utility.h"
|
||||
#include "EventLog.h"
|
||||
#include "SRWExclusiveLock.h"
|
||||
|
|
@ -18,23 +17,20 @@ const LPCSTR IN_PROCESS_APPLICATION::s_exeLocationParameterName = "InProcessExeL
|
|||
IN_PROCESS_APPLICATION* IN_PROCESS_APPLICATION::s_Application = NULL;
|
||||
|
||||
IN_PROCESS_APPLICATION::IN_PROCESS_APPLICATION(
|
||||
IHttpServer *pHttpServer,
|
||||
IHttpServer& pHttpServer,
|
||||
IHttpApplication& pApplication,
|
||||
std::unique_ptr<REQUESTHANDLER_CONFIG> pConfig,
|
||||
APPLICATION_PARAMETER *pParameters,
|
||||
DWORD nParameters) :
|
||||
InProcessApplicationBase(pHttpServer),
|
||||
InProcessApplicationBase(pHttpServer, pApplication),
|
||||
m_pHttpServer(pHttpServer),
|
||||
m_ProcessExitCode(0),
|
||||
m_fBlockCallbacksIntoManaged(FALSE),
|
||||
m_fShutdownCalledFromNative(FALSE),
|
||||
m_fShutdownCalledFromManaged(FALSE),
|
||||
m_fInitialized(FALSE),
|
||||
m_pConfig(std::move(pConfig))
|
||||
{
|
||||
// is it guaranteed that we have already checked app offline at this point?
|
||||
// If so, I don't think there is much to do here.
|
||||
DBG_ASSERT(pHttpServer != NULL);
|
||||
DBG_ASSERT(pConfig != NULL);
|
||||
DBG_ASSERT(m_pConfig);
|
||||
|
||||
for (DWORD i = 0; i < nParameters; i++)
|
||||
{
|
||||
|
|
@ -207,98 +203,11 @@ IN_PROCESS_APPLICATION::ShutDownInternal()
|
|||
s_Application = NULL;
|
||||
}
|
||||
|
||||
REQUEST_NOTIFICATION_STATUS
|
||||
IN_PROCESS_APPLICATION::OnAsyncCompletion(
|
||||
DWORD cbCompletion,
|
||||
HRESULT hrCompletionStatus,
|
||||
IN_PROCESS_HANDLER* pInProcessHandler
|
||||
)
|
||||
{
|
||||
REQUEST_NOTIFICATION_STATUS dwRequestNotificationStatus = RQ_NOTIFICATION_CONTINUE;
|
||||
|
||||
ReferenceApplication();
|
||||
|
||||
if (pInProcessHandler->QueryIsManagedRequestComplete())
|
||||
{
|
||||
// means PostCompletion has been called and this is the associated callback.
|
||||
dwRequestNotificationStatus = pInProcessHandler->QueryAsyncCompletionStatus();
|
||||
}
|
||||
else if (m_fBlockCallbacksIntoManaged)
|
||||
{
|
||||
// this can potentially happen in ungraceful shutdown.
|
||||
// Or something really wrong happening with async completions
|
||||
// At this point, managed is in a shutting down state and we cannot send a request to it.
|
||||
pInProcessHandler->QueryHttpContext()->GetResponse()->SetStatus(503,
|
||||
"Server has been shutdown",
|
||||
0,
|
||||
(ULONG)HRESULT_FROM_WIN32(ERROR_SHUTDOWN_IN_PROGRESS));
|
||||
dwRequestNotificationStatus = RQ_NOTIFICATION_FINISH_REQUEST;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Call the managed handler for async completion.
|
||||
dwRequestNotificationStatus = m_AsyncCompletionHandler(pInProcessHandler->QueryManagedHttpContext(), hrCompletionStatus, cbCompletion);
|
||||
}
|
||||
|
||||
DereferenceApplication();
|
||||
|
||||
return dwRequestNotificationStatus;
|
||||
}
|
||||
|
||||
REQUEST_NOTIFICATION_STATUS
|
||||
IN_PROCESS_APPLICATION::OnExecuteRequest(
|
||||
_In_ IHttpContext* pHttpContext,
|
||||
_In_ IN_PROCESS_HANDLER* pInProcessHandler
|
||||
)
|
||||
{
|
||||
REQUEST_NOTIFICATION_STATUS dwRequestNotificationStatus = RQ_NOTIFICATION_CONTINUE;
|
||||
PFN_REQUEST_HANDLER pRequestHandler = NULL;
|
||||
|
||||
ReferenceApplication();
|
||||
pRequestHandler = m_RequestHandler;
|
||||
|
||||
if (pRequestHandler == NULL)
|
||||
{
|
||||
//
|
||||
// return error as the application did not register callback
|
||||
//
|
||||
if (ANCMEvents::ANCM_EXECUTE_REQUEST_FAIL::IsEnabled(pHttpContext->GetTraceContext()))
|
||||
{
|
||||
ANCMEvents::ANCM_EXECUTE_REQUEST_FAIL::RaiseEvent(pHttpContext->GetTraceContext(),
|
||||
NULL,
|
||||
(ULONG)E_APPLICATION_ACTIVATION_EXEC_FAILURE);
|
||||
}
|
||||
|
||||
pHttpContext->GetResponse()->SetStatus(500,
|
||||
"Internal Server Error",
|
||||
0,
|
||||
(ULONG)E_APPLICATION_ACTIVATION_EXEC_FAILURE);
|
||||
|
||||
dwRequestNotificationStatus = RQ_NOTIFICATION_FINISH_REQUEST;
|
||||
}
|
||||
else if (m_status != APPLICATION_STATUS::RUNNING || m_fBlockCallbacksIntoManaged)
|
||||
{
|
||||
pHttpContext->GetResponse()->SetStatus(503,
|
||||
"Server is currently shutting down.",
|
||||
0,
|
||||
(ULONG)HRESULT_FROM_WIN32(ERROR_SHUTDOWN_IN_PROGRESS));
|
||||
dwRequestNotificationStatus = RQ_NOTIFICATION_FINISH_REQUEST;
|
||||
}
|
||||
else
|
||||
{
|
||||
dwRequestNotificationStatus = pRequestHandler(pInProcessHandler, m_RequestHandlerContext);
|
||||
}
|
||||
|
||||
DereferenceApplication();
|
||||
|
||||
return dwRequestNotificationStatus;
|
||||
}
|
||||
|
||||
VOID
|
||||
IN_PROCESS_APPLICATION::SetCallbackHandles(
|
||||
_In_ PFN_REQUEST_HANDLER request_handler,
|
||||
_In_ PFN_SHUTDOWN_HANDLER shutdown_handler,
|
||||
_In_ PFN_MANAGED_CONTEXT_HANDLER async_completion_handler,
|
||||
_In_ PFN_ASYNC_COMPLETION_HANDLER async_completion_handler,
|
||||
_In_ VOID* pvRequstHandlerContext,
|
||||
_In_ VOID* pvShutdownHandlerContext
|
||||
)
|
||||
|
|
@ -664,14 +573,6 @@ IN_PROCESS_APPLICATION::RunDotnetApplication(DWORD argc, CONST PCWSTR* argv, hos
|
|||
return hr;
|
||||
}
|
||||
|
||||
// static
|
||||
|
||||
REQUESTHANDLER_CONFIG*
|
||||
IN_PROCESS_APPLICATION::QueryConfig() const
|
||||
{
|
||||
return m_pConfig.get();
|
||||
}
|
||||
|
||||
HRESULT
|
||||
IN_PROCESS_APPLICATION::CreateHandler(
|
||||
_In_ IHttpContext *pHttpContext,
|
||||
|
|
@ -680,7 +581,7 @@ IN_PROCESS_APPLICATION::CreateHandler(
|
|||
HRESULT hr = S_OK;
|
||||
IREQUEST_HANDLER* pHandler = NULL;
|
||||
|
||||
pHandler = new IN_PROCESS_HANDLER(pHttpContext, this);
|
||||
pHandler = new IN_PROCESS_HANDLER(::ReferenceApplication(this), pHttpContext, m_RequestHandler, m_RequestHandlerContext, m_AsyncCompletionHandler);
|
||||
|
||||
if (pHandler == NULL)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -3,21 +3,21 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "precomp.hxx"
|
||||
#include "InProcessApplicationBase.h"
|
||||
#include "inprocesshandler.h"
|
||||
#include "requesthandler_config.h"
|
||||
#include "IOutputManager.h"
|
||||
|
||||
class IN_PROCESS_HANDLER;
|
||||
typedef REQUEST_NOTIFICATION_STATUS(WINAPI * PFN_REQUEST_HANDLER) (IN_PROCESS_HANDLER* pInProcessHandler, void* pvRequestHandlerContext);
|
||||
typedef BOOL(WINAPI * PFN_SHUTDOWN_HANDLER) (void* pvShutdownHandlerContext);
|
||||
typedef REQUEST_NOTIFICATION_STATUS(WINAPI * PFN_MANAGED_CONTEXT_HANDLER)(void *pvManagedHttpContext, HRESULT hrCompletionStatus, DWORD cbCompletion);
|
||||
typedef REQUEST_NOTIFICATION_STATUS(WINAPI * PFN_ASYNC_COMPLETION_HANDLER)(void *pvManagedHttpContext, HRESULT hrCompletionStatus, DWORD cbCompletion);
|
||||
|
||||
class IN_PROCESS_APPLICATION : public InProcessApplicationBase
|
||||
{
|
||||
public:
|
||||
IN_PROCESS_APPLICATION(
|
||||
IHttpServer* pHttpServer,
|
||||
IHttpServer& pHttpServer,
|
||||
IHttpApplication& pApplication,
|
||||
std::unique_ptr<REQUESTHANDLER_CONFIG> pConfig,
|
||||
APPLICATION_PARAMETER *pParameters,
|
||||
DWORD nParameters);
|
||||
|
|
@ -32,7 +32,7 @@ public:
|
|||
SetCallbackHandles(
|
||||
_In_ PFN_REQUEST_HANDLER request_callback,
|
||||
_In_ PFN_SHUTDOWN_HANDLER shutdown_callback,
|
||||
_In_ PFN_MANAGED_CONTEXT_HANDLER managed_context_callback,
|
||||
_In_ PFN_ASYNC_COMPLETION_HANDLER managed_context_callback,
|
||||
_In_ VOID* pvRequstHandlerContext,
|
||||
_In_ VOID* pvShutdownHandlerContext
|
||||
);
|
||||
|
|
@ -60,20 +60,6 @@ public:
|
|||
HRESULT hr
|
||||
);
|
||||
|
||||
REQUEST_NOTIFICATION_STATUS
|
||||
OnAsyncCompletion(
|
||||
DWORD cbCompletion,
|
||||
HRESULT hrCompletionStatus,
|
||||
IN_PROCESS_HANDLER* pInProcessHandler
|
||||
);
|
||||
|
||||
REQUEST_NOTIFICATION_STATUS
|
||||
OnExecuteRequest
|
||||
(
|
||||
IHttpContext* pHttpContext,
|
||||
IN_PROCESS_HANDLER* pInProcessHandler
|
||||
);
|
||||
|
||||
VOID
|
||||
StopCallsIntoManaged(
|
||||
VOID
|
||||
|
|
@ -105,17 +91,27 @@ public:
|
|||
return s_Application;
|
||||
}
|
||||
|
||||
REQUESTHANDLER_CONFIG*
|
||||
QueryConfig() const;
|
||||
|
||||
PCWSTR
|
||||
QueryExeLocation()
|
||||
{
|
||||
return m_struExeLocation.QueryStr();
|
||||
}
|
||||
|
||||
REQUESTHANDLER_CONFIG*
|
||||
QueryConfig()
|
||||
{
|
||||
return m_pConfig.get();
|
||||
}
|
||||
|
||||
bool
|
||||
QueryBlockCallbacksIntoManaged() const
|
||||
{
|
||||
return m_fBlockCallbacksIntoManaged;
|
||||
}
|
||||
|
||||
private:
|
||||
IHttpServer* const m_pHttpServer;
|
||||
|
||||
IHttpServer & m_pHttpServer;
|
||||
|
||||
// Thread executing the .NET Core process
|
||||
HANDLE m_hThread;
|
||||
|
|
@ -128,7 +124,7 @@ private:
|
|||
PFN_SHUTDOWN_HANDLER m_ShutdownHandler;
|
||||
VOID* m_ShutdownHandlerContext;
|
||||
|
||||
PFN_MANAGED_CONTEXT_HANDLER m_AsyncCompletionHandler;
|
||||
PFN_ASYNC_COMPLETION_HANDLER m_AsyncCompletionHandler;
|
||||
|
||||
// The event that gets triggered when managed initialization is complete
|
||||
HANDLE m_pInitalizeEvent;
|
||||
|
|
@ -144,12 +140,11 @@ private:
|
|||
volatile BOOL m_fShutdownCalledFromManaged;
|
||||
BOOL m_fRecycleCalled;
|
||||
BOOL m_fInitialized;
|
||||
|
||||
std::unique_ptr<REQUESTHANDLER_CONFIG> m_pConfig;
|
||||
|
||||
static IN_PROCESS_APPLICATION* s_Application;
|
||||
|
||||
IOutputManager* m_pLoggerProvider;
|
||||
std::unique_ptr<REQUESTHANDLER_CONFIG> m_pConfig;
|
||||
|
||||
static const LPCSTR s_exeLocationParameterName;
|
||||
|
||||
|
|
|
|||
|
|
@ -9,17 +9,20 @@
|
|||
ALLOC_CACHE_HANDLER * IN_PROCESS_HANDLER::sm_pAlloc = NULL;
|
||||
|
||||
IN_PROCESS_HANDLER::IN_PROCESS_HANDLER(
|
||||
_In_ std::unique_ptr<IN_PROCESS_APPLICATION, IAPPLICATION_DELETER> pApplication,
|
||||
_In_ IHttpContext *pW3Context,
|
||||
_In_ IN_PROCESS_APPLICATION *pApplication
|
||||
): m_pW3Context(pW3Context),
|
||||
m_pApplication(pApplication)
|
||||
_In_ PFN_REQUEST_HANDLER pRequestHandler,
|
||||
_In_ void * pRequestHandlerContext,
|
||||
_In_ PFN_ASYNC_COMPLETION_HANDLER pAsyncCompletion
|
||||
): m_pManagedHttpContext(nullptr),
|
||||
m_requestNotificationStatus(RQ_NOTIFICATION_PENDING),
|
||||
m_fManagedRequestComplete(FALSE),
|
||||
m_pW3Context(pW3Context),
|
||||
m_pApplication(std::move(pApplication)),
|
||||
m_pRequestHandler(pRequestHandler),
|
||||
m_pRequestHandlerContext(pRequestHandlerContext),
|
||||
m_pAsyncCompletionHandler(pAsyncCompletion)
|
||||
{
|
||||
m_fManagedRequestComplete = FALSE;
|
||||
}
|
||||
|
||||
IN_PROCESS_HANDLER::~IN_PROCESS_HANDLER()
|
||||
{
|
||||
//todo
|
||||
}
|
||||
|
||||
__override
|
||||
|
|
@ -36,8 +39,32 @@ IN_PROCESS_HANDLER::OnExecuteRequestHandler()
|
|||
L"InProcess Application");
|
||||
}
|
||||
|
||||
//SetHttpSysDisconnectCallback();
|
||||
return m_pApplication->OnExecuteRequest(m_pW3Context, this);
|
||||
if (m_pRequestHandler == NULL)
|
||||
{
|
||||
//
|
||||
// return error as the application did not register callback
|
||||
//
|
||||
if (ANCMEvents::ANCM_EXECUTE_REQUEST_FAIL::IsEnabled(m_pW3Context->GetTraceContext()))
|
||||
{
|
||||
ANCMEvents::ANCM_EXECUTE_REQUEST_FAIL::RaiseEvent(m_pW3Context->GetTraceContext(),
|
||||
NULL,
|
||||
(ULONG)E_APPLICATION_ACTIVATION_EXEC_FAILURE);
|
||||
}
|
||||
|
||||
m_pW3Context->GetResponse()->SetStatus(500,
|
||||
"Internal Server Error",
|
||||
0,
|
||||
(ULONG)E_APPLICATION_ACTIVATION_EXEC_FAILURE);
|
||||
|
||||
return RQ_NOTIFICATION_FINISH_REQUEST;
|
||||
}
|
||||
else if (m_pApplication->QueryStatus() != APPLICATION_STATUS::RUNNING || m_pApplication->
|
||||
QueryBlockCallbacksIntoManaged())
|
||||
{
|
||||
return ServerShutdownMessage();
|
||||
}
|
||||
|
||||
return m_pRequestHandler(this, m_pRequestHandlerContext);
|
||||
}
|
||||
|
||||
__override
|
||||
|
|
@ -47,9 +74,28 @@ IN_PROCESS_HANDLER::OnAsyncCompletion(
|
|||
HRESULT hrCompletionStatus
|
||||
)
|
||||
{
|
||||
// OnAsyncCompletion must call into the application if there was a error. We will redo calls
|
||||
// to Read/Write if we called cancelIo on the IHttpContext.
|
||||
return m_pApplication->OnAsyncCompletion(cbCompletion, hrCompletionStatus, this);
|
||||
if (m_fManagedRequestComplete)
|
||||
{
|
||||
// means PostCompletion has been called and this is the associated callback.
|
||||
return m_requestNotificationStatus;
|
||||
}
|
||||
if (m_pApplication->QueryBlockCallbacksIntoManaged())
|
||||
{
|
||||
// this can potentially happen in ungraceful shutdown.
|
||||
// Or something really wrong happening with async completions
|
||||
// At this point, managed is in a shutting down state and we cannot send a request to it.
|
||||
return ServerShutdownMessage();
|
||||
}
|
||||
|
||||
// Call the managed handler for async completion.
|
||||
return m_pAsyncCompletionHandler(m_pManagedHttpContext, hrCompletionStatus, cbCompletion);
|
||||
}
|
||||
|
||||
REQUEST_NOTIFICATION_STATUS IN_PROCESS_HANDLER::ServerShutdownMessage() const
|
||||
{
|
||||
m_pW3Context->GetResponse()->SetStatus(503, "Server has been shutdown", 0,
|
||||
(ULONG)HRESULT_FROM_WIN32(ERROR_SHUTDOWN_IN_PROGRESS));
|
||||
return RQ_NOTIFICATION_FINISH_REQUEST;
|
||||
}
|
||||
|
||||
VOID
|
||||
|
|
@ -58,31 +104,6 @@ IN_PROCESS_HANDLER::TerminateRequest(
|
|||
)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(fClientInitiated);
|
||||
//todo
|
||||
}
|
||||
|
||||
PVOID
|
||||
IN_PROCESS_HANDLER::QueryManagedHttpContext(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
return m_pManagedHttpContext;
|
||||
}
|
||||
|
||||
BOOL
|
||||
IN_PROCESS_HANDLER::QueryIsManagedRequestComplete(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
return m_fManagedRequestComplete;
|
||||
}
|
||||
|
||||
IHttpContext*
|
||||
IN_PROCESS_HANDLER::QueryHttpContext(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
return m_pW3Context;
|
||||
}
|
||||
|
||||
VOID
|
||||
|
|
@ -93,14 +114,6 @@ IN_PROCESS_HANDLER::IndicateManagedRequestComplete(
|
|||
m_fManagedRequestComplete = TRUE;
|
||||
}
|
||||
|
||||
REQUEST_NOTIFICATION_STATUS
|
||||
IN_PROCESS_HANDLER::QueryAsyncCompletionStatus(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
return m_requestNotificationStatus;
|
||||
}
|
||||
|
||||
VOID
|
||||
IN_PROCESS_HANDLER::SetAsyncCompletionStatus(
|
||||
REQUEST_NOTIFICATION_STATUS requestNotificationStatus
|
||||
|
|
@ -163,7 +176,7 @@ HRESULT
|
|||
}
|
||||
|
||||
hr = sm_pAlloc->Initialize(sizeof(IN_PROCESS_HANDLER),
|
||||
64); // nThreshold
|
||||
64); // nThreshold
|
||||
|
||||
Finished:
|
||||
if (FAILED(hr))
|
||||
|
|
|
|||
|
|
@ -3,8 +3,10 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "precomp.hxx"
|
||||
#include "requesthandler.h"
|
||||
#include <memory>
|
||||
#include "iapplication.h"
|
||||
#include "inprocessapplication.h"
|
||||
|
||||
class IN_PROCESS_APPLICATION;
|
||||
|
||||
|
|
@ -12,10 +14,13 @@ class IN_PROCESS_HANDLER : public REQUEST_HANDLER
|
|||
{
|
||||
public:
|
||||
IN_PROCESS_HANDLER(
|
||||
_In_ std::unique_ptr<IN_PROCESS_APPLICATION, IAPPLICATION_DELETER> pApplication,
|
||||
_In_ IHttpContext *pW3Context,
|
||||
_In_ IN_PROCESS_APPLICATION *pApplication);
|
||||
_In_ PFN_REQUEST_HANDLER pRequestHandler,
|
||||
_In_ void * pRequestHandlerContext,
|
||||
_In_ PFN_ASYNC_COMPLETION_HANDLER pAsyncCompletion);
|
||||
|
||||
~IN_PROCESS_HANDLER() override;
|
||||
~IN_PROCESS_HANDLER() override = default;
|
||||
|
||||
__override
|
||||
REQUEST_NOTIFICATION_STATUS
|
||||
|
|
@ -33,37 +38,25 @@ public:
|
|||
TerminateRequest(
|
||||
bool fClientInitiated
|
||||
) override;
|
||||
|
||||
PVOID
|
||||
QueryManagedHttpContext(
|
||||
|
||||
IHttpContext*
|
||||
QueryHttpContext(
|
||||
VOID
|
||||
);
|
||||
) const
|
||||
{
|
||||
return m_pW3Context;
|
||||
}
|
||||
|
||||
VOID
|
||||
SetManagedHttpContext(
|
||||
PVOID pManagedHttpContext
|
||||
);
|
||||
|
||||
IHttpContext*
|
||||
QueryHttpContext(
|
||||
VOID
|
||||
);
|
||||
|
||||
BOOL
|
||||
QueryIsManagedRequestComplete(
|
||||
VOID
|
||||
);
|
||||
|
||||
VOID
|
||||
IndicateManagedRequestComplete(
|
||||
VOID
|
||||
);
|
||||
|
||||
REQUEST_NOTIFICATION_STATUS
|
||||
QueryAsyncCompletionStatus(
|
||||
VOID
|
||||
);
|
||||
|
||||
VOID
|
||||
SetAsyncCompletionStatus(
|
||||
REQUEST_NOTIFICATION_STATUS requestNotificationStatus
|
||||
|
|
@ -77,12 +70,18 @@ public:
|
|||
HRESULT
|
||||
StaticInitialize(VOID);
|
||||
|
||||
|
||||
private:
|
||||
REQUEST_NOTIFICATION_STATUS
|
||||
ServerShutdownMessage() const;
|
||||
|
||||
PVOID m_pManagedHttpContext;
|
||||
BOOL m_fManagedRequestComplete;
|
||||
REQUEST_NOTIFICATION_STATUS m_requestNotificationStatus;
|
||||
IHttpContext* m_pW3Context;
|
||||
IN_PROCESS_APPLICATION* m_pApplication;
|
||||
std::unique_ptr<IN_PROCESS_APPLICATION, IAPPLICATION_DELETER> m_pApplication;
|
||||
PFN_REQUEST_HANDLER m_pRequestHandler;
|
||||
void* m_pRequestHandlerContext;
|
||||
PFN_ASYNC_COMPLETION_HANDLER m_pAsyncCompletionHandler;
|
||||
|
||||
static ALLOC_CACHE_HANDLER * sm_pAlloc;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
// 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 "inprocessapplication.h"
|
||||
#include "inprocesshandler.h"
|
||||
#include "requesthandler_config.h"
|
||||
|
|
@ -14,7 +13,7 @@ register_callbacks(
|
|||
_In_ IN_PROCESS_APPLICATION* pInProcessApplication,
|
||||
_In_ PFN_REQUEST_HANDLER request_handler,
|
||||
_In_ PFN_SHUTDOWN_HANDLER shutdown_handler,
|
||||
_In_ PFN_MANAGED_CONTEXT_HANDLER async_completion_handler,
|
||||
_In_ PFN_ASYNC_COMPLETION_HANDLER async_completion_handler,
|
||||
_In_ VOID* pvRequstHandlerContext,
|
||||
_In_ VOID* pvShutdownHandlerContext
|
||||
)
|
||||
|
|
@ -64,8 +63,6 @@ http_get_server_variable(
|
|||
PCWSTR pszVariableValue;
|
||||
DWORD cbLength;
|
||||
|
||||
DBG_ASSERT(pszVariableValue != NULL);
|
||||
|
||||
HRESULT hr = pInProcessHandler
|
||||
->QueryHttpContext()
|
||||
->GetServerVariable(pszVariableName, &pszVariableValue, &cbLength);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,4 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
// Do not remove this file. It is used for precompiled header generation
|
||||
|
|
@ -111,6 +111,7 @@
|
|||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>kernel32.lib;user32.lib;nothrownew.obj;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>
|
||||
<LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
|
|
@ -143,6 +144,7 @@
|
|||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>kernel32.lib;user32.lib;nothrownew.obj;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>
|
||||
<LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
|
|
@ -177,6 +179,7 @@
|
|||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<ModuleDefinitionFile>Source.def</ModuleDefinitionFile>
|
||||
<AdditionalDependencies>kernel32.lib;user32.lib;nothrownew.obj;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>
|
||||
<LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
|
|
@ -211,6 +214,7 @@
|
|||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<ModuleDefinitionFile>Source.def</ModuleDefinitionFile>
|
||||
<AdditionalDependencies>kernel32.lib;user32.lib;nothrownew.obj;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>
|
||||
<LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ InitializeGlobalConfiguration(
|
|||
}
|
||||
|
||||
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
||||
L"SOFTWARE\\Microsoft\\IIS Extensions\\IIS AspNetCore Module\\Parameters",
|
||||
L"SOFTWARE\\Microsoft\\IIS Extensions\\IIS AspNetCore Module V2\\Parameters",
|
||||
0,
|
||||
KEY_READ,
|
||||
&hKey) == NO_ERROR)
|
||||
|
|
@ -119,7 +119,7 @@ HRESULT
|
|||
EnsureOutOfProcessInitializtion()
|
||||
{
|
||||
|
||||
DBG_ASSERT(pServer);
|
||||
DBG_ASSERT(g_pHttpServer);
|
||||
|
||||
HRESULT hr = S_OK;
|
||||
BOOL fLocked = FALSE;
|
||||
|
|
@ -148,7 +148,7 @@ EnsureOutOfProcessInitializtion()
|
|||
|
||||
g_hWinHttpModule = GetModuleHandle(TEXT("winhttp.dll"));
|
||||
|
||||
g_hAspNetCoreModule = GetModuleHandle(TEXT("aspnetcore.dll"));
|
||||
g_hAspNetCoreModule = GetModuleHandle(TEXT("aspnetcorev2.dll"));
|
||||
|
||||
hr = WINHTTP_HELPER::StaticInitialize();
|
||||
if (FAILED(hr))
|
||||
|
|
@ -279,42 +279,20 @@ CreateApplication(
|
|||
{
|
||||
UNREFERENCED_PARAMETER(pParameters);
|
||||
UNREFERENCED_PARAMETER(nParameters);
|
||||
HRESULT hr = S_OK;
|
||||
IAPPLICATION *pApplication = NULL;
|
||||
REQUESTHANDLER_CONFIG *pConfig = NULL;
|
||||
|
||||
// Initialze some global variables here
|
||||
|
||||
InitializeGlobalConfiguration(pServer);
|
||||
|
||||
hr = REQUESTHANDLER_CONFIG::CreateRequestHandlerConfig(pServer, pHttpApplication, &pConfig);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
return hr;
|
||||
}
|
||||
REQUESTHANDLER_CONFIG *pConfig = nullptr;
|
||||
RETURN_IF_FAILED(REQUESTHANDLER_CONFIG::CreateRequestHandlerConfig(pServer, pHttpApplication, &pConfig));
|
||||
std::unique_ptr<REQUESTHANDLER_CONFIG> pRequestHandlerConfig(pConfig);
|
||||
|
||||
hr = EnsureOutOfProcessInitializtion();
|
||||
if (FAILED(hr))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
RETURN_IF_FAILED(EnsureOutOfProcessInitializtion());
|
||||
|
||||
pApplication = new OUT_OF_PROCESS_APPLICATION(pConfig);
|
||||
if (pApplication == NULL)
|
||||
{
|
||||
hr = HRESULT_FROM_WIN32(ERROR_OUTOFMEMORY);
|
||||
goto Finished;
|
||||
}
|
||||
std::unique_ptr<OUT_OF_PROCESS_APPLICATION> pApplication = std::make_unique<OUT_OF_PROCESS_APPLICATION>(*pHttpApplication, std::move(pRequestHandlerConfig));
|
||||
|
||||
hr = ((OUT_OF_PROCESS_APPLICATION*)pApplication)->Initialize();
|
||||
if (FAILED(hr))
|
||||
{
|
||||
delete pApplication;
|
||||
pApplication = NULL;
|
||||
goto Finished;
|
||||
}
|
||||
RETURN_IF_FAILED(pApplication->Initialize());
|
||||
RETURN_IF_FAILED(pApplication->StartMonitoringAppOffline());
|
||||
|
||||
*ppApplication = pApplication;
|
||||
|
||||
Finished:
|
||||
return hr;
|
||||
*ppApplication = pApplication.release();
|
||||
return S_OK;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,12 @@
|
|||
#include "..\precomp.hxx"
|
||||
#include "SRWExclusiveLock.h"
|
||||
|
||||
OUT_OF_PROCESS_APPLICATION::OUT_OF_PROCESS_APPLICATION(
|
||||
REQUESTHANDLER_CONFIG *pConfig) :
|
||||
IHttpApplication& pApplication,
|
||||
std::unique_ptr<REQUESTHANDLER_CONFIG> pConfig) :
|
||||
AppOfflineTrackingApplication(pApplication),
|
||||
m_fWebSocketSupported(WEBSOCKET_STATUS::WEBSOCKET_UNKNOWN),
|
||||
m_pConfig(pConfig)
|
||||
m_pConfig(std::move(pConfig))
|
||||
{
|
||||
m_status = APPLICATION_STATUS::RUNNING;
|
||||
m_pProcessManager = NULL;
|
||||
|
|
@ -12,18 +15,13 @@ OUT_OF_PROCESS_APPLICATION::OUT_OF_PROCESS_APPLICATION(
|
|||
|
||||
OUT_OF_PROCESS_APPLICATION::~OUT_OF_PROCESS_APPLICATION()
|
||||
{
|
||||
SRWExclusiveLock lock(m_srwLock);
|
||||
if (m_pProcessManager != NULL)
|
||||
{
|
||||
m_pProcessManager->ShutdownAllProcesses();
|
||||
m_pProcessManager->Shutdown();
|
||||
m_pProcessManager->DereferenceProcessManager();
|
||||
m_pProcessManager = NULL;
|
||||
}
|
||||
|
||||
if (m_pConfig != NULL)
|
||||
{
|
||||
delete m_pConfig;
|
||||
m_pConfig = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT
|
||||
|
|
@ -56,29 +54,18 @@ OUT_OF_PROCESS_APPLICATION::GetProcess(
|
|||
_Out_ SERVER_PROCESS **ppServerProcess
|
||||
)
|
||||
{
|
||||
return m_pProcessManager->GetProcess(m_pConfig, QueryWebsocketStatus(), ppServerProcess);
|
||||
}
|
||||
|
||||
REQUESTHANDLER_CONFIG*
|
||||
OUT_OF_PROCESS_APPLICATION::QueryConfig() const
|
||||
{
|
||||
return m_pConfig;
|
||||
return m_pProcessManager->GetProcess(m_pConfig.get(), QueryWebsocketStatus(), ppServerProcess);
|
||||
}
|
||||
|
||||
__override
|
||||
VOID
|
||||
OUT_OF_PROCESS_APPLICATION::ShutDown()
|
||||
{
|
||||
AcquireSRWLockExclusive(&m_srwLock);
|
||||
{
|
||||
SRWExclusiveLock lock(m_srwLock);
|
||||
if (m_pProcessManager != NULL)
|
||||
{
|
||||
if (m_pProcessManager != NULL)
|
||||
{
|
||||
m_pProcessManager->ShutdownAllProcesses();
|
||||
m_pProcessManager->DereferenceProcessManager();
|
||||
m_pProcessManager = NULL;
|
||||
}
|
||||
m_pProcessManager->Shutdown();
|
||||
}
|
||||
ReleaseSRWLockExclusive(&m_srwLock);
|
||||
}
|
||||
|
||||
__override
|
||||
|
|
|
|||
|
|
@ -3,7 +3,9 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
class OUT_OF_PROCESS_APPLICATION : public APPLICATION
|
||||
#include "AppOfflineTrackingApplication.h"
|
||||
|
||||
class OUT_OF_PROCESS_APPLICATION : public AppOfflineTrackingApplication
|
||||
{
|
||||
enum WEBSOCKET_STATUS
|
||||
{
|
||||
|
|
@ -14,7 +16,8 @@ class OUT_OF_PROCESS_APPLICATION : public APPLICATION
|
|||
|
||||
public:
|
||||
OUT_OF_PROCESS_APPLICATION(
|
||||
REQUESTHANDLER_CONFIG *pConfig);
|
||||
IHttpApplication& pApplication,
|
||||
std::unique_ptr<REQUESTHANDLER_CONFIG> pConfig);
|
||||
|
||||
__override
|
||||
~OUT_OF_PROCESS_APPLICATION() override;
|
||||
|
|
@ -44,14 +47,15 @@ public:
|
|||
_Out_ IREQUEST_HANDLER **pRequestHandler)
|
||||
override;
|
||||
|
||||
REQUESTHANDLER_CONFIG*
|
||||
QueryConfig()
|
||||
const;
|
||||
|
||||
BOOL
|
||||
QueryWebsocketStatus()
|
||||
const;
|
||||
|
||||
REQUESTHANDLER_CONFIG* QueryConfig()
|
||||
{
|
||||
return m_pConfig.get();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
VOID SetWebsocketStatus(IHttpContext *pHttpContext);
|
||||
|
|
@ -60,6 +64,6 @@ private:
|
|||
SRWLOCK m_srwLock;
|
||||
IHttpServer *m_pHttpServer;
|
||||
|
||||
REQUESTHANDLER_CONFIG* m_pConfig;
|
||||
WEBSOCKET_STATUS m_fWebSocketSupported;
|
||||
std::unique_ptr<REQUESTHANDLER_CONFIG> m_pConfig;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -114,6 +114,11 @@ PROCESS_MANAGER::GetProcess(
|
|||
DWORD dwProcessIndex = 0;
|
||||
SERVER_PROCESS *pSelectedServerProcess = NULL;
|
||||
|
||||
if (InterlockedCompareExchange(&m_lStopping, 1L, 1L) == 1L)
|
||||
{
|
||||
return hr = E_APPLICATION_EXITING;
|
||||
}
|
||||
|
||||
if (!m_fServerProcessListReady)
|
||||
{
|
||||
AcquireSRWLockExclusive(&m_srwLock);
|
||||
|
|
|
|||
|
|
@ -88,6 +88,16 @@ public:
|
|||
ReleaseSRWLockExclusive( &m_srwLock );
|
||||
}
|
||||
|
||||
VOID
|
||||
Shutdown(
|
||||
)
|
||||
{
|
||||
if (InterlockedCompareExchange(&m_lStopping, 1L, 0L) == 0L)
|
||||
{
|
||||
ShutdownAllProcesses();
|
||||
}
|
||||
}
|
||||
|
||||
VOID
|
||||
IncrementRapidFailCount(
|
||||
VOID
|
||||
|
|
@ -103,6 +113,7 @@ public:
|
|||
m_dwProcessesPerApplication( 1 ),
|
||||
m_dwRouteToProcessIndex( 0 ),
|
||||
m_fServerProcessListReady(FALSE),
|
||||
m_lStopping(0),
|
||||
m_cRefs( 1 )
|
||||
{
|
||||
m_ppServerProcessList = NULL;
|
||||
|
|
@ -193,4 +204,5 @@ private:
|
|||
|
||||
volatile static BOOL sm_fWSAStartupDone;
|
||||
volatile BOOL m_fServerProcessListReady;
|
||||
volatile LONG m_lStopping;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -0,0 +1,62 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "AppOfflineTrackingApplication.h"
|
||||
#include "EventLog.h"
|
||||
#include "exceptions.h"
|
||||
|
||||
extern HANDLE g_hEventLog;
|
||||
|
||||
HRESULT AppOfflineTrackingApplication::StartMonitoringAppOffline()
|
||||
{
|
||||
LOG_INFOF("Starting app_offline monitoring in application %S", m_applicationPath.c_str());
|
||||
HRESULT hr = StartMonitoringAppOflineImpl();
|
||||
|
||||
if (FAILED_LOG(hr))
|
||||
{
|
||||
UTILITY::LogEventF(g_hEventLog,
|
||||
EVENTLOG_WARNING_TYPE,
|
||||
ASPNETCORE_EVENT_MONITOR_APPOFFLINE_ERROR,
|
||||
ASPNETCORE_EVENT_MONITOR_APPOFFLINE_ERROR_MSG,
|
||||
m_applicationPath.c_str(),
|
||||
hr);
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
HRESULT AppOfflineTrackingApplication::StartMonitoringAppOflineImpl()
|
||||
{
|
||||
if (m_fileWatcher)
|
||||
{
|
||||
RETURN_IF_FAILED(E_UNEXPECTED);
|
||||
}
|
||||
|
||||
m_fileWatcher = std::make_unique<FILE_WATCHER>();
|
||||
RETURN_IF_FAILED(m_fileWatcher->Create());
|
||||
m_fileWatcherEntry.reset(new FILE_WATCHER_ENTRY(m_fileWatcher.get()));
|
||||
// FileWatcherCompletionRoutine calls dereference so we need to get ourselves a reference count
|
||||
m_fileWatcherEntry->ReferenceFileWatcherEntry();
|
||||
RETURN_IF_FAILED(m_fileWatcherEntry->Create(
|
||||
m_applicationPath.c_str(),
|
||||
L"app_offline.htm",
|
||||
std::bind(&AppOfflineTrackingApplication::OnAppOffline, this),
|
||||
NULL));
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
void AppOfflineTrackingApplication::OnAppOffline()
|
||||
{
|
||||
LOG_INFOF("Received app_offline notification in application %S", m_applicationPath.c_str());
|
||||
m_fileWatcherEntry->StopMonitor();
|
||||
m_status = APPLICATION_STATUS::RECYCLED;
|
||||
UTILITY::LogEventF(g_hEventLog,
|
||||
EVENTLOG_INFORMATION_TYPE,
|
||||
ASPNETCORE_EVENT_RECYCLE_APPOFFLINE,
|
||||
ASPNETCORE_EVENT_RECYCLE_APPOFFLINE_MSG,
|
||||
m_applicationPath.c_str());
|
||||
|
||||
Recycle();
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Windows.h>
|
||||
#include "application.h"
|
||||
#include "filewatcher.h"
|
||||
|
||||
class AppOfflineTrackingApplication: public APPLICATION
|
||||
{
|
||||
public:
|
||||
AppOfflineTrackingApplication(const IHttpApplication& application)
|
||||
: m_applicationPath(application.GetApplicationPhysicalPath()),
|
||||
m_fileWatcher(nullptr),
|
||||
m_fileWatcherEntry(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
~AppOfflineTrackingApplication() override = default;
|
||||
|
||||
HRESULT
|
||||
StartMonitoringAppOffline();
|
||||
|
||||
virtual
|
||||
VOID
|
||||
OnAppOffline();
|
||||
|
||||
private:
|
||||
HRESULT
|
||||
StartMonitoringAppOflineImpl();
|
||||
|
||||
std::wstring m_applicationPath;
|
||||
std::unique_ptr<FILE_WATCHER> m_fileWatcher;
|
||||
std::unique_ptr<FILE_WATCHER_ENTRY, FILE_WATCHER_ENTRY_DELETER> m_fileWatcherEntry;
|
||||
};
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?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">
|
||||
|
|
@ -188,7 +188,9 @@
|
|||
</Lib>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="AppOfflineTrackingApplication.h" />
|
||||
<ClInclude Include="environmentvariablehelpers.h" />
|
||||
<ClInclude Include="filewatcher.h" />
|
||||
<ClInclude Include="NullOutputManager.h" />
|
||||
<ClInclude Include="FileOutputManager.h" />
|
||||
<ClInclude Include="environmentvariablehash.h" />
|
||||
|
|
@ -199,7 +201,9 @@
|
|||
<ClInclude Include="stdafx.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="AppOfflineTrackingApplication.cpp" />
|
||||
<ClCompile Include="FileOutputManager.cpp" />
|
||||
<ClCompile Include="filewatcher.cpp" />
|
||||
<ClCompile Include="requesthandler_config.cpp" />
|
||||
<ClCompile Include="LoggingHelpers.cpp" />
|
||||
<ClCompile Include="PipeOutputManager.cpp" />
|
||||
|
|
|
|||
|
|
@ -1,11 +1,9 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "filewatcher.h"
|
||||
|
||||
#include "ntassert.h"
|
||||
#include "applicationinfo.h"
|
||||
|
||||
FILE_WATCHER::FILE_WATCHER() :
|
||||
m_hCompletionPort(NULL),
|
||||
m_hChangeNotificationThread(NULL),
|
||||
|
|
@ -214,7 +212,7 @@ FILE_WATCHER_ENTRY::FILE_WATCHER_ENTRY(FILE_WATCHER * pFileMonitor) :
|
|||
_pFileMonitor(pFileMonitor),
|
||||
_hDirectory(INVALID_HANDLE_VALUE),
|
||||
_hImpersonationToken(NULL),
|
||||
_pApplicationInfo(NULL),
|
||||
_pCallback(),
|
||||
_lStopMonitorCalled(0),
|
||||
_cRefs(1),
|
||||
_fIsValid(TRUE)
|
||||
|
|
@ -225,6 +223,8 @@ FILE_WATCHER_ENTRY::FILE_WATCHER_ENTRY(FILE_WATCHER * pFileMonitor) :
|
|||
|
||||
FILE_WATCHER_ENTRY::~FILE_WATCHER_ENTRY()
|
||||
{
|
||||
StopMonitor();
|
||||
|
||||
_dwSignature = FILE_WATCHER_ENTRY_SIGNATURE_FREE;
|
||||
|
||||
if (_hDirectory != INVALID_HANDLE_VALUE)
|
||||
|
|
@ -330,16 +330,16 @@ HRESULT
|
|||
}
|
||||
}
|
||||
|
||||
Finished:
|
||||
ReleaseSRWLockExclusive(&_srwLock);
|
||||
|
||||
if (fFileChanged)
|
||||
{
|
||||
//
|
||||
// so far we only monitoring app_offline
|
||||
//
|
||||
_pApplicationInfo->UpdateAppOfflineFileHandle();
|
||||
_pCallback();
|
||||
}
|
||||
|
||||
Finished:
|
||||
ReleaseSRWLockExclusive(&_srwLock);
|
||||
return hr;
|
||||
}
|
||||
|
||||
|
|
@ -399,7 +399,7 @@ HRESULT
|
|||
FILE_WATCHER_ENTRY::Create(
|
||||
_In_ PCWSTR pszDirectoryToMonitor,
|
||||
_In_ PCWSTR pszFileNameToMonitor,
|
||||
_In_ APPLICATION_INFO* pApplicationInfo,
|
||||
_In_ std::function<void()> pCallback,
|
||||
_In_ HANDLE hImpersonationToken
|
||||
)
|
||||
{
|
||||
|
|
@ -408,17 +408,14 @@ FILE_WATCHER_ENTRY::Create(
|
|||
|
||||
if (pszDirectoryToMonitor == NULL ||
|
||||
pszFileNameToMonitor == NULL ||
|
||||
pApplicationInfo == NULL)
|
||||
pCallback == NULL)
|
||||
{
|
||||
DBG_ASSERT(FALSE);
|
||||
hr = HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
//
|
||||
//remember the application
|
||||
//
|
||||
_pApplicationInfo = pApplicationInfo;
|
||||
_pCallback = pCallback;
|
||||
|
||||
if (FAILED(hr = _strFileName.Copy(pszFileNameToMonitor)))
|
||||
{
|
||||
|
|
@ -1,20 +1,18 @@
|
|||
// 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>
|
||||
|
||||
#include "stringu.h"
|
||||
#include <Windows.h>
|
||||
#include <functional>
|
||||
|
||||
#define FILE_WATCHER_SHUTDOWN_KEY (ULONG_PTR)(-1)
|
||||
#define FILE_WATCHER_ENTRY_BUFFER_SIZE 4096
|
||||
#define FILE_NOTIFY_VALID_MASK 0x00000fff
|
||||
#define FILE_NOTIFY_VALID_MASK 0x00000fff
|
||||
#define FILE_WATCHER_ENTRY_SIGNATURE ((DWORD) 'FWES')
|
||||
#define FILE_WATCHER_ENTRY_SIGNATURE_FREE ((DWORD) 'sewf')
|
||||
|
||||
class APPLICATION_INFO;
|
||||
|
||||
class FILE_WATCHER{
|
||||
public:
|
||||
|
||||
|
|
@ -62,7 +60,7 @@ public:
|
|||
Create(
|
||||
_In_ PCWSTR pszDirectoryToMonitor,
|
||||
_In_ PCWSTR pszFileNameToMonitor,
|
||||
_In_ APPLICATION_INFO* pApplicationInfo,
|
||||
_In_ std::function<void()> pCallback,
|
||||
_In_ HANDLE hImpersonationToken
|
||||
);
|
||||
|
||||
|
|
@ -111,11 +109,20 @@ private:
|
|||
HANDLE _hImpersonationToken;
|
||||
HANDLE _hDirectory;
|
||||
FILE_WATCHER* _pFileMonitor;
|
||||
APPLICATION_INFO* _pApplicationInfo;
|
||||
STRU _strFileName;
|
||||
STRU _strDirectoryName;
|
||||
LONG _lStopMonitorCalled;
|
||||
mutable LONG _cRefs;
|
||||
BOOL _fIsValid;
|
||||
SRWLOCK _srwLock;
|
||||
std::function<void()> _pCallback;
|
||||
};
|
||||
|
||||
|
||||
struct FILE_WATCHER_ENTRY_DELETER
|
||||
{
|
||||
void operator()(FILE_WATCHER_ENTRY* entry) const
|
||||
{
|
||||
entry->DereferenceFileWatcherEntry();
|
||||
}
|
||||
};
|
||||
|
|
@ -54,7 +54,8 @@ enum APP_HOSTING_MODEL
|
|||
class REQUESTHANDLER_CONFIG
|
||||
{
|
||||
public:
|
||||
virtual
|
||||
|
||||
|
||||
~REQUESTHANDLER_CONFIG();
|
||||
|
||||
static
|
||||
|
|
@ -217,7 +218,6 @@ protected:
|
|||
REQUESTHANDLER_CONFIG() :
|
||||
m_fStdoutLogEnabled(FALSE),
|
||||
m_pEnvironmentVariables(NULL),
|
||||
m_cRefs(1),
|
||||
m_hostingModel(HOSTING_UNKNOWN),
|
||||
m_ppStrArguments(NULL)
|
||||
{
|
||||
|
|
@ -229,8 +229,6 @@ protected:
|
|||
IHttpApplication *pHttpApplication
|
||||
);
|
||||
|
||||
mutable LONG m_cRefs;
|
||||
|
||||
DWORD m_dwRequestTimeoutInMS;
|
||||
DWORD m_dwStartupTimeLimitInMS;
|
||||
DWORD m_dwShutdownTimeLimitInMS;
|
||||
|
|
@ -254,4 +252,5 @@ protected:
|
|||
STRU m_struHostFxrLocation;
|
||||
PWSTR* m_ppStrArguments;
|
||||
DWORD m_dwArgc;
|
||||
|
||||
};
|
||||
|
|
|
|||
|
|
@ -24,5 +24,3 @@
|
|||
#include "dbgutil.h"
|
||||
#include "ahutil.h"
|
||||
#include "hashfn.h"
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,31 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Reflection;
|
||||
using Microsoft.Extensions.Logging.Testing;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
||||
{
|
||||
public class FixtureLoggedTest: LoggedTest
|
||||
{
|
||||
private readonly IISTestSiteFixture _fixture;
|
||||
|
||||
public FixtureLoggedTest(IISTestSiteFixture fixture)
|
||||
{
|
||||
_fixture = fixture;
|
||||
}
|
||||
|
||||
public override void Initialize(MethodInfo methodInfo, object[] testMethodArguments, ITestOutputHelper testOutputHelper)
|
||||
{
|
||||
base.Initialize(methodInfo, testMethodArguments, testOutputHelper);
|
||||
_fixture.Attach(this);
|
||||
}
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
_fixture.Detach(this);
|
||||
base.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -6,23 +6,22 @@ using System.Collections.Generic;
|
|||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Server.IntegrationTesting;
|
||||
using Microsoft.AspNetCore.Testing.xunit;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
||||
{
|
||||
[Collection(IISTestSiteCollection.Name)]
|
||||
public class SynchronousReadAndWriteTests
|
||||
public class SynchronousReadAndWriteTests: FixtureLoggedTest
|
||||
{
|
||||
private readonly IISTestSiteFixture _fixture;
|
||||
|
||||
public SynchronousReadAndWriteTests(IISTestSiteFixture fixture)
|
||||
public SynchronousReadAndWriteTests(IISTestSiteFixture fixture): base(fixture)
|
||||
{
|
||||
_fixture = fixture;
|
||||
}
|
||||
|
||||
[ConditionalFact(Skip = "See: https://github.com/aspnet/IISIntegration/issues/766")]
|
||||
[ConditionalFact]
|
||||
public async Task ReadAndWriteSynchronously()
|
||||
{
|
||||
for (int i = 0; i < 100; i++)
|
||||
|
|
|
|||
|
|
@ -53,15 +53,20 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
|||
}
|
||||
|
||||
// Defaults to inprocess specific deployment parameters
|
||||
public static DeploymentParameters GetBaseDeploymentParameters(string site = "InProcessWebSite")
|
||||
public static DeploymentParameters GetBaseDeploymentParameters(string site = null, HostingModel hostingModel = HostingModel.InProcess, bool publish = false)
|
||||
{
|
||||
if (site == null)
|
||||
{
|
||||
site = hostingModel == HostingModel.InProcess ? "InProcessWebSite" : "OutOfProcessWebSite";
|
||||
}
|
||||
|
||||
return new DeploymentParameters(Helpers.GetTestWebSitePath(site), DeployerSelector.ServerType, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64)
|
||||
{
|
||||
TargetFramework = Tfm.NetCoreApp22,
|
||||
ApplicationType = ApplicationType.Portable,
|
||||
AncmVersion = AncmVersion.AspNetCoreModuleV2,
|
||||
HostingModel = HostingModel.InProcess,
|
||||
PublishApplicationBeforeDeployment = site == "InProcessWebSite",
|
||||
HostingModel = hostingModel,
|
||||
PublishApplicationBeforeDeployment = publish,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,10 +2,12 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Net.Http;
|
||||
using System.Threading;
|
||||
using Microsoft.AspNetCore.Server.IntegrationTesting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
using Microsoft.Extensions.Logging.Testing;
|
||||
|
||||
|
|
@ -14,6 +16,7 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
|||
public class IISTestSiteFixture : IDisposable
|
||||
{
|
||||
private readonly ApplicationDeployer _deployer;
|
||||
private readonly ForwardingProvider _forwardingProvider;
|
||||
|
||||
public IISTestSiteFixture()
|
||||
{
|
||||
|
|
@ -30,14 +33,17 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
|||
PublishApplicationBeforeDeployment = true,
|
||||
};
|
||||
|
||||
_forwardingProvider = new ForwardingProvider();
|
||||
var loggerFactory = logging.CreateLoggerFactory(null, nameof(IISTestSiteFixture));
|
||||
loggerFactory.AddProvider(_forwardingProvider);
|
||||
if (deploymentParameters.ServerType == ServerType.IIS)
|
||||
{
|
||||
// Currently hosting throws if the Servertype = IIS.
|
||||
_deployer = new IISDeployer(deploymentParameters, logging.CreateLoggerFactory(null, nameof(IISTestSiteFixture)));
|
||||
_deployer = new IISDeployer(deploymentParameters, loggerFactory);
|
||||
}
|
||||
else if (deploymentParameters.ServerType == ServerType.IISExpress)
|
||||
{
|
||||
_deployer = new IISExpressDeployer(deploymentParameters, logging.CreateLoggerFactory(null, nameof(IISTestSiteFixture)));
|
||||
_deployer = new IISExpressDeployer(deploymentParameters, loggerFactory);
|
||||
}
|
||||
|
||||
DeploymentResult = _deployer.DeployAsync().Result;
|
||||
|
|
@ -60,5 +66,88 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
|||
{
|
||||
_deployer.Dispose();
|
||||
}
|
||||
|
||||
public void Attach(LoggedTest test)
|
||||
{
|
||||
if (_forwardingProvider.LoggerFactory != null)
|
||||
{
|
||||
throw new InvalidOperationException("Test instance is already attached to this fixture");
|
||||
}
|
||||
|
||||
_forwardingProvider.LoggerFactory = test.LoggerFactory;
|
||||
}
|
||||
|
||||
public void Detach(LoggedTest test)
|
||||
{
|
||||
if (_forwardingProvider.LoggerFactory != test.LoggerFactory)
|
||||
{
|
||||
throw new InvalidOperationException("Different test is attached to this fixture");
|
||||
}
|
||||
|
||||
_forwardingProvider.LoggerFactory = null;
|
||||
}
|
||||
|
||||
private class ForwardingProvider : ILoggerProvider
|
||||
{
|
||||
private readonly List<ForwardingLogger> _loggers = new List<ForwardingLogger>();
|
||||
|
||||
private ILoggerFactory _loggerFactory;
|
||||
|
||||
public ILoggerFactory LoggerFactory
|
||||
{
|
||||
get => _loggerFactory;
|
||||
set
|
||||
{
|
||||
|
||||
lock (_loggers)
|
||||
{
|
||||
_loggerFactory = value;
|
||||
foreach (var logger in _loggers)
|
||||
{
|
||||
logger.Logger = _loggerFactory?.CreateLogger("FIXTURE:" + logger.Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
lock (_loggers)
|
||||
{
|
||||
_loggers.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
public ILogger CreateLogger(string categoryName)
|
||||
{
|
||||
lock (_loggers)
|
||||
{
|
||||
var logger = new ForwardingLogger(categoryName);
|
||||
_loggers.Add(logger);
|
||||
return logger;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal class ForwardingLogger : ILogger
|
||||
{
|
||||
public ForwardingLogger(string name)
|
||||
{
|
||||
Name = name;
|
||||
}
|
||||
|
||||
public ILogger Logger { get; set; }
|
||||
public string Name { get; set; }
|
||||
|
||||
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
|
||||
{
|
||||
Logger?.Log(logLevel, eventId, state, exception, formatter);
|
||||
}
|
||||
|
||||
public bool IsEnabled(LogLevel logLevel) => Logger?.IsEnabled(logLevel) == true;
|
||||
|
||||
public IDisposable BeginScope<TState>(TState state) => Logger?.BeginScope(state);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -101,7 +101,7 @@
|
|||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<AdditionalLibraryDirectories>..\..\src\AspNetCoreModuleV2\InProcessRequestHandler\$(Configuration)\;</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;inprocessapplication.obj;inprocesshandler.obj;ahadmin.lib;Rpcrt4.lib;inprocessapplicationbase.obj;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;inprocessapplication.obj;inprocesshandler.obj;ahadmin.lib;Rpcrt4.lib;inprocessapplicationbase.obj;precomp.obj;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
<Lib>
|
||||
<AdditionalDependencies>
|
||||
|
|
@ -127,7 +127,7 @@
|
|||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<AdditionalLibraryDirectories>..\..\src\AspNetCoreModuleV2\InProcessRequestHandler\x64\$(Configuration)\;</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;inprocessapplication.obj;inprocesshandler.obj;ahadmin.lib;Rpcrt4.lib;inprocessapplicationbase.obj;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;inprocessapplication.obj;inprocesshandler.obj;ahadmin.lib;Rpcrt4.lib;inprocessapplicationbase.obj;precomp.obj;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
<Lib>
|
||||
<AdditionalDependencies>
|
||||
|
|
@ -153,7 +153,7 @@
|
|||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<AdditionalLibraryDirectories>..\..\src\AspNetCoreModuleV2\InProcessRequestHandler\$(Configuration)\;</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;inprocessapplication.obj;inprocesshandler.obj;ahadmin.lib;Rpcrt4.lib;inprocessapplicationbase.obj;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;inprocessapplication.obj;inprocesshandler.obj;ahadmin.lib;Rpcrt4.lib;inprocessapplicationbase.obj;precomp.obj;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
<Lib>
|
||||
<AdditionalDependencies>
|
||||
|
|
@ -179,7 +179,7 @@
|
|||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<AdditionalLibraryDirectories>..\..\src\AspNetCoreModuleV2\InProcessRequestHandler\x64\$(Configuration)\;</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;inprocessapplication.obj;inprocesshandler.obj;ahadmin.lib;Rpcrt4.lib;inprocessapplicationbase.obj;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;inprocessapplication.obj;inprocesshandler.obj;ahadmin.lib;Rpcrt4.lib;inprocessapplicationbase.obj;precomp.obj;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
<Lib>
|
||||
<AdditionalDependencies>
|
||||
|
|
|
|||
|
|
@ -41,7 +41,6 @@ public:
|
|||
class MockElement : public IAppHostElement
|
||||
{
|
||||
public:
|
||||
|
||||
MOCK_METHOD2_WITH_CALLTYPE(__stdcall, QueryInterface, HRESULT(REFIID riid, void ** ppvObject));
|
||||
MOCK_METHOD0_WITH_CALLTYPE(__stdcall, AddRef, ULONG());
|
||||
MOCK_METHOD0_WITH_CALLTYPE(__stdcall, Release, ULONG());
|
||||
|
|
@ -167,6 +166,16 @@ class MockHttpServer : public IHttpServer
|
|||
}
|
||||
};
|
||||
|
||||
|
||||
class MockHttpApplication: public IHttpApplication
|
||||
{
|
||||
public:
|
||||
MOCK_CONST_METHOD0(GetApplicationPhysicalPath, PCWSTR ());
|
||||
MOCK_CONST_METHOD0(GetApplicationId, PCWSTR ());
|
||||
MOCK_CONST_METHOD0(GetAppConfigPath, PCWSTR ());
|
||||
MOCK_METHOD0(GetModuleContextContainer, IHttpModuleContextContainer* ());
|
||||
};
|
||||
|
||||
class MockRequestHandlerConfig : public REQUESTHANDLER_CONFIG
|
||||
{
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -7,6 +7,9 @@
|
|||
#include "inprocessapplication.h"
|
||||
#include "fakeclasses.h"
|
||||
|
||||
using ::testing::_;
|
||||
using ::testing::NiceMock;
|
||||
|
||||
// Externals defined in inprocess
|
||||
BOOL g_fProcessDetach;
|
||||
HANDLE g_hEventLog;
|
||||
|
|
@ -15,16 +18,22 @@ namespace InprocessTests
|
|||
{
|
||||
TEST(InProcessTest, NoNullRefForExePath)
|
||||
{
|
||||
auto server = new MockHttpServer();
|
||||
auto requestHandlerConfig = MockRequestHandlerConfig::CreateConfig();
|
||||
auto config = std::unique_ptr<REQUESTHANDLER_CONFIG>(requestHandlerConfig);
|
||||
MockHttpServer server;
|
||||
NiceMock<MockHttpApplication> application;
|
||||
|
||||
ON_CALL(application, GetApplicationPhysicalPath())
|
||||
.WillByDefault(testing::Return(L"Some path"));
|
||||
|
||||
auto requestHandlerConfig = std::unique_ptr<REQUESTHANDLER_CONFIG>(MockRequestHandlerConfig::CreateConfig());
|
||||
|
||||
std::wstring exePath(L"hello");
|
||||
std::array<APPLICATION_PARAMETER, 1> parameters {
|
||||
|
||||
std::array<APPLICATION_PARAMETER, 1> parameters{
|
||||
{"InProcessExeLocation", exePath.data()}
|
||||
};
|
||||
|
||||
IN_PROCESS_APPLICATION *app = new IN_PROCESS_APPLICATION(server, std::move(config), parameters.data(), 1);
|
||||
IN_PROCESS_APPLICATION *app = new IN_PROCESS_APPLICATION(server, application, std::move(requestHandlerConfig), parameters.data(), 1);
|
||||
|
||||
ASSERT_STREQ(app->QueryExeLocation(), L"hello");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,21 +19,25 @@ namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests.Inprocess
|
|||
public class AppOfflineTests : IISFunctionalTestBase
|
||||
{
|
||||
// TODO these will differ between IIS and IISExpress
|
||||
[ConditionalFact]
|
||||
public async Task AppOfflineDroppedWhileSiteIsDown_SiteReturns503()
|
||||
[ConditionalTheory]
|
||||
[InlineData(HostingModel.InProcess)]
|
||||
[InlineData(HostingModel.OutOfProcess)]
|
||||
public async Task AppOfflineDroppedWhileSiteIsDown_SiteReturns503(HostingModel hostingModel)
|
||||
{
|
||||
var deploymentResult = await DeployApp();
|
||||
var deploymentResult = await DeployApp(hostingModel);
|
||||
|
||||
AddAppOffline(deploymentResult.DeploymentResult.ContentRoot);
|
||||
|
||||
await AssertAppOffline(deploymentResult);
|
||||
}
|
||||
|
||||
[ConditionalFact]
|
||||
public async Task AppOfflineDroppedWhileSiteIsDown_CustomResponse()
|
||||
[ConditionalTheory]
|
||||
[InlineData(HostingModel.InProcess)]
|
||||
[InlineData(HostingModel.OutOfProcess)]
|
||||
public async Task AppOfflineDroppedWhileSiteIsDown_CustomResponse(HostingModel hostingModel)
|
||||
{
|
||||
var expectedResponse = "The app is offline.";
|
||||
var deploymentResult = await DeployApp();
|
||||
var deploymentResult = await DeployApp(hostingModel);
|
||||
|
||||
AddAppOffline(deploymentResult.DeploymentResult.ContentRoot, expectedResponse);
|
||||
|
||||
|
|
@ -41,9 +45,9 @@ namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests.Inprocess
|
|||
}
|
||||
|
||||
[ConditionalFact]
|
||||
public async Task AppOfflineDroppedWhileSiteRunning_SiteShutsDown()
|
||||
public async Task AppOfflineDroppedWhileSiteRunning_SiteShutsDown_InProcess()
|
||||
{
|
||||
var deploymentResult = await AssertStarts();
|
||||
var deploymentResult = await AssertStarts(HostingModel.InProcess);
|
||||
|
||||
AddAppOffline(deploymentResult.DeploymentResult.ContentRoot);
|
||||
|
||||
|
|
@ -51,9 +55,26 @@ namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests.Inprocess
|
|||
}
|
||||
|
||||
[ConditionalFact]
|
||||
public async Task AppOfflineDropped_CanRemoveAppOfflineAfterAddingAndSiteWorks()
|
||||
public async Task AppOfflineDroppedWhileSiteRunning_SiteShutsDown_OutOfProcess()
|
||||
{
|
||||
var deploymentResult = await DeployApp();
|
||||
var deploymentResult = await AssertStarts(HostingModel.OutOfProcess);
|
||||
|
||||
// Repeat dropping file and restarting multiple times
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
AddAppOffline(deploymentResult.DeploymentResult.ContentRoot);
|
||||
await AssertAppOffline(deploymentResult);
|
||||
RemoveAppOffline(deploymentResult.DeploymentResult.ContentRoot);
|
||||
await AssertRunning(deploymentResult);
|
||||
}
|
||||
}
|
||||
|
||||
[ConditionalTheory]
|
||||
[InlineData(HostingModel.InProcess)]
|
||||
[InlineData(HostingModel.OutOfProcess)]
|
||||
public async Task AppOfflineDropped_CanRemoveAppOfflineAfterAddingAndSiteWorks(HostingModel hostingModel)
|
||||
{
|
||||
var deploymentResult = await DeployApp(hostingModel);
|
||||
|
||||
AddAppOffline(deploymentResult.DeploymentResult.ContentRoot);
|
||||
|
||||
|
|
@ -61,13 +82,12 @@ namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests.Inprocess
|
|||
|
||||
RemoveAppOffline(deploymentResult.DeploymentResult.ContentRoot);
|
||||
|
||||
var response = await deploymentResult.HttpClient.GetAsync("HelloWorld");
|
||||
|
||||
await AssertRunning(deploymentResult);
|
||||
}
|
||||
|
||||
private async Task<IISDeploymentResult> DeployApp()
|
||||
private async Task<IISDeploymentResult> DeployApp(HostingModel hostingModel = HostingModel.InProcess)
|
||||
{
|
||||
var deploymentParameters = Helpers.GetBaseDeploymentParameters();
|
||||
var deploymentParameters = Helpers.GetBaseDeploymentParameters(hostingModel: hostingModel, publish: true);
|
||||
|
||||
return await DeployAsync(deploymentParameters);
|
||||
}
|
||||
|
|
@ -118,18 +138,21 @@ namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests.Inprocess
|
|||
Assert.True(hostShutdownToken.IsCancellationRequested);
|
||||
}
|
||||
|
||||
private async Task<IISDeploymentResult> AssertStarts()
|
||||
private async Task<IISDeploymentResult> AssertStarts(HostingModel hostingModel)
|
||||
{
|
||||
var deploymentParameters = Helpers.GetBaseDeploymentParameters();
|
||||
var deploymentResult = await DeployApp(hostingModel);
|
||||
|
||||
var deploymentResult = await DeployAsync(deploymentParameters);
|
||||
await AssertRunning(deploymentResult);
|
||||
|
||||
return deploymentResult;
|
||||
}
|
||||
|
||||
private static async Task AssertRunning(IISDeploymentResult deploymentResult)
|
||||
{
|
||||
var response = await deploymentResult.RetryingHttpClient.GetAsync("HelloWorld");
|
||||
|
||||
var responseText = await response.Content.ReadAsStringAsync();
|
||||
Assert.Equal("Hello World", responseText);
|
||||
|
||||
return deploymentResult;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
|||
[ConditionalFact]
|
||||
public async Task Authentication_InProcess()
|
||||
{
|
||||
var deploymentParameters = Helpers.GetBaseDeploymentParameters();
|
||||
var deploymentParameters = Helpers.GetBaseDeploymentParameters(publish: true);
|
||||
deploymentParameters.ServerConfigTemplateContent = GetWindowsAuthConfig();
|
||||
|
||||
var deploymentResult = await DeployAsync(deploymentParameters);
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
|||
var tempFile = Path.GetTempFileName();
|
||||
try
|
||||
{
|
||||
var deploymentParameters = Helpers.GetBaseDeploymentParameters();
|
||||
var deploymentParameters = Helpers.GetBaseDeploymentParameters(publish: true);
|
||||
deploymentParameters.EnvironmentVariables["ASPNETCORE_MODULE_DEBUG_FILE"] = tempFile;
|
||||
|
||||
var deploymentResult = await DeployAsync(deploymentParameters);
|
||||
|
|
@ -82,7 +82,7 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
|||
StopServer();
|
||||
|
||||
var logContents = File.ReadAllText(tempFile);
|
||||
Assert.Contains("[aspnetcore.dll]", logContents);
|
||||
Assert.Contains("[aspnetcorev2.dll]", logContents);
|
||||
Assert.Contains("[aspnetcorev2_inprocess.dll]", logContents);
|
||||
}
|
||||
finally
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
|||
[ConditionalFact]
|
||||
public async Task ServerShutsDownWhenMainExits()
|
||||
{
|
||||
var parameters = Helpers.GetBaseDeploymentParameters();
|
||||
var parameters = Helpers.GetBaseDeploymentParameters(publish: true);
|
||||
var result = await DeployAsync(parameters);
|
||||
|
||||
var response = await result.RetryingHttpClient.GetAsync("/Shutdown");
|
||||
|
|
|
|||
Loading…
Reference in New Issue