diff --git a/build/testsite.props b/build/testsite.props
index 42e3cb1d8e..ab74d58d72 100644
--- a/build/testsite.props
+++ b/build/testsite.props
@@ -40,7 +40,7 @@
- /config:"$(IISExpressAppHostConfig)"
+ /config:"$(IISExpressAppHostConfig)" /systray:false
-h "$(IISAppHostConfig)"
$(NativePlatform)\aspnetcore.dll
diff --git a/src/AspNetCoreModuleV2/AspNetCore/AspNetCore.vcxproj b/src/AspNetCoreModuleV2/AspNetCore/AspNetCore.vcxproj
index db4a1edf2d..1a80711d26 100644
--- a/src/AspNetCoreModuleV2/AspNetCore/AspNetCore.vcxproj
+++ b/src/AspNetCoreModuleV2/AspNetCore/AspNetCore.vcxproj
@@ -226,11 +226,9 @@
-
-
@@ -239,7 +237,6 @@
-
Create
diff --git a/src/AspNetCoreModuleV2/AspNetCore/Inc/applicationinfo.h b/src/AspNetCoreModuleV2/AspNetCore/Inc/applicationinfo.h
index f6f5890b8e..3d4b901755 100644
--- a/src/AspNetCoreModuleV2/AspNetCore/Inc/applicationinfo.h
+++ b/src/AspNetCoreModuleV2/AspNetCore/Inc/applicationinfo.h
@@ -3,17 +3,12 @@
#pragma once
-#include
-
#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
+ 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;
diff --git a/src/AspNetCoreModuleV2/AspNetCore/Inc/applicationmanager.h b/src/AspNetCoreModuleV2/AspNetCore/Inc/applicationmanager.h
index dac98163f5..5245af06d5 100644
--- a/src/AspNetCoreModuleV2/AspNetCore/Inc/applicationmanager.h
+++ b/src/AspNetCoreModuleV2/AspNetCore/Inc/applicationmanager.h
@@ -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;
diff --git a/src/AspNetCoreModuleV2/AspNetCore/Inc/appoffline.h b/src/AspNetCoreModuleV2/AspNetCore/Inc/appoffline.h
deleted file mode 100644
index 0f985ca64d..0000000000
--- a/src/AspNetCoreModuleV2/AspNetCore/Inc/appoffline.h
+++ /dev/null
@@ -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;
-};
diff --git a/src/AspNetCoreModuleV2/AspNetCore/Inc/precomp.hxx b/src/AspNetCoreModuleV2/AspNetCore/Inc/precomp.hxx
index b0ee0b7e32..1191022c01 100644
--- a/src/AspNetCoreModuleV2/AspNetCore/Inc/precomp.hxx
+++ b/src/AspNetCoreModuleV2/AspNetCore/Inc/precomp.hxx
@@ -16,8 +16,9 @@
#include
#include
#include
+#include
#include "stringu.h"
-#include "stringu.h"
+#include "stringa.h"
extern PVOID g_pModuleId;
extern BOOL g_fAspnetcoreRHAssemblyLoaded;
diff --git a/src/AspNetCoreModuleV2/AspNetCore/Inc/proxymodule.h b/src/AspNetCoreModuleV2/AspNetCore/Inc/proxymodule.h
index a0580b39b1..5864dd0c6f 100644
--- a/src/AspNetCoreModuleV2/AspNetCore/Inc/proxymodule.h
+++ b/src/AspNetCoreModuleV2/AspNetCore/Inc/proxymodule.h
@@ -3,6 +3,7 @@
#pragma once
+#include
#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 m_pHandler;
};
class ASPNET_CORE_PROXY_MODULE_FACTORY : public IHttpModuleFactory
diff --git a/src/AspNetCoreModuleV2/AspNetCore/aspnetcoremodule.rc b/src/AspNetCoreModuleV2/AspNetCore/aspnetcoremodule.rc
index 39edfaffc4..f9acf89035 100644
--- a/src/AspNetCoreModuleV2/AspNetCore/aspnetcoremodule.rc
+++ b/src/AspNetCoreModuleV2/AspNetCore/aspnetcoremodule.rc
@@ -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
/////////////////////////////////////////////////////////////////////////////
//
diff --git a/src/AspNetCoreModuleV2/AspNetCore/src/applicationinfo.cpp b/src/AspNetCoreModuleV2/AspNetCore/src/applicationinfo.cpp
index 99251ddc4a..2072e33af6 100644
--- a/src/AspNetCoreModuleV2/AspNetCore/src/applicationinfo.cpp
+++ b/src/AspNetCoreModuleV2/AspNetCore/src/applicationinfo.cpp
@@ -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 parameters {
+ {"InProcessExeLocation", struExeLocation.QueryStr()}
+ };
+ LOG_INFO("Creating handler application");
+ FINISHED_IF_FAILED(m_pfnAspNetCoreCreateApplication(
+ m_pServer,
+ pHttpContext->GetApplication(),
+ parameters.data(),
+ static_cast(parameters.size()),
+ &pApplication));
- m_fDoneAppCreation = TRUE;
- FINISHED_IF_FAILED(FindRequestHandlerAssembly(struExeLocation));
-
- if (m_pfnAspNetCoreCreateApplication == NULL)
- {
- FINISHED(HRESULT_FROM_WIN32(ERROR_INVALID_FUNCTION));
- }
-
- std::array parameters {
- {"InProcessExeLocation", struExeLocation.QueryStr()}
- };
-
- FINISHED_IF_FAILED(m_pfnAspNetCoreCreateApplication(
- m_pServer,
- pHttpContext->GetApplication(),
- parameters.data(),
- static_cast(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()));
diff --git a/src/AspNetCoreModuleV2/AspNetCore/src/applicationmanager.cxx b/src/AspNetCoreModuleV2/AspNetCore/src/applicationmanager.cxx
index e492b53f04..71fb2e464f 100644
--- a/src/AspNetCoreModuleV2/AspNetCore/src/applicationmanager.cxx
+++ b/src/AspNetCoreModuleV2/AspNetCore/src/applicationmanager.cxx
@@ -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
diff --git a/src/AspNetCoreModuleV2/AspNetCore/src/dllmain.cpp b/src/AspNetCoreModuleV2/AspNetCore/src/dllmain.cpp
index 34d96e45d3..03196a316d 100644
--- a/src/AspNetCoreModuleV2/AspNetCore/src/dllmain.cpp
+++ b/src/AspNetCoreModuleV2/AspNetCore/src/dllmain.cpp
@@ -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)
diff --git a/src/AspNetCoreModuleV2/AspNetCore/src/proxymodule.cxx b/src/AspNetCoreModuleV2/AspNetCore/src/proxymodule.cxx
index 6987863616..f27a1571c3 100644
--- a/src/AspNetCoreModuleV2/AspNetCore/src/proxymodule.cxx
+++ b/src/AspNetCoreModuleV2/AspNetCore/src/proxymodule.cxx
@@ -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;
}
diff --git a/src/AspNetCoreModuleV2/CommonLib/CommonLib.vcxproj b/src/AspNetCoreModuleV2/CommonLib/CommonLib.vcxproj
index bb34327e27..efeb7f1ddc 100644
--- a/src/AspNetCoreModuleV2/CommonLib/CommonLib.vcxproj
+++ b/src/AspNetCoreModuleV2/CommonLib/CommonLib.vcxproj
@@ -205,6 +205,7 @@
+
@@ -221,6 +222,7 @@
+
diff --git a/src/AspNetCoreModuleV2/CommonLib/PollingAppOfflineApplication.cpp b/src/AspNetCoreModuleV2/CommonLib/PollingAppOfflineApplication.cpp
new file mode 100644
index 0000000000..3b07cf8645
--- /dev/null
+++ b/src/AspNetCoreModuleV2/CommonLib/PollingAppOfflineApplication.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
+#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 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(strlen("text/html")),
+ FALSE
+ );
+
+ DataChunk.DataChunkType = HttpDataChunkFromMemory;
+ DataChunk.FromMemory.pBuffer = m_strAppOfflineContent.data();
+ DataChunk.FromMemory.BufferLength = static_cast(m_strAppOfflineContent.size());
+ pResponse->WriteEntityChunkByReference(&DataChunk);
+
+ return REQUEST_NOTIFICATION_STATUS::RQ_NOTIFICATION_FINISH_REQUEST;
+}
diff --git a/src/AspNetCoreModuleV2/CommonLib/PollingAppOfflineApplication.h b/src/AspNetCoreModuleV2/CommonLib/PollingAppOfflineApplication.h
new file mode 100644
index 0000000000..e66f5f46c8
--- /dev/null
+++ b/src/AspNetCoreModuleV2/CommonLib/PollingAppOfflineApplication.h
@@ -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
+#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;
+};
+
+
diff --git a/src/AspNetCoreModuleV2/CommonLib/application.h b/src/AspNetCoreModuleV2/CommonLib/application.h
index 0c0752f0c4..56cf5ce2ac 100644
--- a/src/AspNetCoreModuleV2/CommonLib/application.h
+++ b/src/AspNetCoreModuleV2/CommonLib/application.h
@@ -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;
};
diff --git a/src/AspNetCoreModuleV2/CommonLib/aspnetcore_msg.mc b/src/AspNetCoreModuleV2/CommonLib/aspnetcore_msg.mc
index 5ea3c030d2..13781f7c82 100644
--- a/src/AspNetCoreModuleV2/CommonLib/aspnetcore_msg.mc
+++ b/src/AspNetCoreModuleV2/CommonLib/aspnetcore_msg.mc
@@ -171,7 +171,7 @@ Language=English
.
Messageid=1024
-SymbolicName=ASPNETCORE_EVENT_RECYCLE_APPOFFLINE_REMOVED
+SymbolicName=ASPNETCORE_EVENT_MONITOR_APPOFFLINE_ERROR
Language=English
%1
.
diff --git a/src/AspNetCoreModuleV2/CommonLib/debugutil.cpp b/src/AspNetCoreModuleV2/CommonLib/debugutil.cpp
index 189a5097f9..cd8ca3ea05 100644
--- a/src/AspNetCoreModuleV2/CommonLib/debugutil.cpp
+++ b/src/AspNetCoreModuleV2/CommonLib/debugutil.cpp
@@ -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)
diff --git a/src/AspNetCoreModuleV2/CommonLib/hostfxr_utility.cpp b/src/AspNetCoreModuleV2/CommonLib/hostfxr_utility.cpp
index cf703d34a0..fd3a65abf8 100644
--- a/src/AspNetCoreModuleV2/CommonLib/hostfxr_utility.cpp
+++ b/src/AspNetCoreModuleV2/CommonLib/hostfxr_utility.cpp
@@ -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;
}
diff --git a/src/AspNetCoreModuleV2/CommonLib/iapplication.h b/src/AspNetCoreModuleV2/CommonLib/iapplication.h
index dcec7a5e3e..ef5d2bf8d7 100644
--- a/src/AspNetCoreModuleV2/CommonLib/iapplication.h
+++ b/src/AspNetCoreModuleV2/CommonLib/iapplication.h
@@ -3,6 +3,7 @@
#pragma once
+#include
#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 ReferenceApplication(APPLICATION* application)
+{
+ application->ReferenceApplication();
+ return std::unique_ptr(application);
+};
diff --git a/src/AspNetCoreModuleV2/CommonLib/irequesthandler.h b/src/AspNetCoreModuleV2/CommonLib/irequesthandler.h
index b2be7ee401..5f9b415794 100644
--- a/src/AspNetCoreModuleV2/CommonLib/irequesthandler.h
+++ b/src/AspNetCoreModuleV2/CommonLib/irequesthandler.h
@@ -4,6 +4,7 @@
#pragma once
#include
+#include
//
// Pure abstract class
@@ -46,3 +47,12 @@ public:
VOID
) = 0;
};
+
+
+struct IREQUEST_HANDLER_DELETER
+{
+ void operator ()(IREQUEST_HANDLER* application) const
+ {
+ application->DereferenceRequestHandler();
+ }
+};
diff --git a/src/AspNetCoreModuleV2/CommonLib/requesthandler.h b/src/AspNetCoreModuleV2/CommonLib/requesthandler.h
index 4553ee5c87..ea4692f506 100644
--- a/src/AspNetCoreModuleV2/CommonLib/requesthandler.h
+++ b/src/AspNetCoreModuleV2/CommonLib/requesthandler.h
@@ -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;
};
diff --git a/src/AspNetCoreModuleV2/CommonLib/resources.h b/src/AspNetCoreModuleV2/CommonLib/resources.h
index 153af6d3d0..4620fa7e17 100644
--- a/src/AspNetCoreModuleV2/CommonLib/resources.h
+++ b/src/AspNetCoreModuleV2/CommonLib/resources.h
@@ -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"
diff --git a/src/AspNetCoreModuleV2/IISLib/ntassert.h b/src/AspNetCoreModuleV2/IISLib/ntassert.h
index 6d2f3b9a30..8e19e03239 100644
--- a/src/AspNetCoreModuleV2/IISLib/ntassert.h
+++ b/src/AspNetCoreModuleV2/IISLib/ntassert.h
@@ -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 ) ) )
diff --git a/src/AspNetCoreModuleV2/InProcessRequestHandler/InProcessApplicationBase.cpp b/src/AspNetCoreModuleV2/InProcessRequestHandler/InProcessApplicationBase.cpp
index 2f3986a0f5..5848f37a2f 100644
--- a/src/AspNetCoreModuleV2/InProcessRequestHandler/InProcessApplicationBase.cpp
+++ b/src/AspNetCoreModuleV2/InProcessRequestHandler/InProcessApplicationBase.cpp
@@ -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);
diff --git a/src/AspNetCoreModuleV2/InProcessRequestHandler/InProcessApplicationBase.h b/src/AspNetCoreModuleV2/InProcessRequestHandler/InProcessApplicationBase.h
index defcf3bdf8..ca907d67c6 100644
--- a/src/AspNetCoreModuleV2/InProcessRequestHandler/InProcessApplicationBase.h
+++ b/src/AspNetCoreModuleV2/InProcessRequestHandler/InProcessApplicationBase.h
@@ -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;
diff --git a/src/AspNetCoreModuleV2/InProcessRequestHandler/InProcessRequestHandler.vcxproj b/src/AspNetCoreModuleV2/InProcessRequestHandler/InProcessRequestHandler.vcxproj
index 907726e2b2..c96aaa7000 100644
--- a/src/AspNetCoreModuleV2/InProcessRequestHandler/InProcessRequestHandler.vcxproj
+++ b/src/AspNetCoreModuleV2/InProcessRequestHandler/InProcessRequestHandler.vcxproj
@@ -83,7 +83,7 @@
- NotUsing
+ Use
Level4
Disabled
WIN32;_DEBUG;REQUESTHANDLER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
@@ -104,17 +104,20 @@
CompileAsCpp
true
stdcpp17
+ precomp.hxx
+ true
Windows
true
kernel32.lib;user32.lib;advapi32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;ahadmin.lib;rpcrt4.lib;winhttp.lib;pdh.lib;ws2_32.lib;wbemuuid.lib;iphlpapi.lib;%(AdditionalDependencies)
Source.def
+ UseLinkTimeCodeGeneration
- NotUsing
+ Use
Level4
Disabled
WIN32;_DEBUG;REQUESTHANDLER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
@@ -135,18 +138,21 @@
CompileAsCpp
true
stdcpp17
+ precomp.hxx
+ true
Windows
true
kernel32.lib;user32.lib;advapi32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;ahadmin.lib;rpcrt4.lib;winhttp.lib;pdh.lib;ws2_32.lib;wbemuuid.lib;iphlpapi.lib;%(AdditionalDependencies)
Source.def
+ UseLinkTimeCodeGeneration
Level4
- NotUsing
+ Use
MaxSpeed
true
true
@@ -166,6 +172,8 @@
CompileAsCpp
true
stdcpp17
+ precomp.hxx
+ true
Windows
@@ -174,12 +182,13 @@
true
Source.def
kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;ahadmin.lib;winhttp.lib;odbc32.lib;ws2_32.lib;odbccp32.lib;wbemuuid.lib;iphlpapi.lib;pdh.lib;rpcrt4.lib;%(AdditionalDependencies)
+ UseLinkTimeCodeGeneration
Level4
- NotUsing
+ Use
MaxSpeed
true
true
@@ -199,6 +208,8 @@
CompileAsCpp
true
stdcpp17
+ precomp.hxx
+ true
Windows
@@ -207,6 +218,7 @@
true
Source.def
kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;ahadmin.lib;rpcrt4.lib;winhttp.lib;pdh.lib;ws2_32.lib;wbemuuid.lib;iphlpapi.lib;%(AdditionalDependencies)
+ UseLinkTimeCodeGeneration
@@ -224,6 +236,12 @@
+
+ Create
+ Create
+ Create
+ Create
+
diff --git a/src/AspNetCoreModuleV2/InProcessRequestHandler/StartupExceptionApplication.cpp b/src/AspNetCoreModuleV2/InProcessRequestHandler/StartupExceptionApplication.cpp
index 10d6ddb4af..4aa5b9fb31 100644
--- a/src/AspNetCoreModuleV2/InProcessRequestHandler/StartupExceptionApplication.cpp
+++ b/src/AspNetCoreModuleV2/InProcessRequestHandler/StartupExceptionApplication.cpp
@@ -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;
}
diff --git a/src/AspNetCoreModuleV2/InProcessRequestHandler/StartupExceptionApplication.h b/src/AspNetCoreModuleV2/InProcessRequestHandler/StartupExceptionApplication.h
index 52658c8cda..0a2dc4fe58 100644
--- a/src/AspNetCoreModuleV2/InProcessRequestHandler/StartupExceptionApplication.h
+++ b/src/AspNetCoreModuleV2/InProcessRequestHandler/StartupExceptionApplication.h
@@ -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(" \
+ \
+
\
+ \
+ IIS 500.30 Error \
+ \
+
HTTP Error 500.30 - ANCM In-Process Start Failure
\
+
\
+
\
+
\
+
\
+
\
+
\
+
\
+
");
}
~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(" \
- \
- \
- \
- IIS 500.30 Error \
- \
-
HTTP Error 500.30 - ANCM In-Process Start Failure
\
-
\
-
\
-
\
-
\
-
\
-
\
-
\
-
");
- }
- }
-
return html500Page;
}
private:
std::string html500Page;
- SRWLOCK m_srwLock;
BOOL m_disableLogs;
- IHttpServer* m_pHttpServer;
};
diff --git a/src/AspNetCoreModuleV2/InProcessRequestHandler/StartupExceptionHandler.cpp b/src/AspNetCoreModuleV2/InProcessRequestHandler/StartupExceptionHandler.cpp
index b0817a4659..f8041a0f13 100644
--- a/src/AspNetCoreModuleV2/InProcessRequestHandler/StartupExceptionHandler.cpp
+++ b/src/AspNetCoreModuleV2/InProcessRequestHandler/StartupExceptionHandler.cpp
@@ -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();
-}
diff --git a/src/AspNetCoreModuleV2/InProcessRequestHandler/StartupExceptionHandler.h b/src/AspNetCoreModuleV2/InProcessRequestHandler/StartupExceptionHandler.h
index 859f3a73f5..9b5a9ba45d 100644
--- a/src/AspNetCoreModuleV2/InProcessRequestHandler/StartupExceptionHandler.h
+++ b/src/AspNetCoreModuleV2/InProcessRequestHandler/StartupExceptionHandler.h
@@ -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;
diff --git a/src/AspNetCoreModuleV2/InProcessRequestHandler/dllmain.cxx b/src/AspNetCoreModuleV2/InProcessRequestHandler/dllmain.cxx
index 20314d34a4..e1bc9ac143 100644
--- a/src/AspNetCoreModuleV2/InProcessRequestHandler/dllmain.cxx
+++ b/src/AspNetCoreModuleV2/InProcessRequestHandler/dllmain.cxx
@@ -3,8 +3,6 @@
// dllmain.cpp : Defines the entry point for the DLL application.
-#include "precomp.hxx"
-#include
#include
#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 pRequestHandlerConfig(pConfig);
+
+ BOOL disableStartupPage = pConfig->QueryDisableStartUpErrorPage();
- auto config = std::unique_ptr(pConfig);
-
- const bool disableStartupPage = pConfig->QueryDisableStartUpErrorPage();
-
- auto pApplication = std::make_unique(pServer, std::move(config), pParameters, nParameters);
-
+ auto pApplication = std::make_unique(*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(*pServer, *pHttpApplication, disableStartupPage);
+
+ RETURN_IF_FAILED(pErrorApplication->StartMonitoringAppOffline());
+ *ppApplication = pErrorApplication.release();
}
else
{
+ RETURN_IF_FAILED(pApplication->StartMonitoringAppOffline());
*ppApplication = pApplication.release();
}
}
diff --git a/src/AspNetCoreModuleV2/InProcessRequestHandler/inprocessapplication.cpp b/src/AspNetCoreModuleV2/InProcessRequestHandler/inprocessapplication.cpp
index a1cf301054..ad0f6a35a6 100644
--- a/src/AspNetCoreModuleV2/InProcessRequestHandler/inprocessapplication.cpp
+++ b/src/AspNetCoreModuleV2/InProcessRequestHandler/inprocessapplication.cpp
@@ -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 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)
{
diff --git a/src/AspNetCoreModuleV2/InProcessRequestHandler/inprocessapplication.h b/src/AspNetCoreModuleV2/InProcessRequestHandler/inprocessapplication.h
index 034c36fc93..1f6e3da570 100644
--- a/src/AspNetCoreModuleV2/InProcessRequestHandler/inprocessapplication.h
+++ b/src/AspNetCoreModuleV2/InProcessRequestHandler/inprocessapplication.h
@@ -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 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 m_pConfig;
static IN_PROCESS_APPLICATION* s_Application;
IOutputManager* m_pLoggerProvider;
- std::unique_ptr m_pConfig;
static const LPCSTR s_exeLocationParameterName;
diff --git a/src/AspNetCoreModuleV2/InProcessRequestHandler/inprocesshandler.cpp b/src/AspNetCoreModuleV2/InProcessRequestHandler/inprocesshandler.cpp
index 5daf8d3604..de806e7f71 100644
--- a/src/AspNetCoreModuleV2/InProcessRequestHandler/inprocesshandler.cpp
+++ b/src/AspNetCoreModuleV2/InProcessRequestHandler/inprocesshandler.cpp
@@ -9,17 +9,20 @@
ALLOC_CACHE_HANDLER * IN_PROCESS_HANDLER::sm_pAlloc = NULL;
IN_PROCESS_HANDLER::IN_PROCESS_HANDLER(
+ _In_ std::unique_ptr 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))
diff --git a/src/AspNetCoreModuleV2/InProcessRequestHandler/inprocesshandler.h b/src/AspNetCoreModuleV2/InProcessRequestHandler/inprocesshandler.h
index 24a29b737f..fe0331da9b 100644
--- a/src/AspNetCoreModuleV2/InProcessRequestHandler/inprocesshandler.h
+++ b/src/AspNetCoreModuleV2/InProcessRequestHandler/inprocesshandler.h
@@ -3,8 +3,10 @@
#pragma once
-#include "precomp.hxx"
#include "requesthandler.h"
+#include
+#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 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 m_pApplication;
+ PFN_REQUEST_HANDLER m_pRequestHandler;
+ void* m_pRequestHandlerContext;
+ PFN_ASYNC_COMPLETION_HANDLER m_pAsyncCompletionHandler;
+
static ALLOC_CACHE_HANDLER * sm_pAlloc;
};
diff --git a/src/AspNetCoreModuleV2/InProcessRequestHandler/managedexports.cxx b/src/AspNetCoreModuleV2/InProcessRequestHandler/managedexports.cxx
index c4860c1acb..38c4cb6503 100644
--- a/src/AspNetCoreModuleV2/InProcessRequestHandler/managedexports.cxx
+++ b/src/AspNetCoreModuleV2/InProcessRequestHandler/managedexports.cxx
@@ -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);
diff --git a/src/AspNetCoreModuleV2/InProcessRequestHandler/precomp.cpp b/src/AspNetCoreModuleV2/InProcessRequestHandler/precomp.cpp
new file mode 100644
index 0000000000..12fcb1d436
--- /dev/null
+++ b/src/AspNetCoreModuleV2/InProcessRequestHandler/precomp.cpp
@@ -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
diff --git a/src/AspNetCoreModuleV2/OutOfProcessRequestHandler/OutOfProcessRequestHandler.vcxproj b/src/AspNetCoreModuleV2/OutOfProcessRequestHandler/OutOfProcessRequestHandler.vcxproj
index 3778b906c6..41f2612683 100644
--- a/src/AspNetCoreModuleV2/OutOfProcessRequestHandler/OutOfProcessRequestHandler.vcxproj
+++ b/src/AspNetCoreModuleV2/OutOfProcessRequestHandler/OutOfProcessRequestHandler.vcxproj
@@ -111,6 +111,7 @@
true
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)
Source.def
+ UseLinkTimeCodeGeneration
@@ -143,6 +144,7 @@
true
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)
Source.def
+ UseLinkTimeCodeGeneration
@@ -177,6 +179,7 @@
true
Source.def
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)
+ UseLinkTimeCodeGeneration
@@ -211,6 +214,7 @@
true
Source.def
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)
+ UseLinkTimeCodeGeneration
diff --git a/src/AspNetCoreModuleV2/OutOfProcessRequestHandler/dllmain.cxx b/src/AspNetCoreModuleV2/OutOfProcessRequestHandler/dllmain.cxx
index c74f3cacaa..e2d5c1ec3c 100644
--- a/src/AspNetCoreModuleV2/OutOfProcessRequestHandler/dllmain.cxx
+++ b/src/AspNetCoreModuleV2/OutOfProcessRequestHandler/dllmain.cxx
@@ -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 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 pApplication = std::make_unique(*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;
}
diff --git a/src/AspNetCoreModuleV2/OutOfProcessRequestHandler/outofprocess/outprocessapplication.cpp b/src/AspNetCoreModuleV2/OutOfProcessRequestHandler/outofprocess/outprocessapplication.cpp
index 0457b4d552..ce29fd4745 100644
--- a/src/AspNetCoreModuleV2/OutOfProcessRequestHandler/outofprocess/outprocessapplication.cpp
+++ b/src/AspNetCoreModuleV2/OutOfProcessRequestHandler/outofprocess/outprocessapplication.cpp
@@ -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 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
diff --git a/src/AspNetCoreModuleV2/OutOfProcessRequestHandler/outofprocess/outprocessapplication.h b/src/AspNetCoreModuleV2/OutOfProcessRequestHandler/outofprocess/outprocessapplication.h
index 9601178e63..8f51bf4216 100644
--- a/src/AspNetCoreModuleV2/OutOfProcessRequestHandler/outofprocess/outprocessapplication.h
+++ b/src/AspNetCoreModuleV2/OutOfProcessRequestHandler/outofprocess/outprocessapplication.h
@@ -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 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 m_pConfig;
};
diff --git a/src/AspNetCoreModuleV2/OutOfProcessRequestHandler/outofprocess/processmanager.cxx b/src/AspNetCoreModuleV2/OutOfProcessRequestHandler/outofprocess/processmanager.cxx
index 7c75d65a0d..85160dc55b 100644
--- a/src/AspNetCoreModuleV2/OutOfProcessRequestHandler/outofprocess/processmanager.cxx
+++ b/src/AspNetCoreModuleV2/OutOfProcessRequestHandler/outofprocess/processmanager.cxx
@@ -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);
diff --git a/src/AspNetCoreModuleV2/OutOfProcessRequestHandler/outofprocess/processmanager.h b/src/AspNetCoreModuleV2/OutOfProcessRequestHandler/outofprocess/processmanager.h
index b15da72486..764e77d595 100644
--- a/src/AspNetCoreModuleV2/OutOfProcessRequestHandler/outofprocess/processmanager.h
+++ b/src/AspNetCoreModuleV2/OutOfProcessRequestHandler/outofprocess/processmanager.h
@@ -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;
};
diff --git a/src/AspNetCoreModuleV2/RequestHandlerLib/AppOfflineTrackingApplication.cpp b/src/AspNetCoreModuleV2/RequestHandlerLib/AppOfflineTrackingApplication.cpp
new file mode 100644
index 0000000000..7c335ceff1
--- /dev/null
+++ b/src/AspNetCoreModuleV2/RequestHandlerLib/AppOfflineTrackingApplication.cpp
@@ -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();
+ 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();
+}
diff --git a/src/AspNetCoreModuleV2/RequestHandlerLib/AppOfflineTrackingApplication.h b/src/AspNetCoreModuleV2/RequestHandlerLib/AppOfflineTrackingApplication.h
new file mode 100644
index 0000000000..776ae9913c
--- /dev/null
+++ b/src/AspNetCoreModuleV2/RequestHandlerLib/AppOfflineTrackingApplication.h
@@ -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
+#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 m_fileWatcher;
+ std::unique_ptr m_fileWatcherEntry;
+};
diff --git a/src/AspNetCoreModuleV2/RequestHandlerLib/RequestHandlerLib.vcxproj b/src/AspNetCoreModuleV2/RequestHandlerLib/RequestHandlerLib.vcxproj
index 844328640e..8b1b24631e 100644
--- a/src/AspNetCoreModuleV2/RequestHandlerLib/RequestHandlerLib.vcxproj
+++ b/src/AspNetCoreModuleV2/RequestHandlerLib/RequestHandlerLib.vcxproj
@@ -1,4 +1,4 @@
-
+
@@ -188,7 +188,9 @@
+
+
@@ -199,7 +201,9 @@
+
+
diff --git a/src/AspNetCoreModuleV2/AspNetCore/src/filewatcher.cxx b/src/AspNetCoreModuleV2/RequestHandlerLib/filewatcher.cpp
similarity index 97%
rename from src/AspNetCoreModuleV2/AspNetCore/src/filewatcher.cxx
rename to src/AspNetCoreModuleV2/RequestHandlerLib/filewatcher.cpp
index 4bb215b4ed..a35d8cb63c 100644
--- a/src/AspNetCoreModuleV2/AspNetCore/src/filewatcher.cxx
+++ b/src/AspNetCoreModuleV2/RequestHandlerLib/filewatcher.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 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)))
{
diff --git a/src/AspNetCoreModuleV2/AspNetCore/Inc/filewatcher.h b/src/AspNetCoreModuleV2/RequestHandlerLib/filewatcher.h
similarity index 88%
rename from src/AspNetCoreModuleV2/AspNetCore/Inc/filewatcher.h
rename to src/AspNetCoreModuleV2/RequestHandlerLib/filewatcher.h
index 8bcd746326..c010caefc0 100644
--- a/src/AspNetCoreModuleV2/AspNetCore/Inc/filewatcher.h
+++ b/src/AspNetCoreModuleV2/RequestHandlerLib/filewatcher.h
@@ -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
-
-#include "stringu.h"
+#include
+#include
#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 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 _pCallback;
+};
+
+
+struct FILE_WATCHER_ENTRY_DELETER
+{
+ void operator()(FILE_WATCHER_ENTRY* entry) const
+ {
+ entry->DereferenceFileWatcherEntry();
+ }
};
diff --git a/src/AspNetCoreModuleV2/RequestHandlerLib/requesthandler_config.h b/src/AspNetCoreModuleV2/RequestHandlerLib/requesthandler_config.h
index a7369ca0e7..5ba8959317 100644
--- a/src/AspNetCoreModuleV2/RequestHandlerLib/requesthandler_config.h
+++ b/src/AspNetCoreModuleV2/RequestHandlerLib/requesthandler_config.h
@@ -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;
+
};
diff --git a/src/AspNetCoreModuleV2/RequestHandlerLib/stdafx.h b/src/AspNetCoreModuleV2/RequestHandlerLib/stdafx.h
index 96c3ffe6de..fd6382710b 100644
--- a/src/AspNetCoreModuleV2/RequestHandlerLib/stdafx.h
+++ b/src/AspNetCoreModuleV2/RequestHandlerLib/stdafx.h
@@ -24,5 +24,3 @@
#include "dbgutil.h"
#include "ahutil.h"
#include "hashfn.h"
-
-
diff --git a/test/Common.FunctionalTests/Inprocess/FixtureLoggedTest.cs b/test/Common.FunctionalTests/Inprocess/FixtureLoggedTest.cs
new file mode 100644
index 0000000000..4604687991
--- /dev/null
+++ b/test/Common.FunctionalTests/Inprocess/FixtureLoggedTest.cs
@@ -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();
+ }
+ }
+}
diff --git a/test/Common.FunctionalTests/Inprocess/SynchronousReadAndWriteTests.cs b/test/Common.FunctionalTests/Inprocess/SynchronousReadAndWriteTests.cs
index 9b57d4996b..03aa0e16e6 100644
--- a/test/Common.FunctionalTests/Inprocess/SynchronousReadAndWriteTests.cs
+++ b/test/Common.FunctionalTests/Inprocess/SynchronousReadAndWriteTests.cs
@@ -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++)
diff --git a/test/Common.FunctionalTests/Utilities/Helpers.cs b/test/Common.FunctionalTests/Utilities/Helpers.cs
index 6915d955ec..f4114730b3 100644
--- a/test/Common.FunctionalTests/Utilities/Helpers.cs
+++ b/test/Common.FunctionalTests/Utilities/Helpers.cs
@@ -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,
};
}
diff --git a/test/Common.FunctionalTests/Utilities/IISTestSiteFixture.cs b/test/Common.FunctionalTests/Utilities/IISTestSiteFixture.cs
index d19dad36d0..1a60e85246 100644
--- a/test/Common.FunctionalTests/Utilities/IISTestSiteFixture.cs
+++ b/test/Common.FunctionalTests/Utilities/IISTestSiteFixture.cs
@@ -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 _loggers = new List();
+
+ 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(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func formatter)
+ {
+ Logger?.Log(logLevel, eventId, state, exception, formatter);
+ }
+
+ public bool IsEnabled(LogLevel logLevel) => Logger?.IsEnabled(logLevel) == true;
+
+ public IDisposable BeginScope(TState state) => Logger?.BeginScope(state);
+ }
}
+
}
diff --git a/test/CommonLibTests/CommonLibTests.vcxproj b/test/CommonLibTests/CommonLibTests.vcxproj
index 906518c621..85cc1d39be 100644
--- a/test/CommonLibTests/CommonLibTests.vcxproj
+++ b/test/CommonLibTests/CommonLibTests.vcxproj
@@ -101,7 +101,7 @@
true
Console
..\..\src\AspNetCoreModuleV2\InProcessRequestHandler\$(Configuration)\;
- 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)
+ 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)
@@ -127,7 +127,7 @@
true
Console
..\..\src\AspNetCoreModuleV2\InProcessRequestHandler\x64\$(Configuration)\;
- 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)
+ 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)
@@ -153,7 +153,7 @@
true
true
..\..\src\AspNetCoreModuleV2\InProcessRequestHandler\$(Configuration)\;
- 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)
+ 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)
@@ -179,7 +179,7 @@
true
true
..\..\src\AspNetCoreModuleV2\InProcessRequestHandler\x64\$(Configuration)\;
- 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)
+ 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)
diff --git a/test/CommonLibTests/fakeclasses.h b/test/CommonLibTests/fakeclasses.h
index 14c6f8dfee..ba792017c4 100644
--- a/test/CommonLibTests/fakeclasses.h
+++ b/test/CommonLibTests/fakeclasses.h
@@ -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:
diff --git a/test/CommonLibTests/inprocess_application_tests.cpp b/test/CommonLibTests/inprocess_application_tests.cpp
index 3f1f67e457..00c7b01611 100644
--- a/test/CommonLibTests/inprocess_application_tests.cpp
+++ b/test/CommonLibTests/inprocess_application_tests.cpp
@@ -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(requestHandlerConfig);
+ MockHttpServer server;
+ NiceMock application;
+
+ ON_CALL(application, GetApplicationPhysicalPath())
+ .WillByDefault(testing::Return(L"Some path"));
+
+ auto requestHandlerConfig = std::unique_ptr(MockRequestHandlerConfig::CreateConfig());
std::wstring exePath(L"hello");
- std::array parameters {
+
+ std::array 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");
}
}
diff --git a/test/IISExpress.FunctionalTests/InProcess/AppOfflineTests.cs b/test/IISExpress.FunctionalTests/InProcess/AppOfflineTests.cs
index 5cfd7fe7c0..87741af201 100644
--- a/test/IISExpress.FunctionalTests/InProcess/AppOfflineTests.cs
+++ b/test/IISExpress.FunctionalTests/InProcess/AppOfflineTests.cs
@@ -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 DeployApp()
+ private async Task 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 AssertStarts()
+ private async Task 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;
}
}
}
diff --git a/test/IISExpress.FunctionalTests/InProcess/AuthenticationTests.cs b/test/IISExpress.FunctionalTests/InProcess/AuthenticationTests.cs
index c3540d51ee..31179b1ecf 100644
--- a/test/IISExpress.FunctionalTests/InProcess/AuthenticationTests.cs
+++ b/test/IISExpress.FunctionalTests/InProcess/AuthenticationTests.cs
@@ -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);
diff --git a/test/IISExpress.FunctionalTests/InProcess/LoggingTests.cs b/test/IISExpress.FunctionalTests/InProcess/LoggingTests.cs
index 856bf1669f..6d8e73a15c 100644
--- a/test/IISExpress.FunctionalTests/InProcess/LoggingTests.cs
+++ b/test/IISExpress.FunctionalTests/InProcess/LoggingTests.cs
@@ -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
diff --git a/test/IISExpress.FunctionalTests/InProcess/ShutdownTests.cs b/test/IISExpress.FunctionalTests/InProcess/ShutdownTests.cs
index 69eacfbc43..d43894a2c3 100644
--- a/test/IISExpress.FunctionalTests/InProcess/ShutdownTests.cs
+++ b/test/IISExpress.FunctionalTests/InProcess/ShutdownTests.cs
@@ -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");