Merge branch 'merge/release/2.2-to-master'

This commit is contained in:
Justin Kotalik 2018-08-21 15:35:12 -07:00
commit 453d488095
58 changed files with 1313 additions and 919 deletions

View File

@ -52,6 +52,6 @@
<XunitPackageVersion>2.3.1</XunitPackageVersion> <XunitPackageVersion>2.3.1</XunitPackageVersion>
<XunitRunnerVisualStudioPackageVersion>2.4.0</XunitRunnerVisualStudioPackageVersion> <XunitRunnerVisualStudioPackageVersion>2.4.0</XunitRunnerVisualStudioPackageVersion>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Label="Package Versions: Pinned" />
<Import Project="$(DotNetPackageVersionPropsPath)" Condition=" '$(DotNetPackageVersionPropsPath)' != '' " /> <Import Project="$(DotNetPackageVersionPropsPath)" Condition=" '$(DotNetPackageVersionPropsPath)' != '' " />
<PropertyGroup Label="Package Versions: Pinned" />
</Project> </Project>

View File

@ -11,7 +11,7 @@
#define ASPNETCORE_EVENT_RAPID_FAIL_COUNT_EXCEEDED_MSG L"Maximum rapid fail count per minute of '%d' exceeded." #define ASPNETCORE_EVENT_RAPID_FAIL_COUNT_EXCEEDED_MSG L"Maximum rapid fail count per minute of '%d' exceeded."
#define ASPNETCORE_EVENT_PROCESS_START_INTERNAL_ERROR_MSG L"Application '%s' failed to parse processPath and arguments due to internal error, ErrorCode = '0x%x'." #define ASPNETCORE_EVENT_PROCESS_START_INTERNAL_ERROR_MSG L"Application '%s' failed to parse processPath and arguments due to internal error, ErrorCode = '0x%x'."
#define ASPNETCORE_EVENT_PROCESS_START_POSTCREATE_ERROR_MSG L"Application '%s' with physical root '%s' created process with commandline '%s'but failed to get its status, ErrorCode = '0x%x'." #define ASPNETCORE_EVENT_PROCESS_START_POSTCREATE_ERROR_MSG L"Application '%s' with physical root '%s' created process with commandline '%s'but failed to get its status, ErrorCode = '0x%x'."
#define ASPNETCORE_EVENT_PROCESS_START_ERROR_MSG L"Application '%s' with physical root '%s' failed to start process with commandline '%s', ErrorCode = '0x%x : %x." #define ASPNETCORE_EVENT_PROCESS_START_ERROR_MSG L"Application '%s' with physical root '%s' failed to start process with commandline '%s', ErrorCode = '0x%x' : %x."
#define ASPNETCORE_EVENT_PROCESS_START_WRONGPORT_ERROR_MSG L"Application '%s' with physical root '%s' created process with commandline '%s' but failed to listen on the given port '%d'" #define ASPNETCORE_EVENT_PROCESS_START_WRONGPORT_ERROR_MSG L"Application '%s' with physical root '%s' created process with commandline '%s' but failed to listen on the given port '%d'"
#define ASPNETCORE_EVENT_PROCESS_START_NOTREADY_ERROR_MSG L"Application '%s' with physical root '%s' created process with commandline '%s' but either crashed or did not reponse or did not listen on the given port '%d', ErrorCode = '0x%x'" #define ASPNETCORE_EVENT_PROCESS_START_NOTREADY_ERROR_MSG L"Application '%s' with physical root '%s' created process with commandline '%s' but either crashed or did not reponse or did not listen on the given port '%d', ErrorCode = '0x%x'"
#define ASPNETCORE_EVENT_INVALID_STDOUT_LOG_FILE_MSG L"Warning: Could not create stdoutLogFile %s, ErrorCode = %d." #define ASPNETCORE_EVENT_INVALID_STDOUT_LOG_FILE_MSG L"Warning: Could not create stdoutLogFile %s, ErrorCode = %d."

View File

@ -1,6 +1,7 @@
;/*++ ;/*++
; ;
;Copyright (c) 2014 Microsoft Corporation ; Copyright (c) .NET Foundation. All rights reserved.
; Licensed under the MIT License. See License.txt in the project root for license information.
; ;
;Module Name: ;Module Name:
; ;

View File

@ -3,6 +3,7 @@
#include <windows.h> #include <windows.h>
#include "version.h" #include "version.h"
#include "resource.h" #include "resource.h"
#include "Aspnetcore_msg.rc"
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
// English (United States) resources // English (United States) resources
@ -75,10 +76,10 @@ BEGIN
BEGIN BEGIN
BLOCK "040904b0" BLOCK "040904b0"
BEGIN BEGIN
VALUE "CompanyName", "Microsoft" VALUE "CompanyName", "Microsoft Corporation"
VALUE "FileDescription", FileDescription VALUE "FileDescription", FileDescription
VALUE "FileVersion", FileVersionStr VALUE "FileVersion", FileVersionStr
VALUE "InternalName", "aspnetcore.dll" VALUE "InternalName", "aspnetcore"
VALUE "LegalCopyright", "Copyright (C) Microsoft Corporation" VALUE "LegalCopyright", "Copyright (C) Microsoft Corporation"
VALUE "OriginalFilename", "aspnetcore.dll" VALUE "OriginalFilename", "aspnetcore.dll"
VALUE "ProductName", "ASP.NET Core Module" VALUE "ProductName", "ASP.NET Core Module"

View File

@ -132,7 +132,7 @@ SERVER_PROCESS::SetupListenPort(
pEnvironmentVarTable->FindKey(ASPNETCORE_PORT_ENV_STR, &pEntry); pEnvironmentVarTable->FindKey(ASPNETCORE_PORT_ENV_STR, &pEntry);
if (pEntry != NULL) if (pEntry != NULL)
{ {
if (pEntry->QueryValue() != NULL || pEntry->QueryValue()[0] != L'\0') if (pEntry->QueryValue() != NULL && pEntry->QueryValue()[0] != L'\0')
{ {
m_dwPort = (DWORD)_wtoi(pEntry->QueryValue()); m_dwPort = (DWORD)_wtoi(pEntry->QueryValue());
if(m_dwPort >MAX_PORT || m_dwPort < MIN_PORT) if(m_dwPort >MAX_PORT || m_dwPort < MIN_PORT)
@ -150,6 +150,8 @@ SERVER_PROCESS::SetupListenPort(
// user set the env variable but did not give value, let's set it up // user set the env variable but did not give value, let's set it up
// //
pEnvironmentVarTable->DeleteKey(ASPNETCORE_PORT_ENV_STR); pEnvironmentVarTable->DeleteKey(ASPNETCORE_PORT_ENV_STR);
pEntry->Dereference();
pEntry = NULL;
} }
} }
@ -1068,8 +1070,8 @@ Finished:
{ {
if (!fDonePrepareCommandLine) if (!fDonePrepareCommandLine)
strEventMsg.SafeSnwprintf( strEventMsg.SafeSnwprintf(
m_struAppFullPath.QueryStr(),
ASPNETCORE_EVENT_PROCESS_START_INTERNAL_ERROR_MSG, ASPNETCORE_EVENT_PROCESS_START_INTERNAL_ERROR_MSG,
m_struAppFullPath.QueryStr(),
hr); hr);
else else
strEventMsg.SafeSnwprintf( strEventMsg.SafeSnwprintf(

View File

@ -10,6 +10,8 @@
#include "GlobalVersionUtility.h" #include "GlobalVersionUtility.h"
#include "HandleWrapper.h" #include "HandleWrapper.h"
#include "file_utility.h" #include "file_utility.h"
#include "LoggingHelpers.h"
#include "resources.h"
const PCWSTR HandlerResolver::s_pwzAspnetcoreInProcessRequestHandlerName = L"aspnetcorev2_inprocess.dll"; const PCWSTR HandlerResolver::s_pwzAspnetcoreInProcessRequestHandlerName = L"aspnetcorev2_inprocess.dll";
const PCWSTR HandlerResolver::s_pwzAspnetcoreOutOfProcessRequestHandlerName = L"aspnetcorev2_outofprocess.dll"; const PCWSTR HandlerResolver::s_pwzAspnetcoreOutOfProcessRequestHandlerName = L"aspnetcorev2_outofprocess.dll";
@ -46,6 +48,7 @@ HandlerResolver::LoadRequestHandlerAssembly(IHttpApplication &pApplication, STRU
if (pConfiguration->QueryHostingModel() == APP_HOSTING_MODEL::HOSTING_IN_PROCESS) if (pConfiguration->QueryHostingModel() == APP_HOSTING_MODEL::HOSTING_IN_PROCESS)
{ {
std::unique_ptr<HOSTFXR_OPTIONS> options; std::unique_ptr<HOSTFXR_OPTIONS> options;
std::unique_ptr<IOutputManager> outputManager;
RETURN_IF_FAILED(HOSTFXR_OPTIONS::Create( RETURN_IF_FAILED(HOSTFXR_OPTIONS::Create(
NULL, NULL,
@ -56,14 +59,35 @@ HandlerResolver::LoadRequestHandlerAssembly(IHttpApplication &pApplication, STRU
RETURN_IF_FAILED(location.Copy(options->GetExeLocation())); RETURN_IF_FAILED(location.Copy(options->GetExeLocation()));
if (FAILED_LOG(hr = FindNativeAssemblyFromHostfxr(options.get(), pstrHandlerDllName, &struFileName))) RETURN_IF_FAILED(LoggingHelpers::CreateLoggingProvider(
{ pConfiguration->QueryStdoutLogEnabled(),
EventLog::Error( !m_pServer.IsCommandLineLaunch(),
ASPNETCORE_EVENT_INPROCESS_RH_MISSING, pConfiguration->QueryStdoutLogFile()->QueryStr(),
ASPNETCORE_EVENT_INPROCESS_RH_MISSING_MSG, pApplication.GetApplicationPhysicalPath(),
struFileName.IsEmpty() ? s_pwzAspnetcoreInProcessRequestHandlerName : struFileName.QueryStr()); outputManager));
outputManager->Start();
hr = FindNativeAssemblyFromHostfxr(options.get(), pstrHandlerDllName, &struFileName);
outputManager->Stop();
if (FAILED(hr) && m_hHostFxrDll != NULL)
{
STRA content;
STRU struStdMsg;
outputManager->GetStdOutContent(&content);
if (content.QueryCCH() > 0)
{
struStdMsg.CopyA(content.QueryStr());
}
EventLog::Error(
ASPNETCORE_EVENT_GENERAL_ERROR,
ASPNETCORE_EVENT_INPROCESS_RH_ERROR_MSG,
struFileName.IsEmpty() ? s_pwzAspnetcoreInProcessRequestHandlerName : struFileName.QueryStr(),
struStdMsg.QueryStr());
return hr;
} }
} }
else else
@ -188,12 +212,23 @@ HandlerResolver::FindNativeAssemblyFromHostfxr(
BOOL fFound = FALSE; BOOL fFound = FALSE;
DWORD dwBufferSize = 1024 * 10; DWORD dwBufferSize = 1024 * 10;
DWORD dwRequiredBufferSize = 0; DWORD dwRequiredBufferSize = 0;
STRA output;
DBG_ASSERT(struFilename != NULL); DBG_ASSERT(struFilename != NULL);
RETURN_LAST_ERROR_IF_NULL(m_hHostFxrDll = LoadLibraryW(hostfxrOptions->GetHostFxrLocation())); RETURN_LAST_ERROR_IF_NULL(m_hHostFxrDll = LoadLibraryW(hostfxrOptions->GetHostFxrLocation()));
auto pFnHostFxrSearchDirectories = reinterpret_cast<hostfxr_get_native_search_directories_fn>(GetProcAddress(m_hHostFxrDll, "hostfxr_get_native_search_directories")); auto pFnHostFxrSearchDirectories = reinterpret_cast<hostfxr_get_native_search_directories_fn>(GetProcAddress(m_hHostFxrDll, "hostfxr_get_native_search_directories"));
if (pFnHostFxrSearchDirectories == nullptr)
{
EventLog::Error(
ASPNETCORE_EVENT_GENERAL_ERROR,
ASPNETCORE_EVENT_HOSTFXR_DLL_INVALID_VERSION_MSG,
hostfxrOptions->GetHostFxrLocation()
);
RETURN_IF_FAILED(E_FAIL);
}
RETURN_LAST_ERROR_IF_NULL(pFnHostFxrSearchDirectories); RETURN_LAST_ERROR_IF_NULL(pFnHostFxrSearchDirectories);
RETURN_IF_FAILED(struNativeSearchPaths.Resize(dwBufferSize)); RETURN_IF_FAILED(struNativeSearchPaths.Resize(dwBufferSize));

View File

@ -29,7 +29,7 @@ ASPNETCORE_SHIM_CONFIG::Populate(
CS_ASPNETCORE_PROCESS_EXE_PATH, CS_ASPNETCORE_PROCESS_EXE_PATH,
&m_struProcessPath)); &m_struProcessPath));
// Swallow this error for backward compatability // Swallow this error for backward compatibility
// Use default behavior for empty string // Use default behavior for empty string
GetElementStringProperty(pAspNetCoreElement, GetElementStringProperty(pAspNetCoreElement,
CS_ASPNETCORE_HOSTING_MODEL, CS_ASPNETCORE_HOSTING_MODEL,
@ -50,7 +50,7 @@ ASPNETCORE_SHIM_CONFIG::Populate(
ASPNETCORE_EVENT_UNKNOWN_HOSTING_MODEL_ERROR, ASPNETCORE_EVENT_UNKNOWN_HOSTING_MODEL_ERROR,
ASPNETCORE_EVENT_UNKNOWN_HOSTING_MODEL_ERROR_MSG, ASPNETCORE_EVENT_UNKNOWN_HOSTING_MODEL_ERROR_MSG,
strHostingModel.QueryStr()); strHostingModel.QueryStr());
RETURN_IF_FAILED(HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED)); RETURN_HR(HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED));
} }
RETURN_IF_FAILED(GetElementStringProperty(pAspNetCoreElement, RETURN_IF_FAILED(GetElementStringProperty(pAspNetCoreElement,
@ -62,5 +62,13 @@ ASPNETCORE_SHIM_CONFIG::Populate(
RETURN_IF_FAILED(ConfigUtility::FindHandlerVersion(pAspNetCoreElement, m_struHandlerVersion)); RETURN_IF_FAILED(ConfigUtility::FindHandlerVersion(pAspNetCoreElement, m_struHandlerVersion));
} }
RETURN_IF_FAILED(GetElementBoolProperty(pAspNetCoreElement,
CS_ASPNETCORE_STDOUT_LOG_ENABLED,
&m_fStdoutLogEnabled));
RETURN_IF_FAILED(GetElementStringProperty(pAspNetCoreElement,
CS_ASPNETCORE_STDOUT_LOG_FILE,
&m_struStdoutLogFile));
return S_OK; return S_OK;
} }

View File

@ -12,6 +12,8 @@
#define CS_ASPNETCORE_PROCESS_EXE_PATH L"processPath" #define CS_ASPNETCORE_PROCESS_EXE_PATH L"processPath"
#define CS_ASPNETCORE_PROCESS_ARGUMENTS L"arguments" #define CS_ASPNETCORE_PROCESS_ARGUMENTS L"arguments"
#define CS_ASPNETCORE_HOSTING_MODEL L"hostingModel" #define CS_ASPNETCORE_HOSTING_MODEL L"hostingModel"
#define CS_ASPNETCORE_STDOUT_LOG_ENABLED L"stdoutLogEnabled"
#define CS_ASPNETCORE_STDOUT_LOG_FILE L"stdoutLogFile"
enum APP_HOSTING_MODEL enum APP_HOSTING_MODEL
{ {
@ -56,6 +58,18 @@ public:
return &m_struHandlerVersion; return &m_struHandlerVersion;
} }
BOOL
QueryStdoutLogEnabled()
{
return m_fStdoutLogEnabled;
}
STRU*
QueryStdoutLogFile()
{
return &m_struStdoutLogFile;
}
ASPNETCORE_SHIM_CONFIG() : ASPNETCORE_SHIM_CONFIG() :
m_hostingModel(HOSTING_UNKNOWN) m_hostingModel(HOSTING_UNKNOWN)
{ {
@ -67,5 +81,6 @@ private:
STRU m_struProcessPath; STRU m_struProcessPath;
APP_HOSTING_MODEL m_hostingModel; APP_HOSTING_MODEL m_hostingModel;
STRU m_struHandlerVersion; STRU m_struHandlerVersion;
BOOL m_fStdoutLogEnabled;
STRU m_struStdoutLogFile;
}; };

View File

@ -200,6 +200,7 @@
<ClInclude Include="EventLog.h" /> <ClInclude Include="EventLog.h" />
<ClInclude Include="exceptions.h" /> <ClInclude Include="exceptions.h" />
<ClInclude Include="file_utility.h" /> <ClInclude Include="file_utility.h" />
<ClInclude Include="FileOutputManager.h" />
<ClInclude Include="GlobalVersionUtility.h" /> <ClInclude Include="GlobalVersionUtility.h" />
<ClInclude Include="fx_ver.h" /> <ClInclude Include="fx_ver.h" />
<ClInclude Include="HandleWrapper.h" /> <ClInclude Include="HandleWrapper.h" />
@ -207,7 +208,12 @@
<ClInclude Include="hostfxr_utility.h" /> <ClInclude Include="hostfxr_utility.h" />
<ClInclude Include="iapplication.h" /> <ClInclude Include="iapplication.h" />
<ClInclude Include="debugutil.h" /> <ClInclude Include="debugutil.h" />
<ClInclude Include="IOutputManager.h" />
<ClInclude Include="irequesthandler.h" /> <ClInclude Include="irequesthandler.h" />
<ClInclude Include="LoggingHelpers.h" />
<ClInclude Include="NullOutputManager.h" />
<ClInclude Include="PipeOutputManager.h" />
<ClInclude Include="StdWrapper.h" />
<ClInclude Include="requesthandler.h" /> <ClInclude Include="requesthandler.h" />
<ClInclude Include="resources.h" /> <ClInclude Include="resources.h" />
<ClInclude Include="SRWExclusiveLock.h" /> <ClInclude Include="SRWExclusiveLock.h" />
@ -220,11 +226,15 @@
<ClCompile Include="Environment.cpp" /> <ClCompile Include="Environment.cpp" />
<ClCompile Include="EventLog.cpp" /> <ClCompile Include="EventLog.cpp" />
<ClCompile Include="file_utility.cpp" /> <ClCompile Include="file_utility.cpp" />
<ClCompile Include="FileOutputManager.cpp" />
<ClCompile Include="fx_ver.cpp" /> <ClCompile Include="fx_ver.cpp" />
<ClCompile Include="GlobalVersionUtility.cpp" /> <ClCompile Include="GlobalVersionUtility.cpp" />
<ClCompile Include="HandleWrapper.cpp" /> <ClCompile Include="HandleWrapper.cpp" />
<ClCompile Include="hostfxr_utility.cpp" /> <ClCompile Include="hostfxr_utility.cpp" />
<ClCompile Include="hostfxroptions.cpp" /> <ClCompile Include="hostfxroptions.cpp" />
<ClCompile Include="LoggingHelpers.cpp" />
<ClCompile Include="PipeOutputManager.cpp" />
<ClCompile Include="StdWrapper.cpp" />
<ClCompile Include="SRWExclusiveLock.cpp" /> <ClCompile Include="SRWExclusiveLock.cpp" />
<ClCompile Include="SRWSharedLock.cpp" /> <ClCompile Include="SRWSharedLock.cpp" />
<ClCompile Include="stdafx.cpp"> <ClCompile Include="stdafx.cpp">

View File

@ -27,7 +27,7 @@ EventLog::LogEvent(
); );
} }
DebugPrintf(dwEventInfoType == EVENTLOG_ERROR_TYPE ? ASPNETCORE_DEBUG_FLAG_ERROR : ASPNETCORE_DEBUG_FLAG_INFO, "Event Log: %S", pstrMsg); DebugPrintf(dwEventInfoType == EVENTLOG_ERROR_TYPE ? ASPNETCORE_DEBUG_FLAG_ERROR : ASPNETCORE_DEBUG_FLAG_INFO, "Event Log: %S \r\nEnd Event Log Message.", pstrMsg);
} }
VOID VOID

View File

@ -0,0 +1,190 @@
// 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 "FileOutputManager.h"
#include "sttimer.h"
#include "exceptions.h"
#include "debugutil.h"
#include "SRWExclusiveLock.h"
#include "file_utility.h"
#include "StdWrapper.h"
extern HINSTANCE g_hModule;
FileOutputManager::FileOutputManager() :
FileOutputManager(/* fEnableNativeLogging */ true) { }
FileOutputManager::FileOutputManager(bool fEnableNativeLogging) :
m_hLogFileHandle(INVALID_HANDLE_VALUE),
m_disposed(false),
stdoutWrapper(nullptr),
stderrWrapper(nullptr),
m_fEnableNativeRedirection(fEnableNativeLogging)
{
InitializeSRWLock(&m_srwLock);
}
FileOutputManager::~FileOutputManager()
{
FileOutputManager::Stop();
}
HRESULT
FileOutputManager::Initialize(PCWSTR pwzStdOutLogFileName, PCWSTR pwzApplicationPath)
{
RETURN_IF_FAILED(m_wsApplicationPath.Copy(pwzApplicationPath));
RETURN_IF_FAILED(m_wsStdOutLogFileName.Copy(pwzStdOutLogFileName));
return S_OK;
}
// Start redirecting stdout and stderr into the file handle.
// Uses sttimer to continuously flush output into the file.
HRESULT
FileOutputManager::Start()
{
SYSTEMTIME systemTime;
SECURITY_ATTRIBUTES saAttr = { 0 };
STRU struPath;
// Concatenate the log file name and application path
RETURN_IF_FAILED(FILE_UTILITY::ConvertPathToFullPath(
m_wsStdOutLogFileName.QueryStr(),
m_wsApplicationPath.QueryStr(),
&struPath));
RETURN_IF_FAILED(FILE_UTILITY::EnsureDirectoryPathExist(struPath.QueryStr()));
// Get the module name and add it to the log file name
// as two log files will be created, one from the shim
// and one from the request handler.
WCHAR path[MAX_PATH];
RETURN_LAST_ERROR_IF(!GetModuleFileName(g_hModule, path, sizeof(path)));
std::filesystem::path fsPath(path);
// TODO fix string as it is incorrect
GetSystemTime(&systemTime);
RETURN_IF_FAILED(
m_struLogFilePath.SafeSnwprintf(L"%s_%d%02d%02d%02d%02d%02d_%d_%s.log",
struPath.QueryStr(),
systemTime.wYear,
systemTime.wMonth,
systemTime.wDay,
systemTime.wHour,
systemTime.wMinute,
systemTime.wSecond,
GetCurrentProcessId(),
fsPath.filename().stem().c_str()));
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
saAttr.bInheritHandle = TRUE;
saAttr.lpSecurityDescriptor = NULL;
// Create the file with both READ and WRITE.
m_hLogFileHandle = CreateFileW(m_struLogFilePath.QueryStr(),
FILE_READ_DATA | FILE_WRITE_DATA,
FILE_SHARE_READ,
&saAttr,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
nullptr);
RETURN_LAST_ERROR_IF(m_hLogFileHandle == INVALID_HANDLE_VALUE);
stdoutWrapper = std::make_unique<StdWrapper>(stdout, STD_OUTPUT_HANDLE, m_hLogFileHandle, m_fEnableNativeRedirection);
stderrWrapper = std::make_unique<StdWrapper>(stderr, STD_ERROR_HANDLE, m_hLogFileHandle, m_fEnableNativeRedirection);
stdoutWrapper->StartRedirection();
stderrWrapper->StartRedirection();
return S_OK;
}
HRESULT
FileOutputManager::Stop()
{
STRA straStdOutput;
CHAR pzFileContents[MAX_FILE_READ_SIZE] = { 0 };
DWORD dwNumBytesRead;
LARGE_INTEGER li = { 0 };
DWORD dwFilePointer = 0;
HANDLE handle = NULL;
WIN32_FIND_DATA fileData;
if (m_disposed)
{
return S_OK;
}
SRWExclusiveLock lock(m_srwLock);
if (m_disposed)
{
return S_OK;
}
m_disposed = true;
if (m_hLogFileHandle == INVALID_HANDLE_VALUE)
{
return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
}
FlushFileBuffers(m_hLogFileHandle);
if (stdoutWrapper != nullptr)
{
RETURN_IF_FAILED(stdoutWrapper->StopRedirection());
}
if (stderrWrapper != nullptr)
{
RETURN_IF_FAILED(stderrWrapper->StopRedirection());
}
// delete empty log file
handle = FindFirstFile(m_struLogFilePath.QueryStr(), &fileData);
if (handle != INVALID_HANDLE_VALUE &&
handle != NULL &&
fileData.nFileSizeHigh == 0 &&
fileData.nFileSizeLow == 0) // skip check of nFileSizeHigh
{
FindClose(handle);
LOG_LAST_ERROR_IF(!DeleteFile(m_struLogFilePath.QueryStr()));
}
// Read the first 30Kb from the file and store it in a buffer.
// By doing this, we can close the handle to the file and be done with it.
RETURN_LAST_ERROR_IF(!GetFileSizeEx(m_hLogFileHandle, &li));
if (li.LowPart == 0 || li.HighPart > 0)
{
RETURN_IF_FAILED(HRESULT_FROM_WIN32(ERROR_FILE_INVALID));
}
dwFilePointer = SetFilePointer(m_hLogFileHandle, 0, NULL, FILE_BEGIN);
RETURN_LAST_ERROR_IF(dwFilePointer == INVALID_SET_FILE_POINTER);
RETURN_LAST_ERROR_IF(!ReadFile(m_hLogFileHandle, pzFileContents, MAX_FILE_READ_SIZE, &dwNumBytesRead, NULL));
m_straFileContent.Copy(pzFileContents, dwNumBytesRead);
// printf will fail in in full IIS
if (printf(m_straFileContent.QueryStr()) != -1)
{
// Need to flush contents for the new stdout and stderr
_flushall();
}
return S_OK;
}
bool FileOutputManager::GetStdOutContent(STRA* struStdOutput)
{
struStdOutput->Copy(m_straFileContent);
return m_straFileContent.QueryCCH() > 0;
}

View File

@ -6,12 +6,17 @@
#include "sttimer.h" #include "sttimer.h"
#include "IOutputManager.h" #include "IOutputManager.h"
#include "HandleWrapper.h" #include "HandleWrapper.h"
#include "StdWrapper.h"
#include "stringa.h"
#include "stringu.h"
class FileOutputManager : public IOutputManager class FileOutputManager : public IOutputManager
{ {
#define FILE_FLUSH_TIMEOUT 3000 #define FILE_FLUSH_TIMEOUT 3000
#define MAX_FILE_READ_SIZE 30000
public: public:
FileOutputManager(); FileOutputManager();
FileOutputManager(bool fEnableNativeLogging);
~FileOutputManager(); ~FileOutputManager();
HRESULT HRESULT
@ -27,9 +32,10 @@ private:
STRU m_wsStdOutLogFileName; STRU m_wsStdOutLogFileName;
STRU m_wsApplicationPath; STRU m_wsApplicationPath;
STRU m_struLogFilePath; STRU m_struLogFilePath;
int m_fdPreviousStdOut; STRA m_straFileContent;
int m_fdPreviousStdErr;
BOOL m_disposed; BOOL m_disposed;
SRWLOCK m_srwLock; BOOL m_fEnableNativeRedirection;
SRWLOCK m_srwLock{};
std::unique_ptr<StdWrapper> stdoutWrapper;
std::unique_ptr<StdWrapper> stderrWrapper;
}; };

View File

@ -4,6 +4,7 @@
#pragma once #pragma once
#include <Windows.h> #include <Windows.h>
#include <ntassert.h>
struct InvalidHandleTraits struct InvalidHandleTraits
{ {

View File

@ -1,9 +1,11 @@
// Copyright (c) .NET Foundation. All rights reserved. // Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information. // Licensed under the MIT License. See License.txt in the project root for license information.
#include "stdafx.h"
#pragma once #pragma once
#include "stdafx.h"
#include "stringa.h"
class IOutputManager class IOutputManager
{ {
public: public:

View File

@ -7,14 +7,18 @@
#include "FileOutputManager.h" #include "FileOutputManager.h"
#include "PipeOutputManager.h" #include "PipeOutputManager.h"
#include "NullOutputManager.h" #include "NullOutputManager.h"
#include "debugutil.h"
#include <Windows.h>
#include <io.h>
#include "ntassert.h"
HRESULT HRESULT
LoggingHelpers::CreateLoggingProvider( LoggingHelpers::CreateLoggingProvider(
bool fIsLoggingEnabled, bool fIsLoggingEnabled,
bool fEnablePipe, bool fEnableNativeLogging,
PCWSTR pwzStdOutFileName, PCWSTR pwzStdOutFileName,
PCWSTR pwzApplicationPath, PCWSTR pwzApplicationPath,
_Out_ IOutputManager** outputManager std::unique_ptr<IOutputManager>& outputManager
) )
{ {
HRESULT hr = S_OK; HRESULT hr = S_OK;
@ -25,17 +29,17 @@ LoggingHelpers::CreateLoggingProvider(
{ {
if (fIsLoggingEnabled) if (fIsLoggingEnabled)
{ {
FileOutputManager* manager = new FileOutputManager; auto manager = std::make_unique<FileOutputManager>(fEnableNativeLogging);
hr = manager->Initialize(pwzStdOutFileName, pwzApplicationPath); hr = manager->Initialize(pwzStdOutFileName, pwzApplicationPath);
*outputManager = manager; outputManager = std::move(manager);
} }
else if (fEnablePipe) else if (!GetConsoleWindow())
{ {
*outputManager = new PipeOutputManager; outputManager = std::make_unique<PipeOutputManager>(fEnableNativeLogging);
} }
else else
{ {
*outputManager = new NullOutputManager; outputManager = std::make_unique<NullOutputManager>();
} }
} }
catch (std::bad_alloc&) catch (std::bad_alloc&)

View File

@ -13,10 +13,10 @@ public:
HRESULT HRESULT
CreateLoggingProvider( CreateLoggingProvider(
bool fLoggingEnabled, bool fLoggingEnabled,
bool fEnablePipe, bool fEnableNativeLogging,
PCWSTR pwzStdOutFileName, PCWSTR pwzStdOutFileName,
PCWSTR pwzApplicationPath, PCWSTR pwzApplicationPath,
_Out_ IOutputManager** outputManager std::unique_ptr<IOutputManager>& outputManager
); );
}; };

View File

@ -5,63 +5,74 @@
#include "PipeOutputManager.h" #include "PipeOutputManager.h"
#include "exceptions.h" #include "exceptions.h"
#include "SRWExclusiveLock.h" #include "SRWExclusiveLock.h"
#include "StdWrapper.h"
#include "ntassert.h"
#define LOG_IF_DUPFAIL(err) do { if (err == -1) { LOG_IF_FAILED(HRESULT_FROM_WIN32(_doserrno)); } } while (0, 0); #define LOG_IF_DUPFAIL(err) do { if (err == -1) { LOG_IF_FAILED(HRESULT_FROM_WIN32(_doserrno)); } } while (0, 0);
#define LOG_IF_ERRNO(err) do { if (err != 0) { LOG_IF_FAILED(HRESULT_FROM_WIN32(_doserrno)); } } while (0, 0); #define LOG_IF_ERRNO(err) do { if (err != 0) { LOG_IF_FAILED(HRESULT_FROM_WIN32(_doserrno)); } } while (0, 0);
PipeOutputManager::PipeOutputManager() : PipeOutputManager::PipeOutputManager()
m_dwStdErrReadTotal(0), : PipeOutputManager( /* fEnableNativeLogging */ true)
{
}
PipeOutputManager::PipeOutputManager(bool fEnableNativeLogging) :
m_hErrReadPipe(INVALID_HANDLE_VALUE), m_hErrReadPipe(INVALID_HANDLE_VALUE),
m_hErrWritePipe(INVALID_HANDLE_VALUE), m_hErrWritePipe(INVALID_HANDLE_VALUE),
m_hErrThread(NULL), m_hErrThread(nullptr),
m_dwStdErrReadTotal(0),
m_disposed(FALSE), m_disposed(FALSE),
m_fdPreviousStdOut(-1), m_fEnableNativeRedirection(fEnableNativeLogging),
m_fdPreviousStdErr(-1) stdoutWrapper(nullptr),
stderrWrapper(nullptr)
{ {
InitializeSRWLock(&m_srwLock); InitializeSRWLock(&m_srwLock);
} }
PipeOutputManager::~PipeOutputManager() PipeOutputManager::~PipeOutputManager()
{ {
Stop(); PipeOutputManager::Stop();
} }
// Start redirecting stdout and stderr into a pipe
// Continuously read the pipe on a background thread
// until Stop is called.
HRESULT PipeOutputManager::Start() HRESULT PipeOutputManager::Start()
{ {
SECURITY_ATTRIBUTES saAttr = { 0 }; SECURITY_ATTRIBUTES saAttr = { 0 };
HANDLE hStdErrReadPipe; HANDLE hStdErrReadPipe;
HANDLE hStdErrWritePipe; HANDLE hStdErrWritePipe;
m_fdPreviousStdOut = _dup(_fileno(stdout));
LOG_IF_DUPFAIL(m_fdPreviousStdOut);
m_fdPreviousStdErr = _dup(_fileno(stderr));
LOG_IF_DUPFAIL(m_fdPreviousStdErr);
RETURN_LAST_ERROR_IF(!CreatePipe(&hStdErrReadPipe, &hStdErrWritePipe, &saAttr, 0 /*nSize*/)); RETURN_LAST_ERROR_IF(!CreatePipe(&hStdErrReadPipe, &hStdErrWritePipe, &saAttr, 0 /*nSize*/));
// TODO this still doesn't redirect calls in native, like wprintf
RETURN_LAST_ERROR_IF(!SetStdHandle(STD_ERROR_HANDLE, hStdErrWritePipe));
RETURN_LAST_ERROR_IF(!SetStdHandle(STD_OUTPUT_HANDLE, hStdErrWritePipe));
m_hErrReadPipe = hStdErrReadPipe; m_hErrReadPipe = hStdErrReadPipe;
m_hErrWritePipe = hStdErrWritePipe; m_hErrWritePipe = hStdErrWritePipe;
// Read the stderr handle on a separate thread until we get 4096 bytes. stdoutWrapper = std::make_unique<StdWrapper>(stdout, STD_OUTPUT_HANDLE, hStdErrWritePipe, m_fEnableNativeRedirection);
stderrWrapper = std::make_unique<StdWrapper>(stderr, STD_ERROR_HANDLE, hStdErrWritePipe, m_fEnableNativeRedirection);
LOG_IF_FAILED(stdoutWrapper->StartRedirection());
LOG_IF_FAILED(stderrWrapper->StartRedirection());
// Read the stderr handle on a separate thread until we get 30Kb.
m_hErrThread = CreateThread( m_hErrThread = CreateThread(
NULL, // default security attributes nullptr, // default security attributes
0, // default stack size 0, // default stack size
(LPTHREAD_START_ROUTINE)ReadStdErrHandle, reinterpret_cast<LPTHREAD_START_ROUTINE>(ReadStdErrHandle),
this, // thread function arguments this, // thread function arguments
0, // default creation flags 0, // default creation flags
NULL); // receive thread identifier nullptr); // receive thread identifier
RETURN_LAST_ERROR_IF_NULL(m_hErrThread); RETURN_LAST_ERROR_IF_NULL(m_hErrThread);
return S_OK; return S_OK;
} }
// Stop redirecting stdout and stderr into a pipe
// This closes the background thread reading from the pipe
// and prints any output that was captured in the pipe.
// If more than 30Kb was written to the pipe, that output will
// be thrown away.
HRESULT PipeOutputManager::Stop() HRESULT PipeOutputManager::Stop()
{ {
DWORD dwThreadStatus = 0; DWORD dwThreadStatus = 0;
@ -71,57 +82,53 @@ HRESULT PipeOutputManager::Stop()
{ {
return S_OK; return S_OK;
} }
SRWExclusiveLock lock(m_srwLock); SRWExclusiveLock lock(m_srwLock);
if (m_disposed) if (m_disposed)
{ {
return S_OK; return S_OK;
} }
m_disposed = true; m_disposed = true;
fflush(stdout); // Both pipe wrappers duplicate the pipe writer handle
fflush(stderr); // meaning we are fine to close the handle too.
// Restore the original stdout and stderr handles of the process,
// as the application has either finished startup or has exited.
// If stdout/stderr were not set, we need to set it to NUL:
// such that other calls to Console.WriteLine don't use an invalid handle
FILE *stream;
if (m_fdPreviousStdOut >= 0)
{
LOG_LAST_ERROR_IF(SetStdHandle(STD_OUTPUT_HANDLE, (HANDLE)_get_osfhandle(m_fdPreviousStdOut)));
}
else
{
LOG_IF_ERRNO(freopen_s(&stream, "NUL:", "w", stdout));
}
if (m_fdPreviousStdErr >= 0)
{
LOG_LAST_ERROR_IF(SetStdHandle(STD_ERROR_HANDLE, (HANDLE)_get_osfhandle(m_fdPreviousStdErr)));
}
else
{
LOG_IF_ERRNO(freopen_s(&stream, "NUL:", "w", stderr));
}
if (m_hErrWritePipe != INVALID_HANDLE_VALUE) if (m_hErrWritePipe != INVALID_HANDLE_VALUE)
{ {
// Flush the pipe writer before closing to capture all output
RETURN_LAST_ERROR_IF(!FlushFileBuffers(m_hErrWritePipe));
CloseHandle(m_hErrWritePipe); CloseHandle(m_hErrWritePipe);
m_hErrWritePipe = INVALID_HANDLE_VALUE; m_hErrWritePipe = INVALID_HANDLE_VALUE;
} }
// Tell each pipe wrapper to stop redirecting output and restore the original values
if (stdoutWrapper != nullptr)
{
LOG_IF_FAILED(stdoutWrapper->StopRedirection());
}
if (stderrWrapper != nullptr)
{
LOG_IF_FAILED(stderrWrapper->StopRedirection());
}
// Forces ReadFile to cancel, causing the read loop to complete.
// Don't check return value as IO may or may not be completed already.
if (m_hErrThread != nullptr)
{
CancelSynchronousIo(m_hErrThread);
}
// GetExitCodeThread returns 0 on failure; thread status code is invalid. // GetExitCodeThread returns 0 on failure; thread status code is invalid.
if (m_hErrThread != NULL && if (m_hErrThread != nullptr &&
!LOG_LAST_ERROR_IF(GetExitCodeThread(m_hErrThread, &dwThreadStatus) == 0) && !LOG_LAST_ERROR_IF(GetExitCodeThread(m_hErrThread, &dwThreadStatus) == 0) &&
dwThreadStatus == STILL_ACTIVE) dwThreadStatus == STILL_ACTIVE)
{ {
// wait for graceful shutdown, i.e., the exit of the background thread or timeout // Wait for graceful shutdown, i.e., the exit of the background thread or timeout
if (WaitForSingleObject(m_hErrThread, PIPE_OUTPUT_THREAD_TIMEOUT) != WAIT_OBJECT_0) if (WaitForSingleObject(m_hErrThread, PIPE_OUTPUT_THREAD_TIMEOUT) != WAIT_OBJECT_0)
{ {
// if the thread is still running, we need kill it first before exit to avoid AV // If the thread is still running, we need kill it first before exit to avoid AV
if (!LOG_LAST_ERROR_IF(GetExitCodeThread(m_hErrThread, &dwThreadStatus) == 0) && if (!LOG_LAST_ERROR_IF(GetExitCodeThread(m_hErrThread, &dwThreadStatus) == 0) &&
dwThreadStatus == STILL_ACTIVE) dwThreadStatus == STILL_ACTIVE)
{ {
@ -131,42 +138,38 @@ HRESULT PipeOutputManager::Stop()
} }
} }
if (m_hErrThread != NULL) if (m_hErrThread != nullptr)
{ {
CloseHandle(m_hErrThread); CloseHandle(m_hErrThread);
m_hErrThread = NULL; m_hErrThread = nullptr;
} }
if (m_hErrReadPipe != INVALID_HANDLE_VALUE) if (m_hErrReadPipe != INVALID_HANDLE_VALUE)
{ {
CloseHandle(m_hErrReadPipe); CloseHandle(m_hErrReadPipe);
m_hErrReadPipe = INVALID_HANDLE_VALUE; m_hErrReadPipe = INVALID_HANDLE_VALUE;
} }
// If we captured any output, relog it to the original stdout
// Useful for the IIS Express scenario as it is running with stdout and stderr
if (GetStdOutContent(&straStdOutput)) if (GetStdOutContent(&straStdOutput))
{ {
printf(straStdOutput.QueryStr()); // printf will fail in in full IIS
// Need to flush contents for the new stdout and stderr if (printf(straStdOutput.QueryStr()) != -1)
_flushall(); {
// Need to flush contents for the new stdout and stderr
_flushall();
}
} }
return S_OK; return S_OK;
} }
VOID
PipeOutputManager::ReadStdErrHandle(
LPVOID pContext
)
{
PipeOutputManager *pLoggingProvider = (PipeOutputManager*)pContext;
DBG_ASSERT(pLoggingProvider != NULL);
pLoggingProvider->ReadStdErrHandleInternal();
}
bool PipeOutputManager::GetStdOutContent(STRA* straStdOutput) bool PipeOutputManager::GetStdOutContent(STRA* straStdOutput)
{ {
bool fLogged = false; bool fLogged = false;
// TODO consider returning the file contents rather than copying.
if (m_dwStdErrReadTotal > 0) if (m_dwStdErrReadTotal > 0)
{ {
if (SUCCEEDED(straStdOutput->Copy(m_pzFileContents, m_dwStdErrReadTotal))) if (SUCCEEDED(straStdOutput->Copy(m_pzFileContents, m_dwStdErrReadTotal)))
@ -178,15 +181,29 @@ bool PipeOutputManager::GetStdOutContent(STRA* straStdOutput)
return fLogged; return fLogged;
} }
VOID void
PipeOutputManager::ReadStdErrHandleInternal( PipeOutputManager::ReadStdErrHandle(
VOID LPVOID pContext
) )
{ {
auto pLoggingProvider = static_cast<PipeOutputManager*>(pContext);
DBG_ASSERT(pLoggingProvider != NULL);
pLoggingProvider->ReadStdErrHandleInternal();
}
void
PipeOutputManager::ReadStdErrHandleInternal()
{
// If ReadFile ever returns false, exit the thread
DWORD dwNumBytesRead = 0; DWORD dwNumBytesRead = 0;
while (true) while (true)
{ {
if (ReadFile(m_hErrReadPipe, &m_pzFileContents[m_dwStdErrReadTotal], MAX_PIPE_READ_SIZE - m_dwStdErrReadTotal, &dwNumBytesRead, NULL)) // Fill a maximum of MAX_PIPE_READ_SIZE into a buffer.
if (ReadFile(m_hErrReadPipe,
&m_pzFileContents[m_dwStdErrReadTotal],
MAX_PIPE_READ_SIZE - m_dwStdErrReadTotal,
&dwNumBytesRead,
nullptr))
{ {
m_dwStdErrReadTotal += dwNumBytesRead; m_dwStdErrReadTotal += dwNumBytesRead;
if (m_dwStdErrReadTotal >= MAX_PIPE_READ_SIZE) if (m_dwStdErrReadTotal >= MAX_PIPE_READ_SIZE)
@ -194,19 +211,21 @@ PipeOutputManager::ReadStdErrHandleInternal(
break; break;
} }
} }
else if (GetLastError() == ERROR_BROKEN_PIPE) else
{ {
return; return;
} }
} }
char tempBuffer[MAX_PIPE_READ_SIZE]; // Using std::string as a wrapper around new char[] so we don't need to call delete
// Also don't allocate on stack as stack size is 128KB by default.
std::string tempBuffer;
tempBuffer.resize(MAX_PIPE_READ_SIZE);
// After reading the maximum amount of data, keep reading in a loop until Stop is called on the output manager.
while (true) while (true)
{ {
if (ReadFile(m_hErrReadPipe, tempBuffer, MAX_PIPE_READ_SIZE, &dwNumBytesRead, NULL)) if (!ReadFile(m_hErrReadPipe, tempBuffer.data(), MAX_PIPE_READ_SIZE, &dwNumBytesRead, nullptr))
{
}
else if (GetLastError() == ERROR_BROKEN_PIPE)
{ {
return; return;
} }

View File

@ -4,35 +4,41 @@
#pragma once #pragma once
#include "IOutputManager.h" #include "IOutputManager.h"
#include "StdWrapper.h"
#include "stringu.h"
class PipeOutputManager : public IOutputManager class PipeOutputManager : public IOutputManager
{ {
// Timeout to be used if a thread never exits
#define PIPE_OUTPUT_THREAD_TIMEOUT 2000 #define PIPE_OUTPUT_THREAD_TIMEOUT 2000
#define MAX_PIPE_READ_SIZE 4096
// Max event log message is ~32KB, limit pipe size just below that.
#define MAX_PIPE_READ_SIZE 30000
public: public:
PipeOutputManager(); PipeOutputManager();
PipeOutputManager(bool fEnableNativeLogging);
~PipeOutputManager(); ~PipeOutputManager();
virtual HRESULT Start() override; HRESULT Start() override;
virtual HRESULT Stop() override; HRESULT Stop() override;
virtual bool GetStdOutContent(STRA* struStdOutput) override; bool GetStdOutContent(STRA* straStdOutput) override;
// Thread functions // Thread functions
VOID ReadStdErrHandleInternal(VOID); void ReadStdErrHandleInternal();
static static void ReadStdErrHandle(LPVOID pContext);
VOID ReadStdErrHandle(LPVOID pContext);
private: private:
HANDLE m_hErrReadPipe; HANDLE m_hErrReadPipe;
HANDLE m_hErrWritePipe; HANDLE m_hErrWritePipe;
STRU m_struLogFilePath; STRU m_struLogFilePath;
HANDLE m_hErrThread; HANDLE m_hErrThread;
CHAR m_pzFileContents[MAX_PIPE_READ_SIZE] = { 0 }; CHAR m_pzFileContents[MAX_PIPE_READ_SIZE] = { 0 };
DWORD m_dwStdErrReadTotal; DWORD m_dwStdErrReadTotal;
SRWLOCK m_srwLock; SRWLOCK m_srwLock {};
int m_fdPreviousStdOut;
int m_fdPreviousStdErr;
BOOL m_disposed; BOOL m_disposed;
BOOL m_fEnableNativeRedirection;
std::unique_ptr<StdWrapper> stdoutWrapper;
std::unique_ptr<StdWrapper> stderrWrapper;
}; };

View File

@ -0,0 +1,148 @@
// 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 "StdWrapper.h"
#include "exceptions.h"
#include "LoggingHelpers.h"
#include <corecrt_io.h>
#include <fcntl.h>
StdWrapper::StdWrapper(FILE* stdStream, DWORD stdHandleNumber, HANDLE handleToRedirectTo, BOOL fEnableNativeRedirection)
: m_previousFileDescriptor(0),
m_stdStream(stdStream),
m_stdHandleNumber(stdHandleNumber),
m_fEnableNativeRedirection(fEnableNativeRedirection),
m_handleToRedirectTo(handleToRedirectTo),
m_redirectedFile(nullptr)
{
}
StdWrapper::~StdWrapper() = default;
// Redirects stdout/stderr to the provided handle.
// Example:
// If the handleToRedirecTo = 0x24
// Before:
// _fileno(stdout) = 1
// GetStdHandle(STD_OUTPUT_HANDLE) = 0x20
// After:
// _fileno(stdout) = 3
// GetStdHandle(STD_OUTPUT_HANDLE) = 0x28 <- Duplicated from 0x24
HRESULT
StdWrapper::StartRedirection()
{
HANDLE stdHandle;
// In IIS, stdout and stderr are set to null as w3wp is created with DETACHED_PROCESS,
// so fileno(m_stdStream) returns -2.
// Open a null file such that undoing the redirection succeeds and _dup2 works.
// m_previousFileDescriptor will be used for restoring stdout/stderr
if (_fileno(m_stdStream) == -2)
{
freopen_s((FILE**)&m_stdStream, "nul", "w", m_stdStream);
m_previousFileDescriptor = _dup(_fileno(m_stdStream));
}
else
{
m_previousFileDescriptor = _dup(_fileno(m_stdStream));
}
if (!m_fEnableNativeRedirection)
{
RETURN_LAST_ERROR_IF(!SetStdHandle(m_stdHandleNumber, m_handleToRedirectTo));
return S_OK;
}
// After setting the std handle, we need to set stdout/stderr to the current
// output/error handle.
// Duplicate the handle before opening the handle and associating a file pointer.
// If we don't by calling close on the file, the same handle value will be closed
// multiple times.
// Note, by calling duplicate handle, the new handle returned will have a different value
// than the original, but point to the same underlying file object.
RETURN_LAST_ERROR_IF(!DuplicateHandle(
/* hSourceProcessHandle*/ GetCurrentProcess(),
/* hSourceHandle */ m_handleToRedirectTo,
/* hTargetProcessHandle */ GetCurrentProcess(),
/* lpTargetHandle */&stdHandle,
/* dwDesiredAccess */ 0, // dwDesired is ignored if DUPLICATE_SAME_ACCESS is specified
/* bInheritHandle */ TRUE,
/* dwOptions */ DUPLICATE_SAME_ACCESS));
RETURN_LAST_ERROR_IF(!SetStdHandle(m_stdHandleNumber, stdHandle));
// _open_osfhandle will associate a filedescriptor with the handle.
const auto fileDescriptor = _open_osfhandle(reinterpret_cast<intptr_t>(stdHandle), _O_WTEXT | _O_TEXT);
if (fileDescriptor == -1)
{
RETURN_IF_FAILED(HRESULT_FROM_WIN32(ERROR_FILE_INVALID));
}
m_redirectedFile = _fdopen(fileDescriptor, "w");
if (m_redirectedFile == nullptr)
{
RETURN_IF_FAILED(HRESULT_FROM_WIN32(ERROR_FILE_INVALID));
}
// Set stdout/stderr to the newly created file.
const auto dup2Result = _dup2(_fileno(m_redirectedFile), _fileno(m_stdStream));
if (dup2Result != 0)
{
RETURN_IF_FAILED(HRESULT_FROM_WIN32(ERROR_FILE_INVALID));
}
// Removes buffering from the output
if (setvbuf(m_stdStream, nullptr, _IONBF, 0) != 0)
{
RETURN_IF_FAILED(HRESULT_FROM_WIN32(ERROR_FILE_INVALID));
}
return S_OK;
}
// Redirects stdout/stderr back to the original stdout/stderr.
// Note, this will not restore the original handle values returned by GetStdHandle,
// rather a duplicated number. This is because the original handle value is invalid
// due to dup2 closing the file originally in stdout/stderr
HRESULT
StdWrapper::StopRedirection() const
{
// After setting the std handle, we need to set stdout/stderr to the current
// output/error handle.
FILE * file = _fdopen(m_previousFileDescriptor, "w");
if (file == nullptr)
{
RETURN_IF_FAILED(HRESULT_FROM_WIN32(ERROR_FILE_INVALID));
}
RETURN_LAST_ERROR_IF(!SetStdHandle(m_stdHandleNumber, reinterpret_cast<HANDLE>(_get_osfhandle(m_previousFileDescriptor))));
if (!m_fEnableNativeRedirection)
{
return S_OK;
}
// Set stdout/stderr to the newly created file output.
const auto dup2Result = _dup2(_fileno(file), _fileno(m_stdStream));
if (dup2Result != 0)
{
RETURN_IF_FAILED(HRESULT_FROM_WIN32(ERROR_FILE_INVALID));
}
if (setvbuf(m_stdStream, nullptr, _IONBF, 0) != 0)
{
RETURN_IF_FAILED(HRESULT_FROM_WIN32(ERROR_FILE_INVALID));
}
if (fclose(m_redirectedFile) != 0)
{
RETURN_IF_FAILED(HRESULT_FROM_WIN32(ERROR_FILE_INVALID));
}
return S_OK;
}

View File

@ -0,0 +1,25 @@
// 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 <cstdio>
// Wraps stdout/stderr stream, modifying them to redirect to the given handle
class StdWrapper
{
public:
StdWrapper(FILE* stdStream, DWORD stdHandleNumber, HANDLE handleToRedirectTo, BOOL fEnableNativeRedirection);
~StdWrapper();
HRESULT StartRedirection();
HRESULT StopRedirection() const;
private:
int m_previousFileDescriptor;
FILE* m_stdStream;
DWORD m_stdHandleNumber;
BOOL m_fEnableNativeRedirection;
HANDLE m_handleToRedirectTo;
FILE* m_redirectedFile;
};

View File

@ -177,19 +177,19 @@ Language=English
. .
Messageid=1025 Messageid=1025
SymbolicName=ASPNETCORE_EVENT_GENERAL_INFO_MSG SymbolicName=ASPNETCORE_EVENT_GENERAL_INFO
Language=English Language=English
%1 %1
. .
Messageid=1026 Messageid=1026
SymbolicName=ASPNETCORE_EVENT_GENERAL_WARNING_MSG SymbolicName=ASPNETCORE_EVENT_GENERAL_WARNING
Language=English Language=English
%1 %1
. .
Messageid=1027 Messageid=1027
SymbolicName=ASPNETCORE_EVENT_GENERAL_ERROR_MSG SymbolicName=ASPNETCORE_EVENT_GENERAL_ERROR
Language=English Language=English
%1 %1
. .

View File

@ -26,6 +26,8 @@
#endif #endif
#define OBSERVE_CAUGHT_EXCEPTION() CaughtExceptionHResult(LOCATION_INFO); #define OBSERVE_CAUGHT_EXCEPTION() CaughtExceptionHResult(LOCATION_INFO);
#define RETURN_HR(hr) do { HRESULT __hrRet = hr; if (FAILED(__hrRet)) { LogHResultFailed(LOCATION_INFO, __hrRet); } return __hrRet; } while (0, 0)
#define RETURN_LAST_ERROR() do { return LogLastError(LOCATION_INFO); } while (0, 0)
#define RETURN_IF_FAILED(hr) do { HRESULT __hrRet = hr; if (FAILED(__hrRet)) { LogHResultFailed(LOCATION_INFO, __hrRet); return __hrRet; }} while (0, 0) #define RETURN_IF_FAILED(hr) do { HRESULT __hrRet = hr; if (FAILED(__hrRet)) { LogHResultFailed(LOCATION_INFO, __hrRet); return __hrRet; }} while (0, 0)
#define RETURN_CAUGHT_EXCEPTION() return CaughtExceptionHResult(LOCATION_INFO); #define RETURN_CAUGHT_EXCEPTION() return CaughtExceptionHResult(LOCATION_INFO);
#define RETURN_LAST_ERROR_IF(condition) do { if (condition) { return LogLastError(LOCATION_INFO); }} while (0, 0) #define RETURN_LAST_ERROR_IF(condition) do { if (condition) { return LogLastError(LOCATION_INFO); }} while (0, 0)

View File

@ -17,7 +17,7 @@
#define ASPNETCORE_EVENT_PROCESS_START_ERROR_MSG L"Application '%s' with physical root '%s' failed to start process with commandline '%s' at stage '%s', ErrorCode = '0x%x', assigned port %d, retryCounter '%d'." #define ASPNETCORE_EVENT_PROCESS_START_ERROR_MSG L"Application '%s' with physical root '%s' failed to start process with commandline '%s' at stage '%s', ErrorCode = '0x%x', assigned port %d, retryCounter '%d'."
#define ASPNETCORE_EVENT_PROCESS_START_FAILURE_MSG L"Application '%s' with physical root '%s' failed to start process with commandline '%s' with multiple retries. The last try of listening port is '%d'. See previous warnings for details." #define ASPNETCORE_EVENT_PROCESS_START_FAILURE_MSG L"Application '%s' with physical root '%s' failed to start process with commandline '%s' with multiple retries. The last try of listening port is '%d'. See previous warnings for details."
#define ASPNETCORE_EVENT_PROCESS_START_STATUS_ERROR_MSG L"Application '%s' with physical root '%s' failed to start process with commandline '%s' , ErrorCode = '0x%x', processId '%d', processStatus '%d'." #define ASPNETCORE_EVENT_PROCESS_START_STATUS_ERROR_MSG L"Application '%s' with physical root '%s' failed to start process with commandline '%s' , ErrorCode = '0x%x', processId '%d', processStatus '%d'."
#define ASPNETCORE_EVENT_PROCESS_START_PORTSETUP_ERROR_MSG L"Application '%s' with physical root '%s' failed to choose listen port '%d' given port rang '%d - %d', EorrorCode = '0x%x'. If environment variable 'ASPNETCORE_PORT' was set, try removing it such that a random port is selected instead." #define ASPNETCORE_EVENT_PROCESS_START_PORTSETUP_ERROR_MSG L"Application '%s' with physical root '%s' failed to choose listen port '%d' given port range '%d - %d', ErrorCode = '0x%x'. If environment variable 'ASPNETCORE_PORT' was set, try removing it such that a random port is selected instead."
#define ASPNETCORE_EVENT_PROCESS_START_WRONGPORT_ERROR_MSG L"Application '%s' with physical root '%s' created process with commandline '%s' but failed to listen on the given port '%d'" #define ASPNETCORE_EVENT_PROCESS_START_WRONGPORT_ERROR_MSG L"Application '%s' with physical root '%s' created process with commandline '%s' but failed to listen on the given port '%d'"
#define ASPNETCORE_EVENT_PROCESS_START_NOTREADY_ERROR_MSG L"Application '%s' with physical root '%s' created process with commandline '%s' but either crashed or did not respond or did not listen on the given port '%d', ErrorCode = '0x%x'" #define ASPNETCORE_EVENT_PROCESS_START_NOTREADY_ERROR_MSG L"Application '%s' with physical root '%s' created process with commandline '%s' but either crashed or did not respond or did not listen on the given port '%d', ErrorCode = '0x%x'"
#define ASPNETCORE_EVENT_PROCESS_SHUTDOWN_MSG L"Application '%s' with physical root '%s' shut down process with Id '%d' listening on port '%d'" #define ASPNETCORE_EVENT_PROCESS_SHUTDOWN_MSG L"Application '%s' with physical root '%s' shut down process with Id '%d' listening on port '%d'"
@ -31,8 +31,8 @@
#define ASPNETCORE_EVENT_MIXED_HOSTING_MODEL_ERROR_MSG L"Mixed hosting model is not supported. Application '%s' configured with different hostingModel value '%d' other than the one of running application(s)." #define ASPNETCORE_EVENT_MIXED_HOSTING_MODEL_ERROR_MSG L"Mixed hosting model is not supported. Application '%s' configured with different hostingModel value '%d' other than the one of running application(s)."
#define ASPNETCORE_EVENT_UNKNOWN_HOSTING_MODEL_ERROR_MSG L"Unknown hosting model '%s'. Please specify either hostingModel=\"inprocess\" or hostingModel=\"outofprocess\" in the web.config file." #define ASPNETCORE_EVENT_UNKNOWN_HOSTING_MODEL_ERROR_MSG L"Unknown hosting model '%s'. Please specify either hostingModel=\"inprocess\" or hostingModel=\"outofprocess\" in the web.config file."
#define ASPNETCORE_EVENT_ADD_APPLICATION_ERROR_MSG L"Failed to start application '%s', ErrorCode '0x%x'." #define ASPNETCORE_EVENT_ADD_APPLICATION_ERROR_MSG L"Failed to start application '%s', ErrorCode '0x%x'."
#define ASPNETCORE_EVENT_INPROCESS_THREAD_EXIT_STDOUT_MSG L"Application '%s' with physical root '%s' hit unexpected managed background thread exit, ErrorCode = '0x%x. Last 4KB characters of captured stdout and stderr logs:\r\n%s" #define ASPNETCORE_EVENT_INPROCESS_THREAD_EXIT_STDOUT_MSG L"Application '%s' with physical root '%s' hit unexpected managed background thread exit, ErrorCode = '0x%x'. Last 4KB characters of captured stdout and stderr logs:\r\n%s"
#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_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_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_MSG L"Application '%s' was recycled after detecting the app_offline file."
#define ASPNETCORE_EVENT_MONITOR_APPOFFLINE_ERROR_MSG L"Monitoring app_offline.htm failed for application '%s', ErrorCode '0x%x'. " #define ASPNETCORE_EVENT_MONITOR_APPOFFLINE_ERROR_MSG L"Monitoring app_offline.htm failed for application '%s', ErrorCode '0x%x'. "
@ -43,9 +43,11 @@
#define ASPNETCORE_EVENT_PORTABLE_APP_DOTNET_MISSING_MSG L"Could not find dotnet.exe on the system PATH environment variable for portable application '%s'. Check that a valid path to dotnet is on the PATH and the bitness of dotnet matches the bitness of the IIS worker process. ErrorCode = '0x%x'." #define ASPNETCORE_EVENT_PORTABLE_APP_DOTNET_MISSING_MSG L"Could not find dotnet.exe on the system PATH environment variable for portable application '%s'. Check that a valid path to dotnet is on the PATH and the bitness of dotnet matches the bitness of the IIS worker process. ErrorCode = '0x%x'."
#define ASPNETCORE_EVENT_HOSTFXR_DIRECTORY_NOT_FOUND_MSG L"Could not find the hostfxr directory '%s' in the dotnet directory. ErrorCode = '0x%x'." #define ASPNETCORE_EVENT_HOSTFXR_DIRECTORY_NOT_FOUND_MSG L"Could not find the hostfxr directory '%s' in the dotnet directory. ErrorCode = '0x%x'."
#define ASPNETCORE_EVENT_HOSTFXR_DLL_NOT_FOUND_MSG L"Could not find hostfxr.dll in '%s'. ErrorCode = '0x%x'." #define ASPNETCORE_EVENT_HOSTFXR_DLL_NOT_FOUND_MSG L"Could not find hostfxr.dll in '%s'. ErrorCode = '0x%x'."
#define ASPNETCORE_EVENT_HOSTFXR_DLL_INVALID_VERSION_MSG L"Hostfxr version used does not support 'hostfxr_get_native_search_directories', update the version of hostfxr to a higher version. Path to hostfxr: '%s'."
#define ASPNETCORE_EVENT_APPLICATION_EXE_NOT_FOUND_LEVEL EVENTLOG_ERROR_TYPE
#define ASPNETCORE_EVENT_APPLICATION_EXE_NOT_FOUND_MSG L"Could not find application executable in '%s'. ErrorCode = '0x%x'." #define ASPNETCORE_EVENT_APPLICATION_EXE_NOT_FOUND_MSG L"Could not find application executable in '%s'. ErrorCode = '0x%x'."
#define ASPNETCORE_EVENT_INPROCESS_THREAD_EXCEPTION_MSG L"Application '%s' with physical root '%s' hit unexpected managed exception, ErrorCode = '0x%x. Please check the stderr logs for more information." #define ASPNETCORE_EVENT_INPROCESS_THREAD_EXCEPTION_MSG L"Application '%s' with physical root '%s' hit unexpected managed exception, ErrorCode = '0x%x. Please check the stderr logs for more information."
#define ASPNETCORE_EVENT_INVALID_PROCESS_PATH_MSG L"Invalid or unknown processPath provided in web.config: processPath = '%s', ErrorCode = '0x%x'." #define ASPNETCORE_EVENT_INVALID_PROCESS_PATH_MSG L"Invalid or unknown processPath provided in web.config: processPath = '%s', ErrorCode = '0x%x'."
#define ASPNETCORE_EVENT_INPROCESS_RH_MISSING_MSG L"Could not find the assembly '%s' for in-process application. Please confirm the Microsoft.AspNetCore.Server.IIS package is referenced in your application." #define ASPNETCORE_EVENT_INPROCESS_RH_ERROR_MSG L"Could not find the assembly '%s' for in-process application. Please confirm the Microsoft.AspNetCore.Server.IIS package is referenced in your application. Captured output: %s"
#define ASPNETCORE_EVENT_OUT_OF_PROCESS_RH_MISSING_MSG L"Could not find the assembly '%s' for out-of-process application. Please confirm the assembly is installed correctly for IIS or IISExpress." #define ASPNETCORE_EVENT_OUT_OF_PROCESS_RH_MISSING_MSG L"Could not find the assembly '%s' for out-of-process application. Please confirm the assembly is installed correctly for IIS or IISExpress."
#define ASPNETCORE_EVENT_INPROCESS_START_SUCCESS_MSG L"Application '%s' started the coreclr in-process successfully." #define ASPNETCORE_EVENT_INPROCESS_START_SUCCESS_MSG L"Application '%s' started the coreclr in-process successfully."

View File

@ -6,6 +6,7 @@
#ifndef _STTIMER_H #ifndef _STTIMER_H
#define _STTIMER_H #define _STTIMER_H
#include "stringu.h"
class STTIMER class STTIMER
{ {

View File

@ -102,12 +102,6 @@ IN_PROCESS_APPLICATION::StopInternal(bool fServerInitiated)
} }
} }
if (m_pLoggerProvider != NULL)
{
delete m_pLoggerProvider;
m_pLoggerProvider = NULL;
}
Finished: Finished:
if (FAILED(hr)) if (FAILED(hr))
@ -256,24 +250,7 @@ IN_PROCESS_APPLICATION::LoadManagedApplication
} }
{ {
// Set up stdout redirect
SRWExclusiveLock lock(m_stateLock); SRWExclusiveLock lock(m_stateLock);
if (m_pLoggerProvider == NULL)
{
hr = LoggingHelpers::CreateLoggingProvider(
m_pConfig->QueryStdoutLogEnabled(),
!GetConsoleWindow(),
m_pConfig->QueryStdoutLogFile()->QueryStr(),
m_pConfig->QueryApplicationPhysicalPath()->QueryStr(),
&m_pLoggerProvider);
if (FAILED(hr))
{
goto Finished;
}
LOG_IF_FAILED(m_pLoggerProvider->Start());
}
if (m_status != MANAGED_APPLICATION_STATUS::STARTING) if (m_status != MANAGED_APPLICATION_STATUS::STARTING)
{ {
@ -461,6 +438,20 @@ IN_PROCESS_APPLICATION::ExecuteApplication(
FINISHED_IF_FAILED(SetEnvironementVariablesOnWorkerProcess()); FINISHED_IF_FAILED(SetEnvironementVariablesOnWorkerProcess());
} }
LOG_INFO("Starting managed application");
if (m_pLoggerProvider == NULL)
{
FINISHED_IF_FAILED(hr = LoggingHelpers::CreateLoggingProvider(
m_pConfig->QueryStdoutLogEnabled(),
!m_pHttpServer.IsCommandLineLaunch(),
m_pConfig->QueryStdoutLogFile()->QueryStr(),
m_pConfig->QueryApplicationPhysicalPath()->QueryStr(),
m_pLoggerProvider));
LOG_IF_FAILED(m_pLoggerProvider->Start());
}
// There can only ever be a single instance of .NET Core // There can only ever be a single instance of .NET Core
// loaded in the process but we need to get config information to boot it up in the // loaded in the process but we need to get config information to boot it up in the
// first place. This is happening in an execute request handler and everyone waits // first place. This is happening in an execute request handler and everyone waits
@ -482,7 +473,7 @@ Finished:
// //
m_status = MANAGED_APPLICATION_STATUS::SHUTDOWN; m_status = MANAGED_APPLICATION_STATUS::SHUTDOWN;
m_fShutdownCalledFromManaged = TRUE; m_fShutdownCalledFromManaged = TRUE;
FreeLibrary(hModule);
m_pLoggerProvider->Stop(); m_pLoggerProvider->Stop();
if (!m_fShutdownCalledFromNative) if (!m_fShutdownCalledFromNative)
@ -545,7 +536,6 @@ IN_PROCESS_APPLICATION::RunDotnetApplication(DWORD argc, CONST PCWSTR* argv, hos
__try __try
{ {
LOG_INFO("Starting managed application");
m_ProcessExitCode = pProc(argc, argv); m_ProcessExitCode = pProc(argc, argv);
if (m_ProcessExitCode != 0) if (m_ProcessExitCode != 0)
{ {

View File

@ -150,7 +150,7 @@ private:
static IN_PROCESS_APPLICATION* s_Application; static IN_PROCESS_APPLICATION* s_Application;
IOutputManager* m_pLoggerProvider; std::unique_ptr<IOutputManager> m_pLoggerProvider;
static const LPCSTR s_exeLocationParameterName; static const LPCSTR s_exeLocationParameterName;

View File

@ -224,7 +224,6 @@
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="aspnetcore_event.h" />
<ClInclude Include="disconnectcontext.h" /> <ClInclude Include="disconnectcontext.h" />
<ClInclude Include="environmentvariablehelpers.h" /> <ClInclude Include="environmentvariablehelpers.h" />
<ClInclude Include="forwarderconnection.h" /> <ClInclude Include="forwarderconnection.h" />

View File

@ -121,28 +121,29 @@ EnsureOutOfProcessInitializtion()
DBG_ASSERT(g_pHttpServer); DBG_ASSERT(g_pHttpServer);
HRESULT hr = S_OK; HRESULT hr = S_OK;
BOOL fLocked = FALSE;
if (g_fOutOfProcessInitializeError) if (g_fOutOfProcessInitializeError)
{ {
hr = E_NOT_VALID_STATE; FINISHED(E_NOT_VALID_STATE);
goto Finished;
} }
if (!g_fOutOfProcessInitialize) if (g_fOutOfProcessInitialize)
{ {
AcquireSRWLockExclusive(&g_srwLockRH); FINISHED(S_OK);
fLocked = TRUE; }
{
auto lock = SRWExclusiveLock(g_srwLockRH);
if (g_fOutOfProcessInitializeError) if (g_fOutOfProcessInitializeError)
{ {
hr = E_NOT_VALID_STATE; FINISHED(E_NOT_VALID_STATE);
goto Finished;
} }
if (g_fOutOfProcessInitialize) if (g_fOutOfProcessInitialize)
{ {
// Done by another thread // Done by another thread
goto Finished; FINISHED(S_OK);
} }
g_hWinHttpModule = GetModuleHandle(TEXT("winhttp.dll")); g_hWinHttpModule = GetModuleHandle(TEXT("winhttp.dll"));
@ -150,7 +151,7 @@ EnsureOutOfProcessInitializtion()
g_hAspNetCoreModule = GetModuleHandle(TEXT("aspnetcorev2.dll")); g_hAspNetCoreModule = GetModuleHandle(TEXT("aspnetcorev2.dll"));
hr = WINHTTP_HELPER::StaticInitialize(); hr = WINHTTP_HELPER::StaticInitialize();
if (FAILED(hr)) if (FAILED_LOG(hr))
{ {
if (hr == HRESULT_FROM_WIN32(ERROR_PROC_NOT_FOUND)) if (hr == HRESULT_FROM_WIN32(ERROR_PROC_NOT_FOUND))
{ {
@ -158,7 +159,7 @@ EnsureOutOfProcessInitializtion()
} }
else else
{ {
goto Finished; FINISHED(hr);
} }
} }
@ -167,11 +168,7 @@ EnsureOutOfProcessInitializtion()
WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_NAME,
WINHTTP_NO_PROXY_BYPASS, WINHTTP_NO_PROXY_BYPASS,
WINHTTP_FLAG_ASYNC); WINHTTP_FLAG_ASYNC);
if (g_hWinhttpSession == NULL) FINISHED_LAST_ERROR_IF(g_hWinhttpSession == NULL);
{
hr = HRESULT_FROM_WIN32(GetLastError());
goto Finished;
}
// //
// Don't set non-blocking callbacks WINHTTP_OPTION_ASSURED_NON_BLOCKING_CALLBACKS, // Don't set non-blocking callbacks WINHTTP_OPTION_ASSURED_NON_BLOCKING_CALLBACKS,
@ -182,65 +179,33 @@ EnsureOutOfProcessInitializtion()
// //
// Setup the callback function // Setup the callback function
// //
if (WinHttpSetStatusCallback(g_hWinhttpSession, FINISHED_LAST_ERROR_IF(WinHttpSetStatusCallback(g_hWinhttpSession,
FORWARDING_HANDLER::OnWinHttpCompletion, FORWARDING_HANDLER::OnWinHttpCompletion,
(WINHTTP_CALLBACK_FLAG_ALL_COMPLETIONS | (WINHTTP_CALLBACK_FLAG_ALL_COMPLETIONS |
WINHTTP_CALLBACK_STATUS_SENDING_REQUEST), WINHTTP_CALLBACK_STATUS_SENDING_REQUEST),
NULL) == WINHTTP_INVALID_STATUS_CALLBACK) NULL) == WINHTTP_INVALID_STATUS_CALLBACK);
{
hr = HRESULT_FROM_WIN32(GetLastError());
goto Finished;
}
// //
// Make sure we see the redirects (rather than winhttp doing it // Make sure we see the redirects (rather than winhttp doing it
// automatically) // automatically)
// //
DWORD dwRedirectOption = WINHTTP_OPTION_REDIRECT_POLICY_NEVER; DWORD dwRedirectOption = WINHTTP_OPTION_REDIRECT_POLICY_NEVER;
if (!WinHttpSetOption(g_hWinhttpSession, FINISHED_LAST_ERROR_IF(!WinHttpSetOption(g_hWinhttpSession,
WINHTTP_OPTION_REDIRECT_POLICY, WINHTTP_OPTION_REDIRECT_POLICY,
&dwRedirectOption, &dwRedirectOption,
sizeof(dwRedirectOption))) sizeof(dwRedirectOption)));
{
hr = HRESULT_FROM_WIN32(GetLastError());
goto Finished;
}
g_dwTlsIndex = TlsAlloc(); g_dwTlsIndex = TlsAlloc();
if (g_dwTlsIndex == TLS_OUT_OF_INDEXES) FINISHED_LAST_ERROR_IF(g_dwTlsIndex == TLS_OUT_OF_INDEXES);
{ FINISHED_IF_FAILED(ALLOC_CACHE_HANDLER::StaticInitialize());
hr = HRESULT_FROM_WIN32(GetLastError()); FINISHED_IF_FAILED(FORWARDING_HANDLER::StaticInitialize(g_fEnableReferenceCountTracing));
goto Finished; FINISHED_IF_FAILED(WEBSOCKET_HANDLER::StaticInitialize(g_fEnableReferenceCountTracing));
}
hr = ALLOC_CACHE_HANDLER::StaticInitialize();
if (FAILED(hr))
{
goto Finished;
}
hr = FORWARDING_HANDLER::StaticInitialize(g_fEnableReferenceCountTracing);
if (FAILED(hr))
{
goto Finished;
}
hr = WEBSOCKET_HANDLER::StaticInitialize(g_fEnableReferenceCountTracing);
if (FAILED(hr))
{
goto Finished;
}
} }
Finished: Finished:
if (FAILED(hr)) if (FAILED(hr))
{ {
g_fOutOfProcessInitializeError = TRUE; g_fOutOfProcessInitializeError = TRUE;
} }
if (fLocked)
{
ReleaseSRWLockExclusive(&g_srwLockRH);
}
return hr; return hr;
} }

View File

@ -2,6 +2,7 @@
// Licensed under the MIT License. See License.txt in the project root for license information. // Licensed under the MIT License. See License.txt in the project root for license information.
#include "forwarderconnection.h" #include "forwarderconnection.h"
#include "exceptions.h"
FORWARDER_CONNECTION::FORWARDER_CONNECTION( FORWARDER_CONNECTION::FORWARDER_CONNECTION(
VOID VOID
@ -15,38 +16,19 @@ FORWARDER_CONNECTION::Initialize(
DWORD dwPort DWORD dwPort
) )
{ {
HRESULT hr = S_OK; RETURN_IF_FAILED(m_ConnectionKey.Initialize( dwPort ));
hr = m_ConnectionKey.Initialize( dwPort );
if ( FAILED( hr ) )
{
goto Finished;
}
m_hConnection = WinHttpConnect(g_hWinhttpSession, m_hConnection = WinHttpConnect(g_hWinhttpSession,
L"127.0.0.1", L"127.0.0.1",
(USHORT) dwPort, (USHORT) dwPort,
0); 0);
if (m_hConnection == NULL) RETURN_LAST_ERROR_IF_NULL(m_hConnection);
{
hr = HRESULT_FROM_WIN32(GetLastError());
goto Finished;
}
// //
// Since WinHttp will not emit WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING // Since WinHttp will not emit WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING
// when closing WebSocket handle on Win8. Register callback at Connect level as a workaround // when closing WebSocket handle on Win8. Register callback at Connect level as a workaround
// //
if (WinHttpSetStatusCallback(m_hConnection, RETURN_LAST_ERROR_IF (WinHttpSetStatusCallback(m_hConnection,
FORWARDING_HANDLER::OnWinHttpCompletion, FORWARDING_HANDLER::OnWinHttpCompletion,
WINHTTP_CALLBACK_FLAG_HANDLES, WINHTTP_CALLBACK_FLAG_HANDLES,
NULL) == WINHTTP_INVALID_STATUS_CALLBACK) NULL) == WINHTTP_INVALID_STATUS_CALLBACK);
{ return S_OK;
hr = HRESULT_FROM_WIN32(GetLastError());
goto Finished;
}
Finished:
return hr;
} }

View File

@ -3,6 +3,7 @@
#include "forwardinghandler.h" #include "forwardinghandler.h"
#include "url_utility.h" #include "url_utility.h"
#include "exceptions.h"
// Just to be aware of the FORWARDING_HANDLER object size. // Just to be aware of the FORWARDING_HANDLER object size.
C_ASSERT(sizeof(FORWARDING_HANDLER) <= 632); C_ASSERT(sizeof(FORWARDING_HANDLER) <= 632);
@ -140,7 +141,7 @@ FORWARDING_HANDLER::OnExecuteRequestHandler()
} }
hr = pApplication->GetProcess(&pServerProcess); hr = pApplication->GetProcess(&pServerProcess);
if (FAILED(hr)) if (FAILED_LOG(hr))
{ {
fFailedToStartKestrel = TRUE; fFailedToStartKestrel = TRUE;
goto Failure; goto Failure;
@ -165,7 +166,7 @@ FORWARDING_HANDLER::OnExecuteRequestHandler()
// //
// parse original url // parse original url
// //
if (FAILED(hr = URL_UTILITY::SplitUrl(pRequest->GetRawHttpRequest()->CookedUrl.pFullUrl, if (FAILED_LOG(hr = URL_UTILITY::SplitUrl(pRequest->GetRawHttpRequest()->CookedUrl.pFullUrl,
&fSecure, &fSecure,
&strDestination, &strDestination,
&strUrl))) &strUrl)))
@ -173,7 +174,7 @@ FORWARDING_HANDLER::OnExecuteRequestHandler()
goto Failure; goto Failure;
} }
if (FAILED(hr = URL_UTILITY::EscapeAbsPath(pRequest, &struEscapedUrl))) if (FAILED_LOG(hr = URL_UTILITY::EscapeAbsPath(pRequest, &struEscapedUrl)))
{ {
goto Failure; goto Failure;
} }
@ -200,7 +201,7 @@ FORWARDING_HANDLER::OnExecuteRequestHandler()
hConnect, hConnect,
&struEscapedUrl, &struEscapedUrl,
pServerProcess); pServerProcess);
if (FAILED(hr)) if (FAILED_LOG(hr))
{ {
goto Failure; goto Failure;
} }
@ -222,7 +223,7 @@ FORWARDING_HANDLER::OnExecuteRequestHandler()
SetConnectionModuleContext(m_pDisconnect, SetConnectionModuleContext(m_pDisconnect,
m_pModuleId); m_pModuleId);
DBG_ASSERT(hr != HRESULT_FROM_WIN32(ERROR_ALREADY_ASSIGNED)); DBG_ASSERT(hr != HRESULT_FROM_WIN32(ERROR_ALREADY_ASSIGNED));
if (FAILED(hr)) if (FAILED_LOG(hr))
{ {
goto Failure; goto Failure;
} }
@ -477,7 +478,7 @@ REQUEST_NOTIFICATION_STATUS
InterlockedIncrement(&m_dwHandlers); InterlockedIncrement(&m_dwHandlers);
} }
if (FAILED(hr)) if (FAILED_LOG(hr))
{ {
// This failure could happen when client disconnect happens or backend server fails // This failure could happen when client disconnect happens or backend server fails
// after websocket upgrade // after websocket upgrade
@ -514,7 +515,7 @@ REQUEST_NOTIFICATION_STATUS
// failure, if there is more data available from WinHTTP, read it // failure, if there is more data available from WinHTTP, read it
// or else ask if there is more. // or else ask if there is more.
// //
if (FAILED(hrCompletionStatus)) if (FAILED_LOG(hrCompletionStatus))
{ {
hr = hrCompletionStatus; hr = hrCompletionStatus;
fClientError = TRUE; fClientError = TRUE;
@ -522,7 +523,7 @@ REQUEST_NOTIFICATION_STATUS
} }
hr = OnReceivingResponse(); hr = OnReceivingResponse();
if (FAILED(hr)) if (FAILED_LOG(hr))
{ {
goto Failure; goto Failure;
} }
@ -533,7 +534,7 @@ REQUEST_NOTIFICATION_STATUS
hr = OnSendingRequest(cbCompletion, hr = OnSendingRequest(cbCompletion,
hrCompletionStatus, hrCompletionStatus,
&fClientError); &fClientError);
if (FAILED(hr)) if (FAILED_LOG(hr))
{ {
goto Failure; goto Failure;
} }
@ -730,7 +731,7 @@ HRESULT
hr = sm_pAlloc->Initialize(sizeof(FORWARDING_HANDLER), hr = sm_pAlloc->Initialize(sizeof(FORWARDING_HANDLER),
64); // nThreshold 64); // nThreshold
if (FAILED(hr)) if (FAILED_LOG(hr))
{ {
goto Finished; goto Finished;
} }
@ -743,14 +744,14 @@ HRESULT
} }
hr = sm_pResponseHeaderHash->Initialize(); hr = sm_pResponseHeaderHash->Initialize();
if (FAILED(hr)) if (FAILED_LOG(hr))
{ {
goto Finished; goto Finished;
} }
// Initialize PROTOCOL_CONFIG // Initialize PROTOCOL_CONFIG
hr = sm_ProtocolConfig.Initialize(); hr = sm_ProtocolConfig.Initialize();
if (FAILED(hr)) if (FAILED_LOG(hr))
{ {
goto Finished; goto Finished;
} }
@ -786,7 +787,7 @@ HRESULT
</div></body></html>"); </div></body></html>");
Finished: Finished:
if (FAILED(hr)) if (FAILED_LOG(hr))
{ {
StaticTerminate(); StaticTerminate();
} }
@ -871,12 +872,12 @@ FORWARDING_HANDLER::GetHeaders(
// //
if (!pProtocol->QueryPreserveHostHeader()) if (!pProtocol->QueryPreserveHostHeader())
{ {
if (FAILED(hr = URL_UTILITY::SplitUrl(pRequest->GetRawHttpRequest()->CookedUrl.pFullUrl, if (FAILED_LOG(hr = URL_UTILITY::SplitUrl(pRequest->GetRawHttpRequest()->CookedUrl.pFullUrl,
&fSecure, &fSecure,
&struDestination, &struDestination,
&struUrl)) || &struUrl)) ||
FAILED(hr = strTemp.CopyW(struDestination.QueryStr())) || FAILED_LOG(hr = strTemp.CopyW(struDestination.QueryStr())) ||
FAILED(hr = pRequest->SetHeader(HttpHeaderHost, FAILED_LOG(hr = pRequest->SetHeader(HttpHeaderHost,
strTemp.QueryStr(), strTemp.QueryStr(),
static_cast<USHORT>(strTemp.QueryCCH()), static_cast<USHORT>(strTemp.QueryCCH()),
TRUE))) // fReplace TRUE))) // fReplace
@ -917,7 +918,7 @@ FORWARDING_HANDLER::GetHeaders(
pServerProcess->QueryGuid(), pServerProcess->QueryGuid(),
(USHORT)strlen(pServerProcess->QueryGuid()), (USHORT)strlen(pServerProcess->QueryGuid()),
TRUE); TRUE);
if (FAILED(hr)) if (FAILED_LOG(hr))
{ {
return hr; return hr;
} }
@ -933,7 +934,7 @@ FORWARDING_HANDLER::GetHeaders(
HANDLE hTargetTokenHandle = NULL; HANDLE hTargetTokenHandle = NULL;
hr = pServerProcess->SetWindowsAuthToken(m_pW3Context->GetUser()->GetPrimaryToken(), hr = pServerProcess->SetWindowsAuthToken(m_pW3Context->GetUser()->GetPrimaryToken(),
&hTargetTokenHandle); &hTargetTokenHandle);
if (FAILED(hr)) if (FAILED_LOG(hr))
{ {
return hr; return hr;
} }
@ -952,7 +953,7 @@ FORWARDING_HANDLER::GetHeaders(
pszHandleStr, pszHandleStr,
(USHORT)strlen(pszHandleStr), (USHORT)strlen(pszHandleStr),
TRUE); TRUE);
if (FAILED(hr)) if (FAILED_LOG(hr))
{ {
return hr; return hr;
} }
@ -966,14 +967,14 @@ FORWARDING_HANDLER::GetHeaders(
pszCurrentHeader = pRequest->GetHeader(pProtocol->QueryXForwardedForName()->QueryStr(), &cchCurrentHeader); pszCurrentHeader = pRequest->GetHeader(pProtocol->QueryXForwardedForName()->QueryStr(), &cchCurrentHeader);
if (pszCurrentHeader != NULL) if (pszCurrentHeader != NULL)
{ {
if (FAILED(hr = strTemp.Copy(pszCurrentHeader, cchCurrentHeader)) || if (FAILED_LOG(hr = strTemp.Copy(pszCurrentHeader, cchCurrentHeader)) ||
FAILED(hr = strTemp.Append(", ", 2))) FAILED_LOG(hr = strTemp.Append(", ", 2)))
{ {
return hr; return hr;
} }
} }
if (FAILED(hr = m_pW3Context->GetServerVariable("REMOTE_ADDR", if (FAILED_LOG(hr = m_pW3Context->GetServerVariable("REMOTE_ADDR",
&pszFinalHeader, &pszFinalHeader,
&cchFinalHeader))) &cchFinalHeader)))
{ {
@ -982,16 +983,16 @@ FORWARDING_HANDLER::GetHeaders(
if (pRequest->GetRawHttpRequest()->Address.pRemoteAddress->sa_family == AF_INET6) if (pRequest->GetRawHttpRequest()->Address.pRemoteAddress->sa_family == AF_INET6)
{ {
if (FAILED(hr = strTemp.Append("[", 1)) || if (FAILED_LOG(hr = strTemp.Append("[", 1)) ||
FAILED(hr = strTemp.Append(pszFinalHeader, cchFinalHeader)) || FAILED_LOG(hr = strTemp.Append(pszFinalHeader, cchFinalHeader)) ||
FAILED(hr = strTemp.Append("]", 1))) FAILED_LOG(hr = strTemp.Append("]", 1)))
{ {
return hr; return hr;
} }
} }
else else
{ {
if (FAILED(hr = strTemp.Append(pszFinalHeader, cchFinalHeader))) if (FAILED_LOG(hr = strTemp.Append(pszFinalHeader, cchFinalHeader)))
{ {
return hr; return hr;
} }
@ -999,21 +1000,21 @@ FORWARDING_HANDLER::GetHeaders(
if (pProtocol->QueryIncludePortInXForwardedFor()) if (pProtocol->QueryIncludePortInXForwardedFor())
{ {
if (FAILED(hr = m_pW3Context->GetServerVariable("REMOTE_PORT", if (FAILED_LOG(hr = m_pW3Context->GetServerVariable("REMOTE_PORT",
&pszFinalHeader, &pszFinalHeader,
&cchFinalHeader))) &cchFinalHeader)))
{ {
return hr; return hr;
} }
if (FAILED(hr = strTemp.Append(":", 1)) || if (FAILED_LOG(hr = strTemp.Append(":", 1)) ||
FAILED(hr = strTemp.Append(pszFinalHeader, cchFinalHeader))) FAILED_LOG(hr = strTemp.Append(pszFinalHeader, cchFinalHeader)))
{ {
return hr; return hr;
} }
} }
if (FAILED(hr = pRequest->SetHeader(pProtocol->QueryXForwardedForName()->QueryStr(), if (FAILED_LOG(hr = pRequest->SetHeader(pProtocol->QueryXForwardedForName()->QueryStr(),
strTemp.QueryStr(), strTemp.QueryStr(),
static_cast<USHORT>(strTemp.QueryCCH()), static_cast<USHORT>(strTemp.QueryCCH()),
TRUE))) // fReplace TRUE))) // fReplace
@ -1036,19 +1037,19 @@ FORWARDING_HANDLER::GetHeaders(
pszCurrentHeader = pRequest->GetHeader(pProtocol->QuerySslHeaderName()->QueryStr(), &cchCurrentHeader); pszCurrentHeader = pRequest->GetHeader(pProtocol->QuerySslHeaderName()->QueryStr(), &cchCurrentHeader);
if (pszCurrentHeader != NULL) if (pszCurrentHeader != NULL)
{ {
if (FAILED(hr = strTemp.Copy(pszCurrentHeader, cchCurrentHeader)) || if (FAILED_LOG(hr = strTemp.Copy(pszCurrentHeader, cchCurrentHeader)) ||
FAILED(hr = strTemp.Append(", ", 2))) FAILED_LOG(hr = strTemp.Append(", ", 2)))
{ {
return hr; return hr;
} }
} }
if (FAILED(hr = strTemp.Append(pszScheme))) if (FAILED_LOG(hr = strTemp.Append(pszScheme)))
{ {
return hr; return hr;
} }
if (FAILED(pRequest->SetHeader(pProtocol->QuerySslHeaderName()->QueryStr(), if (FAILED_LOG(pRequest->SetHeader(pProtocol->QuerySslHeaderName()->QueryStr(),
strTemp.QueryStr(), strTemp.QueryStr(),
(USHORT)strTemp.QueryCCH(), (USHORT)strTemp.QueryCCH(),
TRUE))) TRUE)))
@ -1067,7 +1068,7 @@ FORWARDING_HANDLER::GetHeaders(
else else
{ {
// Resize the buffer large enough to hold the encoded certificate info // Resize the buffer large enough to hold the encoded certificate info
if (FAILED(hr = strTemp.Resize( if (FAILED_LOG(hr = strTemp.Resize(
1 + (pRequest->GetRawHttpRequest()->pSslInfo->pClientCertInfo->CertEncodedSize + 2) / 3 * 4))) 1 + (pRequest->GetRawHttpRequest()->pSslInfo->pClientCertInfo->CertEncodedSize + 2) / 3 * 4)))
{ {
return hr; return hr;
@ -1081,7 +1082,7 @@ FORWARDING_HANDLER::GetHeaders(
NULL); NULL);
strTemp.SyncWithBuffer(); strTemp.SyncWithBuffer();
if (FAILED(hr = pRequest->SetHeader( if (FAILED_LOG(hr = pRequest->SetHeader(
pProtocol->QueryClientCertName()->QueryStr(), pProtocol->QueryClientCertName()->QueryStr(),
strTemp.QueryStr(), strTemp.QueryStr(),
static_cast<USHORT>(strTemp.QueryCCH()), static_cast<USHORT>(strTemp.QueryCCH()),
@ -1106,7 +1107,7 @@ FORWARDING_HANDLER::GetHeaders(
hr = m_pW3Context->GetServerVariable("ALL_RAW", hr = m_pW3Context->GetServerVariable("ALL_RAW",
ppszHeaders, ppszHeaders,
pcchHeaders); pcchHeaders);
if (FAILED(hr)) if (FAILED_LOG(hr))
{ {
return hr; return hr;
} }
@ -1134,7 +1135,7 @@ FORWARDING_HANDLER::CreateWinHttpRequest(
// we will fill them when sending the request) // we will fill them when sending the request)
// //
pszVerb = pRequest->GetHttpMethod(); pszVerb = pRequest->GetHttpMethod();
if (FAILED(hr = strVerb.CopyA(pszVerb))) if (FAILED_LOG(hr = strVerb.CopyA(pszVerb)))
{ {
goto Finished; goto Finished;
} }
@ -1147,7 +1148,7 @@ FORWARDING_HANDLER::CreateWinHttpRequest(
"HTTP_VERSION", "HTTP_VERSION",
&pszVersion, &pszVersion,
&cchUnused); &cchUnused);
if (FAILED(hr)) if (FAILED_LOG(hr))
{ {
goto Finished; goto Finished;
} }
@ -1235,7 +1236,7 @@ FORWARDING_HANDLER::CreateWinHttpRequest(
pServerProcess, pServerProcess,
&m_pszHeaders, &m_pszHeaders,
&m_cchHeaders); &m_cchHeaders);
if (FAILED(hr)) if (FAILED_LOG(hr))
{ {
goto Finished; goto Finished;
} }
@ -1514,7 +1515,7 @@ None
// //
// Handle failure code for switch statement above. // Handle failure code for switch statement above.
// //
if (FAILED(hr)) if (FAILED_LOG(hr))
{ {
goto Failure; goto Failure;
} }
@ -1762,7 +1763,7 @@ FORWARDING_HANDLER::OnWinHttpCompletionSendRequestOrWriteComplete(
goto Finished; goto Finished;
} }
} }
else if (FAILED(hr)) else if (FAILED_LOG(hr))
{ {
*pfClientError = TRUE; *pfClientError = TRUE;
goto Finished; goto Finished;
@ -1842,7 +1843,7 @@ FORWARDING_HANDLER::OnWinHttpCompletionStatusHeadersAvailable(
} }
} }
if (FAILED(hr = strHeaders.CopyW( if (FAILED_LOG(hr = strHeaders.CopyW(
reinterpret_cast<PWSTR>(bufHeaderBuffer.QueryPtr())))) reinterpret_cast<PWSTR>(bufHeaderBuffer.QueryPtr()))))
{ {
goto Finished; goto Finished;
@ -1859,13 +1860,13 @@ FORWARDING_HANDLER::OnWinHttpCompletionStatusHeadersAvailable(
if (!strHeaders.IsEmpty() && strHeaders.QueryStr()[strHeaders.QueryCCH() - 1] != '\n') if (!strHeaders.IsEmpty() && strHeaders.QueryStr()[strHeaders.QueryCCH() - 1] != '\n')
{ {
hr = strHeaders.Append("\r\n"); hr = strHeaders.Append("\r\n");
if (FAILED(hr)) if (FAILED_LOG(hr))
{ {
goto Finished; goto Finished;
} }
} }
if (FAILED(hr = SetStatusAndHeaders( if (FAILED_LOG(hr = SetStatusAndHeaders(
strHeaders.QueryStr(), strHeaders.QueryStr(),
strHeaders.QueryCCH()))) strHeaders.QueryCCH())))
{ {
@ -1890,7 +1891,7 @@ FORWARDING_HANDLER::OnWinHttpCompletionStatusHeadersAvailable(
NULL, NULL,
NULL); NULL);
if (FAILED(hr)) if (FAILED_LOG(hr))
{ {
*pfAnotherCompletionExpected = FALSE; *pfAnotherCompletionExpected = FALSE;
} }
@ -2022,7 +2023,7 @@ FORWARDING_HANDLER::OnWinHttpCompletionStatusReadComplete(
Chunk.DataChunkType = HttpDataChunkFromMemory; Chunk.DataChunkType = HttpDataChunkFromMemory;
Chunk.FromMemory.pBuffer = m_pEntityBuffer; Chunk.FromMemory.pBuffer = m_pEntityBuffer;
Chunk.FromMemory.BufferLength = dwStatusInformationLength; Chunk.FromMemory.BufferLength = dwStatusInformationLength;
if (FAILED(hr = pResponse->WriteEntityChunkByReference(&Chunk))) if (FAILED_LOG(hr = pResponse->WriteEntityChunkByReference(&Chunk)))
{ {
goto Finished; goto Finished;
} }
@ -2036,7 +2037,7 @@ FORWARDING_HANDLER::OnWinHttpCompletionStatusReadComplete(
hr = pResponse->Flush(TRUE, // fAsync hr = pResponse->Flush(TRUE, // fAsync
TRUE, // fMoreData TRUE, // fMoreData
NULL); // pcbSent NULL); // pcbSent
if (FAILED(hr)) if (FAILED_LOG(hr))
{ {
goto Finished; goto Finished;
} }
@ -2357,10 +2358,10 @@ FORWARDING_HANDLER::SetStatusAndHeaders(
// //
// Copy the status description // Copy the status description
// //
if (FAILED(hr = strHeaderValue.Copy( if (FAILED_LOG(hr = strHeaderValue.Copy(
pchStatus, pchStatus,
(DWORD)(pchEndofHeaderValue - pchStatus) + 1)) || (DWORD)(pchEndofHeaderValue - pchStatus) + 1)) ||
FAILED(hr = pResponse->SetStatus(uStatus, FAILED_LOG(hr = pResponse->SetStatus(uStatus,
strHeaderValue.QueryStr(), strHeaderValue.QueryStr(),
0, 0,
S_OK, S_OK,
@ -2422,7 +2423,7 @@ FORWARDING_HANDLER::SetStatusAndHeaders(
// //
// Copy the header name // Copy the header name
// //
if (FAILED(hr = strHeaderName.Copy( if (FAILED_LOG(hr = strHeaderName.Copy(
pszHeaders + index, pszHeaders + index,
(DWORD)(pchEndofHeaderName - pszHeaders) - index))) (DWORD)(pchEndofHeaderName - pszHeaders) - index)))
{ {
@ -2458,7 +2459,7 @@ FORWARDING_HANDLER::SetStatusAndHeaders(
{ {
strHeaderValue.Reset(); strHeaderValue.Reset();
} }
else if (FAILED(hr = strHeaderValue.Copy( else if (FAILED_LOG(hr = strHeaderValue.Copy(
pszHeaders + index, pszHeaders + index,
(DWORD)(pchEndofHeaderValue - pszHeaders) - index))) (DWORD)(pchEndofHeaderValue - pszHeaders) - index)))
{ {
@ -2508,7 +2509,7 @@ FORWARDING_HANDLER::SetStatusAndHeaders(
static_cast<USHORT>(strHeaderValue.QueryCCH()), static_cast<USHORT>(strHeaderValue.QueryCCH()),
TRUE); // fReplace TRUE); // fReplace
} }
if (FAILED(hr)) if (FAILED_LOG(hr))
{ {
return hr; return hr;
} }
@ -2526,7 +2527,7 @@ FORWARDING_HANDLER::SetStatusAndHeaders(
if (m_fDoReverseRewriteHeaders) if (m_fDoReverseRewriteHeaders)
{ {
hr = DoReverseRewrite(pResponse); hr = DoReverseRewrite(pResponse);
if (FAILED(hr)) if (FAILED_LOG(hr))
{ {
return hr; return hr;
} }
@ -2573,17 +2574,17 @@ FORWARDING_HANDLER::DoReverseRewrite(
pszEndHost = strchr(pszStartHost, '/'); pszEndHost = strchr(pszStartHost, '/');
if (FAILED(hr = strTemp.Copy(fSecure ? "https://" : "http://")) || if (FAILED_LOG(hr = strTemp.Copy(fSecure ? "https://" : "http://")) ||
FAILED(hr = strTemp.Append(m_pszOriginalHostHeader))) FAILED_LOG(hr = strTemp.Append(m_pszOriginalHostHeader)))
{ {
return hr; return hr;
} }
if (pszEndHost != NULL && if (pszEndHost != NULL &&
FAILED(hr = strTemp.Append(pszEndHost))) FAILED_LOG(hr = strTemp.Append(pszEndHost)))
{ {
return hr; return hr;
} }
if (FAILED(hr = pResponse->SetHeader(HttpHeaderContentLocation, if (FAILED_LOG(hr = pResponse->SetHeader(HttpHeaderContentLocation,
strTemp.QueryStr(), strTemp.QueryStr(),
static_cast<USHORT>(strTemp.QueryCCH()), static_cast<USHORT>(strTemp.QueryCCH()),
TRUE))) TRUE)))
@ -2612,17 +2613,17 @@ Location:
pszEndHost = strchr(pszStartHost, '/'); pszEndHost = strchr(pszStartHost, '/');
if (FAILED(hr = strTemp.Copy(fSecure ? "https://" : "http://")) || if (FAILED_LOG(hr = strTemp.Copy(fSecure ? "https://" : "http://")) ||
FAILED(hr = strTemp.Append(m_pszOriginalHostHeader))) FAILED_LOG(hr = strTemp.Append(m_pszOriginalHostHeader)))
{ {
return hr; return hr;
} }
if (pszEndHost != NULL && if (pszEndHost != NULL &&
FAILED(hr = strTemp.Append(pszEndHost))) FAILED_LOG(hr = strTemp.Append(pszEndHost)))
{ {
return hr; return hr;
} }
if (FAILED(hr = pResponse->SetHeader(HttpHeaderLocation, if (FAILED_LOG(hr = pResponse->SetHeader(HttpHeaderLocation,
strTemp.QueryStr(), strTemp.QueryStr(),
static_cast<USHORT>(strTemp.QueryCCH()), static_cast<USHORT>(strTemp.QueryCCH()),
TRUE))) TRUE)))
@ -2687,9 +2688,9 @@ SetCookie:
pszEndHost++; pszEndHost++;
} }
if (FAILED(hr = strTemp.Copy(pszHeader, static_cast<DWORD>(pszStartHost - pszHeader))) || if (FAILED_LOG(hr = strTemp.Copy(pszHeader, static_cast<DWORD>(pszStartHost - pszHeader))) ||
FAILED(hr = strTemp.Append(m_pszOriginalHostHeader)) || FAILED_LOG(hr = strTemp.Append(m_pszOriginalHostHeader)) ||
FAILED(hr = strTemp.Append(pszEndHost))) FAILED_LOG(hr = strTemp.Append(pszEndHost)))
{ {
return hr; return hr;
} }

View File

@ -4,6 +4,7 @@
#include "outprocessapplication.h" #include "outprocessapplication.h"
#include "SRWExclusiveLock.h" #include "SRWExclusiveLock.h"
#include "exceptions.h"
OUT_OF_PROCESS_APPLICATION::OUT_OF_PROCESS_APPLICATION( OUT_OF_PROCESS_APPLICATION::OUT_OF_PROCESS_APPLICATION(
IHttpApplication& pApplication, IHttpApplication& pApplication,
@ -30,25 +31,12 @@ HRESULT
OUT_OF_PROCESS_APPLICATION::Initialize( OUT_OF_PROCESS_APPLICATION::Initialize(
) )
{ {
HRESULT hr = S_OK;
if (m_pProcessManager == NULL) if (m_pProcessManager == NULL)
{ {
m_pProcessManager = new PROCESS_MANAGER; m_pProcessManager = new PROCESS_MANAGER();
if (m_pProcessManager == NULL) RETURN_IF_FAILED(m_pProcessManager->Initialize());
{
hr = E_OUTOFMEMORY;
goto Finished;
}
hr = m_pProcessManager->Initialize();
if (FAILED(hr))
{
goto Finished;
}
} }
return S_OK;
Finished:
return hr;
} }
HRESULT HRESULT
@ -76,7 +64,6 @@ OUT_OF_PROCESS_APPLICATION::CreateHandler(
_In_ IHttpContext *pHttpContext, _In_ IHttpContext *pHttpContext,
_Out_ IREQUEST_HANDLER **pRequestHandler) _Out_ IREQUEST_HANDLER **pRequestHandler)
{ {
HRESULT hr = S_OK;
IREQUEST_HANDLER* pHandler = NULL; IREQUEST_HANDLER* pHandler = NULL;
//add websocket check here //add websocket check here
@ -86,14 +73,8 @@ OUT_OF_PROCESS_APPLICATION::CreateHandler(
} }
pHandler = new FORWARDING_HANDLER(pHttpContext, this); pHandler = new FORWARDING_HANDLER(pHttpContext, this);
if (pHandler == NULL)
{
hr = HRESULT_FROM_WIN32(ERROR_OUTOFMEMORY);
}
*pRequestHandler = pHandler; *pRequestHandler = pHandler;
return hr; return S_OK;
} }
VOID VOID
@ -105,10 +86,8 @@ OUT_OF_PROCESS_APPLICATION::SetWebsocketStatus(
// the websocket module may still not be enabled. // the websocket module may still not be enabled.
PCWSTR pszTempWebsocketValue; PCWSTR pszTempWebsocketValue;
DWORD cbLength; DWORD cbLength;
HRESULT hr;
hr = pHttpContext->GetServerVariable("WEBSOCKET_VERSION", &pszTempWebsocketValue, &cbLength); if (FAILED_LOG(pHttpContext->GetServerVariable("WEBSOCKET_VERSION", &pszTempWebsocketValue, &cbLength)))
if (FAILED(hr))
{ {
m_fWebSocketSupported = WEBSOCKET_STATUS::WEBSOCKET_NOT_SUPPORTED; m_fWebSocketSupported = WEBSOCKET_STATUS::WEBSOCKET_NOT_SUPPORTED;
} }

View File

@ -3,6 +3,8 @@
#include "processmanager.h" #include "processmanager.h"
#include "EventLog.h" #include "EventLog.h"
#include "exceptions.h"
#include "SRWSharedLock.h"
volatile BOOL PROCESS_MANAGER::sm_fWSAStartupDone = FALSE; volatile BOOL PROCESS_MANAGER::sm_fWSAStartupDone = FALSE;
@ -11,28 +13,21 @@ PROCESS_MANAGER::Initialize(
VOID VOID
) )
{ {
HRESULT hr = S_OK;
WSADATA wsaData; WSADATA wsaData;
int result; int result;
BOOL fLocked = FALSE;
if( !sm_fWSAStartupDone ) if( !sm_fWSAStartupDone )
{ {
AcquireSRWLockExclusive( &m_srwLock ); auto lock = SRWExclusiveLock(m_srwLock);
fLocked = TRUE;
if( !sm_fWSAStartupDone ) if( !sm_fWSAStartupDone )
{ {
if( (result = WSAStartup(MAKEWORD(2, 2), &wsaData)) != 0 ) if( (result = WSAStartup(MAKEWORD(2, 2), &wsaData)) != 0 )
{ {
hr = HRESULT_FROM_WIN32( result ); RETURN_HR(HRESULT_FROM_WIN32( result ));
goto Finished;
} }
sm_fWSAStartupDone = TRUE; sm_fWSAStartupDone = TRUE;
} }
ReleaseSRWLockExclusive( &m_srwLock );
fLocked = FALSE;
} }
m_dwRapidFailTickStart = GetTickCount(); m_dwRapidFailTickStart = GetTickCount();
@ -51,55 +46,14 @@ PROCESS_MANAGER::Initialize(
CREATE_ALWAYS, CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL, FILE_ATTRIBUTE_NORMAL,
NULL ); NULL );
if( m_hNULHandle == INVALID_HANDLE_VALUE ) RETURN_LAST_ERROR_IF( m_hNULHandle == INVALID_HANDLE_VALUE );
{
hr = HRESULT_FROM_WIN32(GetLastError());
goto Finished;
}
} }
Finished: return S_OK;
if(fLocked)
{
ReleaseSRWLockExclusive( &m_srwLock );
}
return hr;
} }
PROCESS_MANAGER::~PROCESS_MANAGER() PROCESS_MANAGER::~PROCESS_MANAGER()
{ {
AcquireSRWLockExclusive(&m_srwLock);
//if( m_ppServerProcessList != NULL )
//{
// for( DWORD i = 0; i < m_dwProcessesPerApplication; ++i )
// {
// if( m_ppServerProcessList[i] != NULL )
// {
// m_ppServerProcessList[i]->DereferenceServerProcess();
// m_ppServerProcessList[i] = NULL;
// }
// }
// delete[] m_ppServerProcessList;
// m_ppServerProcessList = NULL;
//}
//if( m_hNULHandle != NULL )
//{
// CloseHandle( m_hNULHandle );
// m_hNULHandle = NULL;
//}
//if( sm_fWSAStartupDone )
//{
// WSACleanup();
// sm_fWSAStartupDone = FALSE;
//}
ReleaseSRWLockExclusive(&m_srwLock);
} }
HRESULT HRESULT
@ -109,31 +63,22 @@ PROCESS_MANAGER::GetProcess(
_Out_ SERVER_PROCESS **ppServerProcess _Out_ SERVER_PROCESS **ppServerProcess
) )
{ {
HRESULT hr = S_OK;
BOOL fSharedLock = FALSE;
BOOL fExclusiveLock = FALSE;
DWORD dwProcessIndex = 0; DWORD dwProcessIndex = 0;
SERVER_PROCESS *pSelectedServerProcess = NULL; std::unique_ptr<SERVER_PROCESS> pSelectedServerProcess;
if (InterlockedCompareExchange(&m_lStopping, 1L, 1L) == 1L) if (InterlockedCompareExchange(&m_lStopping, 1L, 1L) == 1L)
{ {
return hr = E_APPLICATION_EXITING; RETURN_IF_FAILED(E_APPLICATION_EXITING);
} }
if (!m_fServerProcessListReady) if (!m_fServerProcessListReady)
{ {
AcquireSRWLockExclusive(&m_srwLock); auto lock = SRWExclusiveLock(m_srwLock);
fExclusiveLock = TRUE;
if (!m_fServerProcessListReady) if (!m_fServerProcessListReady)
{ {
m_dwProcessesPerApplication = pConfig->QueryProcessesPerApplication(); m_dwProcessesPerApplication = pConfig->QueryProcessesPerApplication();
m_ppServerProcessList = new SERVER_PROCESS*[m_dwProcessesPerApplication]; m_ppServerProcessList = new SERVER_PROCESS*[m_dwProcessesPerApplication];
if (m_ppServerProcessList == NULL)
{
hr = E_OUTOFMEMORY;
goto Finished;
}
for (DWORD i = 0; i < m_dwProcessesPerApplication; ++i) for (DWORD i = 0; i < m_dwProcessesPerApplication; ++i)
{ {
@ -141,35 +86,30 @@ PROCESS_MANAGER::GetProcess(
} }
} }
m_fServerProcessListReady = TRUE; m_fServerProcessListReady = TRUE;
ReleaseSRWLockExclusive(&m_srwLock);
fExclusiveLock = FALSE;
} }
AcquireSRWLockShared(&m_srwLock);
fSharedLock = TRUE;
//
// round robin through to the next available process.
//
dwProcessIndex = (DWORD)InterlockedIncrement64((LONGLONG*)&m_dwRouteToProcessIndex);
dwProcessIndex = dwProcessIndex % m_dwProcessesPerApplication;
if (m_ppServerProcessList[dwProcessIndex] != NULL &&
m_ppServerProcessList[dwProcessIndex]->IsReady())
{ {
*ppServerProcess = m_ppServerProcessList[dwProcessIndex]; auto lock = SRWSharedLock(m_srwLock);
goto Finished;
}
ReleaseSRWLockShared(&m_srwLock); //
fSharedLock = FALSE; // round robin through to the next available process.
//
dwProcessIndex = (DWORD)InterlockedIncrement64((LONGLONG*)&m_dwRouteToProcessIndex);
dwProcessIndex = dwProcessIndex % m_dwProcessesPerApplication;
if (m_ppServerProcessList[dwProcessIndex] != NULL &&
m_ppServerProcessList[dwProcessIndex]->IsReady())
{
*ppServerProcess = m_ppServerProcessList[dwProcessIndex];
return S_OK;
}
}
// should make the lock per process so that we can start processes simultaneously ? // should make the lock per process so that we can start processes simultaneously ?
if (m_ppServerProcessList[dwProcessIndex] == NULL || if (m_ppServerProcessList[dwProcessIndex] == NULL ||
!m_ppServerProcessList[dwProcessIndex]->IsReady()) !m_ppServerProcessList[dwProcessIndex]->IsReady())
{ {
AcquireSRWLockExclusive(&m_srwLock); auto lock = SRWExclusiveLock(m_srwLock);
fExclusiveLock = TRUE;
if (m_ppServerProcessList[dwProcessIndex] != NULL) if (m_ppServerProcessList[dwProcessIndex] != NULL)
{ {
@ -186,7 +126,7 @@ PROCESS_MANAGER::GetProcess(
// server is already up and ready to serve requests. // server is already up and ready to serve requests.
//m_ppServerProcessList[dwProcessIndex]->ReferenceServerProcess(); //m_ppServerProcessList[dwProcessIndex]->ReferenceServerProcess();
*ppServerProcess = m_ppServerProcessList[dwProcessIndex]; *ppServerProcess = m_ppServerProcessList[dwProcessIndex];
goto Finished; return S_OK;
} }
} }
@ -200,22 +140,14 @@ PROCESS_MANAGER::GetProcess(
ASPNETCORE_EVENT_RAPID_FAIL_COUNT_EXCEEDED_MSG, ASPNETCORE_EVENT_RAPID_FAIL_COUNT_EXCEEDED_MSG,
pConfig->QueryRapidFailsPerMinute()); pConfig->QueryRapidFailsPerMinute());
hr = HRESULT_FROM_WIN32(ERROR_SERVER_DISABLED); RETURN_HR(HRESULT_FROM_WIN32(ERROR_SERVER_DISABLED));
goto Finished;
} }
if (m_ppServerProcessList[dwProcessIndex] == NULL) if (m_ppServerProcessList[dwProcessIndex] == NULL)
{ {
pSelectedServerProcess = new SERVER_PROCESS(); pSelectedServerProcess = std::make_unique<SERVER_PROCESS>();
if (pSelectedServerProcess == NULL) RETURN_IF_FAILED(pSelectedServerProcess->Initialize(
{
hr = E_OUTOFMEMORY;
goto Finished;
}
hr = pSelectedServerProcess->Initialize(
this, //ProcessManager this, //ProcessManager
pConfig->QueryProcessPath(), // pConfig->QueryProcessPath(), //
pConfig->QueryArguments(), // pConfig->QueryArguments(), //
@ -231,50 +163,18 @@ PROCESS_MANAGER::GetProcess(
pConfig->QueryApplicationPhysicalPath(), // physical path pConfig->QueryApplicationPhysicalPath(), // physical path
pConfig->QueryApplicationPath(), // app path pConfig->QueryApplicationPath(), // app path
pConfig->QueryApplicationVirtualPath() // App relative virtual path pConfig->QueryApplicationVirtualPath() // App relative virtual path
); ));
if (FAILED(hr)) RETURN_IF_FAILED(pSelectedServerProcess->StartProcess());
{
goto Finished;
}
hr = pSelectedServerProcess->StartProcess();
if (FAILED(hr))
{
goto Finished;
}
} }
if (!pSelectedServerProcess->IsReady()) if (!pSelectedServerProcess->IsReady())
{ {
hr = HRESULT_FROM_WIN32(ERROR_CREATE_FAILED); RETURN_HR(HRESULT_FROM_WIN32(ERROR_CREATE_FAILED));
goto Finished;
} }
m_ppServerProcessList[dwProcessIndex] = pSelectedServerProcess; m_ppServerProcessList[dwProcessIndex] = pSelectedServerProcess.release();
pSelectedServerProcess = NULL;
} }
*ppServerProcess = m_ppServerProcessList[dwProcessIndex]; *ppServerProcess = m_ppServerProcessList[dwProcessIndex];
Finished: return S_OK;
if (fSharedLock)
{
ReleaseSRWLockShared(&m_srwLock);
fSharedLock = FALSE;
}
if (fExclusiveLock)
{
ReleaseSRWLockExclusive(&m_srwLock);
fExclusiveLock = FALSE;
}
if (pSelectedServerProcess != NULL)
{
delete pSelectedServerProcess;
pSelectedServerProcess = NULL;
}
return hr;
} }

View File

@ -2,41 +2,25 @@
// Licensed under the MIT License. See License.txt in the project root for license information. // Licensed under the MIT License. See License.txt in the project root for license information.
#include "protocolconfig.h" #include "protocolconfig.h"
#include "exceptions.h"
HRESULT HRESULT
PROTOCOL_CONFIG::Initialize() PROTOCOL_CONFIG::Initialize()
{ {
HRESULT hr;
STRU strTemp;
m_fKeepAlive = TRUE; m_fKeepAlive = TRUE;
m_msTimeout = 120000; m_msTimeout = 120000;
m_fPreserveHostHeader = TRUE; m_fPreserveHostHeader = TRUE;
m_fReverseRewriteHeaders = FALSE; m_fReverseRewriteHeaders = FALSE;
if (FAILED(hr = m_strXForwardedForName.CopyW(L"X-Forwarded-For"))) RETURN_IF_FAILED(m_strXForwardedForName.CopyW(L"X-Forwarded-For"));
{ RETURN_IF_FAILED(m_strSslHeaderName.CopyW(L"X-Forwarded-Proto"));
goto Finished; RETURN_IF_FAILED(m_strClientCertName.CopyW(L"MS-ASPNETCORE-CLIENTCERT"));
}
if (FAILED(hr = m_strSslHeaderName.CopyW(L"X-Forwarded-Proto")))
{
goto Finished;
}
if (FAILED(hr = m_strClientCertName.CopyW(L"MS-ASPNETCORE-CLIENTCERT")))
{
goto Finished;
}
m_fIncludePortInXForwardedFor = TRUE; m_fIncludePortInXForwardedFor = TRUE;
m_dwMinResponseBuffer = 0; // no response buffering m_dwMinResponseBuffer = 0; // no response buffering
m_dwResponseBufferLimit = 4096*1024; m_dwResponseBufferLimit = 4096*1024;
m_dwMaxResponseHeaderSize = 65536; m_dwMaxResponseHeaderSize = 65536;
return S_OK;
Finished:
return hr;
} }
VOID VOID

View File

@ -2,6 +2,7 @@
// Licensed under the MIT License. See License.txt in the project root for license information. // Licensed under the MIT License. See License.txt in the project root for license information.
#include "responseheaderhash.h" #include "responseheaderhash.h"
#include "exceptions.h"
HEADER_RECORD RESPONSE_HEADER_HASH::sm_rgHeaders[] = HEADER_RECORD RESPONSE_HEADER_HASH::sm_rgHeaders[] =
{ {
@ -65,8 +66,6 @@ Return Value:
--*/ --*/
{ {
HRESULT hr;
// //
// 31 response headers. // 31 response headers.
// Make sure to update the number of buckets it new headers // Make sure to update the number of buckets it new headers
@ -79,18 +78,11 @@ Return Value:
// Known collisions are "Age" colliding with "Expire" and "Location" // Known collisions are "Age" colliding with "Expire" and "Location"
// colliding with both "Expire" and "Age". // colliding with both "Expire" and "Age".
// //
hr = HASH_TABLE::Initialize(79); RETURN_IF_FAILED(HASH_TABLE::Initialize(79));
if (FAILED(hr))
{
return hr;
}
for ( DWORD Index = 0; Index < _countof(sm_rgHeaders); ++Index ) for ( DWORD Index = 0; Index < _countof(sm_rgHeaders); ++Index )
{ {
if (FAILED(hr = InsertRecord(&sm_rgHeaders[Index]))) RETURN_IF_FAILED(InsertRecord(&sm_rgHeaders[Index]));
{
return hr;
}
} }
return S_OK; return S_OK;

View File

@ -6,6 +6,7 @@
#include <IPHlpApi.h> #include <IPHlpApi.h>
#include "EventLog.h" #include "EventLog.h"
#include "file_utility.h" #include "file_utility.h"
#include "exceptions.h"
//#include <share.h> //#include <share.h>
//extern BOOL g_fNsiApiNotSupported; //extern BOOL g_fNsiApiNotSupported;
@ -45,13 +46,13 @@ SERVER_PROCESS::Initialize(
m_pProcessManager->ReferenceProcessManager(); m_pProcessManager->ReferenceProcessManager();
m_fDebuggerAttached = FALSE; m_fDebuggerAttached = FALSE;
if (FAILED(hr = m_ProcessPath.Copy(*pszProcessExePath)) || if (FAILED_LOG(hr = m_ProcessPath.Copy(*pszProcessExePath)) ||
FAILED(hr = m_struLogFile.Copy(*pstruStdoutLogFile))|| FAILED_LOG(hr = m_struLogFile.Copy(*pstruStdoutLogFile))||
FAILED(hr = m_struPhysicalPath.Copy(*pszAppPhysicalPath))|| FAILED_LOG(hr = m_struPhysicalPath.Copy(*pszAppPhysicalPath))||
FAILED(hr = m_struAppFullPath.Copy(*pszAppPath))|| FAILED_LOG(hr = m_struAppFullPath.Copy(*pszAppPath))||
FAILED(hr = m_struAppVirtualPath.Copy(*pszAppVirtualPath))|| FAILED_LOG(hr = m_struAppVirtualPath.Copy(*pszAppVirtualPath))||
FAILED(hr = m_Arguments.Copy(*pszArguments)) || FAILED_LOG(hr = m_Arguments.Copy(*pszArguments)) ||
FAILED(hr = SetupJobObject())) FAILED_LOG(hr = SetupJobObject()))
{ {
goto Finished; goto Finished;
} }
@ -155,7 +156,7 @@ SERVER_PROCESS::SetupListenPort(
pEnvironmentVarTable->FindKey(ASPNETCORE_PORT_ENV_STR, &pEntry); pEnvironmentVarTable->FindKey(ASPNETCORE_PORT_ENV_STR, &pEntry);
if (pEntry != NULL) if (pEntry != NULL)
{ {
if (pEntry->QueryValue() != NULL || pEntry->QueryValue()[0] != L'\0') if (pEntry->QueryValue() != NULL && pEntry->QueryValue()[0] != L'\0')
{ {
m_dwPort = (DWORD)_wtoi(pEntry->QueryValue()); m_dwPort = (DWORD)_wtoi(pEntry->QueryValue());
if (m_dwPort >MAX_PORT || m_dwPort < MIN_PORT) if (m_dwPort >MAX_PORT || m_dwPort < MIN_PORT)
@ -174,13 +175,13 @@ SERVER_PROCESS::SetupListenPort(
// user set the env variable but did not give value, let's set it up // user set the env variable but did not give value, let's set it up
// //
pEnvironmentVarTable->DeleteKey(ASPNETCORE_PORT_ENV_STR); pEnvironmentVarTable->DeleteKey(ASPNETCORE_PORT_ENV_STR);
pEntry->Dereference();
pEntry = NULL;
} }
pEntry->Dereference();
pEntry = NULL;
} }
WCHAR buffer[15]; WCHAR buffer[15];
if (FAILED(hr = GetRandomPort(&m_dwPort))) if (FAILED_LOG(hr = GetRandomPort(&m_dwPort)))
{ {
goto Finished; goto Finished;
} }
@ -198,9 +199,9 @@ SERVER_PROCESS::SetupListenPort(
goto Finished; goto Finished;
} }
if (FAILED(hr = pEntry->Initialize(ASPNETCORE_PORT_ENV_STR, buffer)) || if (FAILED_LOG(hr = pEntry->Initialize(ASPNETCORE_PORT_ENV_STR, buffer)) ||
FAILED(hr = pEnvironmentVarTable->InsertRecord(pEntry)) || FAILED_LOG(hr = pEnvironmentVarTable->InsertRecord(pEntry)) ||
FAILED(hr = m_struPort.Copy(buffer))) FAILED_LOG(hr = m_struPort.Copy(buffer)))
{ {
goto Finished; goto Finished;
} }
@ -212,7 +213,7 @@ Finished:
pEntry = NULL; pEntry = NULL;
} }
if (FAILED(hr)) if (FAILED_LOG(hr))
{ {
EventLog::Error( EventLog::Error(
ASPNETCORE_EVENT_PROCESS_START_SUCCESS, ASPNETCORE_EVENT_PROCESS_START_SUCCESS,
@ -252,8 +253,8 @@ SERVER_PROCESS::SetupAppPath(
goto Finished; goto Finished;
} }
if (FAILED(hr = pEntry->Initialize(ASPNETCORE_APP_PATH_ENV_STR, m_struAppVirtualPath.QueryStr())) || if (FAILED_LOG(hr = pEntry->Initialize(ASPNETCORE_APP_PATH_ENV_STR, m_struAppVirtualPath.QueryStr())) ||
FAILED(hr = pEnvironmentVarTable->InsertRecord(pEntry))) FAILED_LOG(hr = pEnvironmentVarTable->InsertRecord(pEntry)))
{ {
goto Finished; goto Finished;
} }
@ -311,7 +312,7 @@ SERVER_PROCESS::SetupAppToken(
fRpcStringAllocd = TRUE; fRpcStringAllocd = TRUE;
if (FAILED(hr = m_straGuid.Copy(pszLogUuid))) if (FAILED_LOG(hr = m_straGuid.Copy(pszLogUuid)))
{ {
goto Finished; goto Finished;
} }
@ -324,9 +325,9 @@ SERVER_PROCESS::SetupAppToken(
goto Finished; goto Finished;
} }
if (FAILED(strAppToken.CopyA(m_straGuid.QueryStr())) || if (FAILED_LOG(strAppToken.CopyA(m_straGuid.QueryStr())) ||
FAILED(hr = pEntry->Initialize(ASPNETCORE_APP_TOKEN_ENV_STR, strAppToken.QueryStr())) || FAILED_LOG(hr = pEntry->Initialize(ASPNETCORE_APP_TOKEN_ENV_STR, strAppToken.QueryStr())) ||
FAILED(hr = pEnvironmentVarTable->InsertRecord(pEntry))) FAILED_LOG(hr = pEnvironmentVarTable->InsertRecord(pEntry)))
{ {
goto Finished; goto Finished;
} }
@ -382,7 +383,7 @@ SERVER_PROCESS::OutputEnvironmentVariables
pszEqualChar = wcschr(pszCurrentVariable, L'='); pszEqualChar = wcschr(pszCurrentVariable, L'=');
if (pszEqualChar != NULL) if (pszEqualChar != NULL)
{ {
if (FAILED(hr = strEnvVar.Copy(pszCurrentVariable, (DWORD)(pszEqualChar - pszCurrentVariable) + 1))) if (FAILED_LOG(hr = strEnvVar.Copy(pszCurrentVariable, (DWORD)(pszEqualChar - pszCurrentVariable) + 1)))
{ {
goto Finished; goto Finished;
} }
@ -390,7 +391,7 @@ SERVER_PROCESS::OutputEnvironmentVariables
if (pEntry != NULL) if (pEntry != NULL)
{ {
// same env variable is defined in configuration, use it // same env variable is defined in configuration, use it
if (FAILED(hr = strEnvVar.Append(pEntry->QueryValue()))) if (FAILED_LOG(hr = strEnvVar.Append(pEntry->QueryValue())))
{ {
goto Finished; goto Finished;
} }
@ -453,9 +454,9 @@ SERVER_PROCESS::SetupCommandLine(
if ((wcsstr(pszPath, L":") == NULL) && (wcsstr(pszPath, L"%") == NULL)) if ((wcsstr(pszPath, L":") == NULL) && (wcsstr(pszPath, L"%") == NULL))
{ {
// let's check whether it is a relative path // let's check whether it is a relative path
if (FAILED(hr = strRelativePath.Copy(m_struPhysicalPath.QueryStr())) || if (FAILED_LOG(hr = strRelativePath.Copy(m_struPhysicalPath.QueryStr())) ||
FAILED(hr = strRelativePath.Append(L"\\")) || FAILED_LOG(hr = strRelativePath.Append(L"\\")) ||
FAILED(hr = strRelativePath.Append(pszPath))) FAILED_LOG(hr = strRelativePath.Append(pszPath)))
{ {
goto Finished; goto Finished;
} }
@ -482,9 +483,9 @@ SERVER_PROCESS::SetupCommandLine(
pszPath = pszFullPath; pszPath = pszFullPath;
} }
} }
if (FAILED(hr = pstrCommandLine->Copy(pszPath)) || if (FAILED_LOG(hr = pstrCommandLine->Copy(pszPath)) ||
FAILED(hr = pstrCommandLine->Append(L" ")) || FAILED_LOG(hr = pstrCommandLine->Append(L" ")) ||
FAILED(hr = pstrCommandLine->Append(m_Arguments.QueryStr()))) FAILED_LOG(hr = pstrCommandLine->Append(m_Arguments.QueryStr())))
{ {
goto Finished; goto Finished;
} }
@ -566,7 +567,7 @@ SERVER_PROCESS::PostStartCheck(
} }
// register call back with the created process // register call back with the created process
if (FAILED(hr = RegisterProcessWait(&m_hProcessWaitHandle, m_hProcessHandle))) if (FAILED_LOG(hr = RegisterProcessWait(&m_hProcessWaitHandle, m_hProcessHandle)))
{ {
goto Finished; goto Finished;
} }
@ -595,7 +596,7 @@ SERVER_PROCESS::PostStartCheck(
if (!fProcessMatch) if (!fProcessMatch)
{ {
// could be the scenario that backend creates child process // could be the scenario that backend creates child process
if (FAILED(hr = GetChildProcessHandles())) if (FAILED_LOG(hr = GetChildProcessHandles()))
{ {
goto Finished; goto Finished;
} }
@ -617,7 +618,7 @@ SERVER_PROCESS::PostStartCheck(
fDebuggerAttached = FALSE; fDebuggerAttached = FALSE;
} }
if (FAILED(hr = RegisterProcessWait(&m_hChildProcessWaitHandles[i], if (FAILED_LOG(hr = RegisterProcessWait(&m_hChildProcessWaitHandles[i],
m_hChildProcessHandles[i]))) m_hChildProcessHandles[i])))
{ {
goto Finished; goto Finished;
@ -678,7 +679,7 @@ SERVER_PROCESS::PostStartCheck(
hr = CheckIfServerIsUp(m_dwPort, &dwActualProcessId, &fReady); hr = CheckIfServerIsUp(m_dwPort, &dwActualProcessId, &fReady);
if ((FAILED(hr) || fReady == FALSE)) if ((FAILED_LOG(hr) || fReady == FALSE))
{ {
strEventMsg.SafeSnwprintf( strEventMsg.SafeSnwprintf(
ASPNETCORE_EVENT_PROCESS_START_NOTREADY_ERROR_MSG, ASPNETCORE_EVENT_PROCESS_START_NOTREADY_ERROR_MSG,
@ -705,7 +706,7 @@ SERVER_PROCESS::PostStartCheck(
} }
hr = m_pForwarderConnection->Initialize(m_dwPort); hr = m_pForwarderConnection->Initialize(m_dwPort);
if (FAILED(hr)) if (FAILED_LOG(hr))
{ {
goto Finished; goto Finished;
} }
@ -726,7 +727,7 @@ SERVER_PROCESS::PostStartCheck(
Finished: Finished:
m_fDebuggerAttached = fDebuggerAttached; m_fDebuggerAttached = fDebuggerAttached;
if (FAILED(hr)) if (FAILED_LOG(hr))
{ {
if (m_pForwarderConnection != NULL) if (m_pForwarderConnection != NULL)
{ {
@ -773,13 +774,13 @@ SERVER_PROCESS::StartProcess(
// //
// generate process command line. // generate process command line.
// //
if (FAILED(hr = SetupCommandLine(&m_struCommandLine))) if (FAILED_LOG(hr = SetupCommandLine(&m_struCommandLine)))
{ {
pStrStage = L"SetupCommandLine"; pStrStage = L"SetupCommandLine";
goto Failure; goto Failure;
} }
if (FAILED(hr = ENVIRONMENT_VAR_HELPERS::InitEnvironmentVariablesTable( if (FAILED_LOG(hr = ENVIRONMENT_VAR_HELPERS::InitEnvironmentVariablesTable(
m_pEnvironmentVarTable, m_pEnvironmentVarTable,
m_fWindowsAuthEnabled, m_fWindowsAuthEnabled,
m_fBasicAuthEnabled, m_fBasicAuthEnabled,
@ -790,7 +791,7 @@ SERVER_PROCESS::StartProcess(
goto Failure; goto Failure;
} }
if (FAILED(hr = ENVIRONMENT_VAR_HELPERS::AddWebsocketEnabledToEnvironmentVariables( if (FAILED_LOG(hr = ENVIRONMENT_VAR_HELPERS::AddWebsocketEnabledToEnvironmentVariables(
pHashTable, pHashTable,
m_fWebSocketSupported m_fWebSocketSupported
))) )))
@ -803,7 +804,7 @@ SERVER_PROCESS::StartProcess(
// //
// setup the the port that the backend process will listen on // setup the the port that the backend process will listen on
// //
if (FAILED(hr = SetupListenPort(pHashTable, &fCriticalError))) if (FAILED_LOG(hr = SetupListenPort(pHashTable, &fCriticalError)))
{ {
pStrStage = L"SetupListenPort"; pStrStage = L"SetupListenPort";
goto Failure; goto Failure;
@ -812,7 +813,7 @@ SERVER_PROCESS::StartProcess(
// //
// get app path // get app path
// //
if (FAILED(hr = SetupAppPath(pHashTable))) if (FAILED_LOG(hr = SetupAppPath(pHashTable)))
{ {
pStrStage = L"SetupAppPath"; pStrStage = L"SetupAppPath";
goto Failure; goto Failure;
@ -821,7 +822,7 @@ SERVER_PROCESS::StartProcess(
// //
// generate new guid for each process // generate new guid for each process
// //
if (FAILED(hr = SetupAppToken(pHashTable))) if (FAILED_LOG(hr = SetupAppToken(pHashTable)))
{ {
pStrStage = L"SetupAppToken"; pStrStage = L"SetupAppToken";
goto Failure; goto Failure;
@ -830,7 +831,7 @@ SERVER_PROCESS::StartProcess(
// //
// setup environment variables for new process // setup environment variables for new process
// //
if (FAILED(hr = OutputEnvironmentVariables(&mszNewEnvironment, pHashTable))) if (FAILED_LOG(hr = OutputEnvironmentVariables(&mszNewEnvironment, pHashTable)))
{ {
pStrStage = L"OutputEnvironmentVariables"; pStrStage = L"OutputEnvironmentVariables";
goto Failure; goto Failure;
@ -861,7 +862,7 @@ SERVER_PROCESS::StartProcess(
m_hProcessHandle = processInformation.hProcess; m_hProcessHandle = processInformation.hProcess;
m_dwProcessId = processInformation.dwProcessId; m_dwProcessId = processInformation.dwProcessId;
if (FAILED(hr = SetupJobObject())) if (FAILED_LOG(hr = SetupJobObject()))
{ {
pStrStage = L"SetupJobObject"; pStrStage = L"SetupJobObject";
goto Failure; goto Failure;
@ -890,7 +891,7 @@ SERVER_PROCESS::StartProcess(
// //
// need to make sure the server is up and listening on the port specified. // need to make sure the server is up and listening on the port specified.
// //
if (FAILED(hr = PostStartCheck())) if (FAILED_LOG(hr = PostStartCheck()))
{ {
pStrStage = L"PostStartCheck"; pStrStage = L"PostStartCheck";
goto Failure; goto Failure;
@ -944,7 +945,7 @@ SERVER_PROCESS::StartProcess(
} }
Finished: Finished:
if (FAILED(hr) || m_fReady == FALSE) if (FAILED_LOG(hr) || m_fReady == FALSE)
{ {
if (m_hStdoutHandle != NULL) if (m_hStdoutHandle != NULL)
{ {
@ -1034,7 +1035,7 @@ SERVER_PROCESS::SetupStdHandles(
m_struLogFile.QueryStr(), m_struLogFile.QueryStr(),
m_struPhysicalPath.QueryStr(), m_struPhysicalPath.QueryStr(),
&struPath); &struPath);
if (FAILED(hr)) if (FAILED_LOG(hr))
{ {
goto Finished; goto Finished;
} }
@ -1049,13 +1050,13 @@ SERVER_PROCESS::SetupStdHandles(
systemTime.wMinute, systemTime.wMinute,
systemTime.wSecond, systemTime.wSecond,
GetCurrentProcessId()); GetCurrentProcessId());
if (FAILED(hr)) if (FAILED_LOG(hr))
{ {
goto Finished; goto Finished;
} }
hr = FILE_UTILITY::EnsureDirectoryPathExist(struPath.QueryStr()); hr = FILE_UTILITY::EnsureDirectoryPathExist(struPath.QueryStr());
if (FAILED(hr)) if (FAILED_LOG(hr))
{ {
goto Finished; goto Finished;
} }
@ -1086,7 +1087,7 @@ SERVER_PROCESS::SetupStdHandles(
m_Timer.InitializeTimer(STTIMER::TimerCallback, &m_struFullLogFile, 3000, 3000); m_Timer.InitializeTimer(STTIMER::TimerCallback, &m_struFullLogFile, 3000, 3000);
Finished: Finished:
if (FAILED(hr)) if (FAILED_LOG(hr))
{ {
pStartupInfo->dwFlags = STARTF_USESTDHANDLES; pStartupInfo->dwFlags = STARTF_USESTDHANDLES;
pStartupInfo->hStdInput = INVALID_HANDLE_VALUE; pStartupInfo->hStdInput = INVALID_HANDLE_VALUE;
@ -1305,7 +1306,7 @@ Finished:
hThread = NULL; hThread = NULL;
} }
if (FAILED(hr)) if (FAILED_LOG(hr))
{ {
TerminateBackendProcess(); TerminateBackendProcess();
} }
@ -1874,7 +1875,7 @@ SERVER_PROCESS::RegisterProcessWait(
Finished: Finished:
if (FAILED(hr)) if (FAILED_LOG(hr))
{ {
*phWaitHandle = NULL; *phWaitHandle = NULL;
DereferenceServerProcess(); DereferenceServerProcess();
@ -1981,10 +1982,10 @@ SERVER_PROCESS::SendShutdownHttpMessage( VOID )
} }
// set up the shutdown headers // set up the shutdown headers
if (FAILED(hr = strHeaders.Append(L"MS-ASPNETCORE-EVENT:shutdown \r\n")) || if (FAILED_LOG(hr = strHeaders.Append(L"MS-ASPNETCORE-EVENT:shutdown \r\n")) ||
FAILED(hr = strAppToken.Append(L"MS-ASPNETCORE-TOKEN:")) || FAILED_LOG(hr = strAppToken.Append(L"MS-ASPNETCORE-TOKEN:")) ||
FAILED(hr = strAppToken.AppendA(m_straGuid.QueryStr())) || FAILED_LOG(hr = strAppToken.AppendA(m_straGuid.QueryStr())) ||
FAILED(hr = strHeaders.Append(strAppToken.QueryStr()))) FAILED_LOG(hr = strHeaders.Append(strAppToken.QueryStr())))
{ {
goto Finished; goto Finished;
} }
@ -2072,7 +2073,7 @@ SERVER_PROCESS::SendShutDownSignalInternal(
{ {
ReferenceServerProcess(); ReferenceServerProcess();
if (FAILED(SendShutdownHttpMessage())) if (FAILED_LOG(SendShutdownHttpMessage()))
{ {
// //
// failed to send shutdown http message // failed to send shutdown http message

View File

@ -5,6 +5,7 @@
#include <Shlwapi.h> #include <Shlwapi.h>
#include "debugutil.h" #include "debugutil.h"
#include "exceptions.h"
// static // static
HRESULT HRESULT
@ -38,8 +39,6 @@ Return Value:
--*/ --*/
{ {
HRESULT hr;
// //
// First determine if the target is secure // First determine if the target is secure
// //
@ -55,12 +54,12 @@ Return Value:
} }
else else
{ {
return HRESULT_FROM_WIN32(ERROR_INVALID_DATA); RETURN_HR(HRESULT_FROM_WIN32(ERROR_INVALID_DATA));
} }
if (*pszDestinationUrl == L'\0') if (*pszDestinationUrl == L'\0')
{ {
return HRESULT_FROM_WIN32(ERROR_INVALID_DATA); RETURN_HR(HRESULT_FROM_WIN32(ERROR_INVALID_DATA));
} }
// //
@ -69,20 +68,14 @@ Return Value:
LPCWSTR pszSlash = wcschr(pszDestinationUrl, L'/'); LPCWSTR pszSlash = wcschr(pszDestinationUrl, L'/');
if (pszSlash == NULL) if (pszSlash == NULL)
{ {
if (FAILED(hr = pstrUrl->Copy(L"/", 1)) || RETURN_IF_FAILED(pstrUrl->Copy(L"/", 1));
FAILED(hr = pstrDestination->Copy(pszDestinationUrl))) RETURN_IF_FAILED(pstrDestination->Copy(pszDestinationUrl));
{
return hr;
}
} }
else else
{ {
if (FAILED(hr = pstrUrl->Copy(pszSlash)) || RETURN_IF_FAILED(pstrUrl->Copy(pszSlash));
FAILED(hr = pstrDestination->Copy(pszDestinationUrl, RETURN_IF_FAILED(pstrDestination->Copy(pszDestinationUrl,
(DWORD)(pszSlash - pszDestinationUrl)))) (DWORD)(pszSlash - pszDestinationUrl)));
{
return hr;
}
} }
return S_OK; return S_OK;
@ -102,34 +95,28 @@ URL_UTILITY::EscapeAbsPath(
STRU * strEscapedUrl STRU * strEscapedUrl
) )
{ {
HRESULT hr = S_OK;
STRU strAbsPath; STRU strAbsPath;
LPCWSTR pszAbsPath = NULL; LPCWSTR pszAbsPath = NULL;
LPCWSTR pszFindStr = NULL; LPCWSTR pszFindStr = NULL;
hr = strAbsPath.Copy( pRequest->GetRawHttpRequest()->CookedUrl.pAbsPath, RETURN_IF_FAILED(strAbsPath.Copy( pRequest->GetRawHttpRequest()->CookedUrl.pAbsPath,
pRequest->GetRawHttpRequest()->CookedUrl.AbsPathLength / sizeof(WCHAR) ); pRequest->GetRawHttpRequest()->CookedUrl.AbsPathLength / sizeof(WCHAR) ));
if(FAILED(hr))
{
goto Finished;
}
pszAbsPath = strAbsPath.QueryStr(); pszAbsPath = strAbsPath.QueryStr();
pszFindStr = wcschr(pszAbsPath, L'?'); pszFindStr = wcschr(pszAbsPath, L'?');
while(pszFindStr != NULL) while(pszFindStr != NULL)
{ {
strEscapedUrl->Append( pszAbsPath, pszFindStr - pszAbsPath); RETURN_IF_FAILED(strEscapedUrl->Append( pszAbsPath, pszFindStr - pszAbsPath));
strEscapedUrl->Append(L"%3F"); RETURN_IF_FAILED(strEscapedUrl->Append(L"%3F"));
pszAbsPath = pszFindStr + 1; pszAbsPath = pszFindStr + 1;
pszFindStr = wcschr(pszAbsPath, L'?'); pszFindStr = wcschr(pszAbsPath, L'?');
} }
strEscapedUrl->Append(pszAbsPath); RETURN_IF_FAILED(strEscapedUrl->Append(pszAbsPath));
strEscapedUrl->Append(pRequest->GetRawHttpRequest()->CookedUrl.pQueryString, RETURN_IF_FAILED(strEscapedUrl->Append(pRequest->GetRawHttpRequest()->CookedUrl.pQueryString,
pRequest->GetRawHttpRequest()->CookedUrl.QueryStringLength / sizeof(WCHAR)); pRequest->GetRawHttpRequest()->CookedUrl.QueryStringLength / sizeof(WCHAR)));
Finished: return S_OK;
return hr;
} }

View File

@ -28,6 +28,7 @@ This prevents the need for data buffering at the Asp.Net Core Module level.
--*/ --*/
#include "websockethandler.h" #include "websockethandler.h"
#include "exceptions.h"
SRWLOCK WEBSOCKET_HANDLER::sm_RequestsListLock; SRWLOCK WEBSOCKET_HANDLER::sm_RequestsListLock;
@ -270,7 +271,7 @@ Routine Description:
hr = HttpGetExtendedInterface(g_pHttpServer, hr = HttpGetExtendedInterface(g_pHttpServer,
pHttpContext, pHttpContext,
&_pHttpContext); &_pHttpContext);
if (FAILED (hr)) if (FAILED_LOG(hr))
{ {
goto Finished; goto Finished;
} }
@ -338,7 +339,7 @@ Routine Description:
// Initiate Read on IIS // Initiate Read on IIS
// //
hr = DoIisWebSocketReceive(); hr = DoIisWebSocketReceive();
if (FAILED(hr)) if (FAILED_LOG(hr))
{ {
goto Finished; goto Finished;
} }
@ -348,7 +349,7 @@ Routine Description:
// //
hr = DoWinHttpWebSocketReceive(); hr = DoWinHttpWebSocketReceive();
if (FAILED(hr)) if (FAILED_LOG(hr))
{ {
goto Finished; goto Finished;
} }
@ -356,7 +357,7 @@ Routine Description:
Finished: Finished:
LeaveCriticalSection(&_RequestLock); LeaveCriticalSection(&_RequestLock);
if (FAILED (hr)) if (FAILED_LOG(hr))
{ {
DebugPrintf (ASPNETCORE_DEBUG_FLAG_ERROR, DebugPrintf (ASPNETCORE_DEBUG_FLAG_ERROR,
"Process Request Failed with HR=%08x", hr); "Process Request Failed with HR=%08x", hr);
@ -399,7 +400,7 @@ Routine Description:
OnReadIoCompletion, OnReadIoCompletion,
this, this,
NULL); NULL);
if (FAILED(hr)) if (FAILED_LOG(hr))
{ {
DecrementOutstandingIo(); DecrementOutstandingIo();
DebugPrintf(ASPNETCORE_DEBUG_FLAG_ERROR, DebugPrintf(ASPNETCORE_DEBUG_FLAG_ERROR,
@ -498,7 +499,7 @@ Routine Description:
// //
hr = strCloseReason.CopyA((PCSTR)&_WinHttpReceiveBuffer, hr = strCloseReason.CopyA((PCSTR)&_WinHttpReceiveBuffer,
dwReceived); dwReceived);
if (FAILED(hr)) if (FAILED_LOG(hr))
{ {
goto Finished; goto Finished;
} }
@ -549,13 +550,13 @@ Routine Description:
NULL); NULL);
} }
if (FAILED(hr)) if (FAILED_LOG(hr))
{ {
DecrementOutstandingIo(); DecrementOutstandingIo();
} }
Finished: Finished:
if (FAILED(hr)) if (FAILED_LOG(hr))
{ {
DebugPrintf(ASPNETCORE_DEBUG_FLAG_ERROR, DebugPrintf(ASPNETCORE_DEBUG_FLAG_ERROR,
"WEBSOCKET_HANDLER::DoIisWebSocketSend failed with %08x", hr); "WEBSOCKET_HANDLER::DoIisWebSocketSend failed with %08x", hr);
@ -595,7 +596,7 @@ Routine Description:
hr = _pWebSocketContext->GetCloseStatus(&uStatus, hr = _pWebSocketContext->GetCloseStatus(&uStatus,
&pszReason); &pszReason);
if (FAILED(hr)) if (FAILED_LOG(hr))
{ {
goto Finished; goto Finished;
} }
@ -604,7 +605,7 @@ Routine Description:
// Convert status to UTF8 // Convert status to UTF8
// //
hr = strCloseReason.CopyWToUTF8Unescaped(pszReason); hr = strCloseReason.CopyWToUTF8Unescaped(pszReason);
if (FAILED(hr)) if (FAILED_LOG(hr))
{ {
goto Finished; goto Finished;
} }
@ -663,7 +664,7 @@ Routine Description:
} }
Finished: Finished:
if (FAILED(hr)) if (FAILED_LOG(hr))
{ {
DebugPrintf(ASPNETCORE_DEBUG_FLAG_ERROR, DebugPrintf(ASPNETCORE_DEBUG_FLAG_ERROR,
"WEBSOCKET_HANDLER::DoWinHttpWebSocketSend failed with %08x", hr); "WEBSOCKET_HANDLER::DoWinHttpWebSocketSend failed with %08x", hr);
@ -776,7 +777,7 @@ Routine Description:
// //
hr = DoIisWebSocketReceive(); hr = DoIisWebSocketReceive();
if (FAILED(hr)) if (FAILED_LOG(hr))
{ {
goto Finished; goto Finished;
} }
@ -787,7 +788,7 @@ Finished:
LeaveCriticalSection(&_RequestLock); LeaveCriticalSection(&_RequestLock);
} }
if (FAILED (hr)) if (FAILED_LOG(hr))
{ {
Cleanup (cleanupReason); Cleanup (cleanupReason);
@ -877,7 +878,7 @@ Routine Description:
pCompletionStatus->eBufferType pCompletionStatus->eBufferType
); );
if (FAILED (hr)) if (FAILED_LOG(hr))
{ {
cleanupReason = ClientDisconnect; cleanupReason = ClientDisconnect;
goto Finished; goto Finished;
@ -888,7 +889,7 @@ Finished:
{ {
LeaveCriticalSection(&_RequestLock); LeaveCriticalSection(&_RequestLock);
} }
if (FAILED (hr)) if (FAILED_LOG(hr))
{ {
Cleanup (cleanupReason); Cleanup (cleanupReason);
@ -930,7 +931,7 @@ Routine Description:
DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO, "WEBSOCKET_HANDLER::OnIisSendComplete"); DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO, "WEBSOCKET_HANDLER::OnIisSendComplete");
if (FAILED(hrCompletion)) if (FAILED_LOG(hrCompletion))
{ {
hr = hrCompletion; hr = hrCompletion;
cleanupReason = ClientDisconnect; cleanupReason = ClientDisconnect;
@ -957,7 +958,7 @@ Routine Description:
// Write Completed, initiate next read from backend server. // Write Completed, initiate next read from backend server.
// //
hr = DoWinHttpWebSocketReceive(); hr = DoWinHttpWebSocketReceive();
if (FAILED(hr)) if (FAILED_LOG(hr))
{ {
cleanupReason = ServerDisconnect; cleanupReason = ServerDisconnect;
goto Finished; goto Finished;
@ -969,7 +970,7 @@ Finished:
{ {
LeaveCriticalSection(&_RequestLock); LeaveCriticalSection(&_RequestLock);
} }
if (FAILED (hr)) if (FAILED_LOG(hr))
{ {
Cleanup (cleanupReason); Cleanup (cleanupReason);
@ -1016,7 +1017,7 @@ Routine Description:
DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO, DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO,
"WEBSOCKET_HANDLER::OnIisReceiveComplete"); "WEBSOCKET_HANDLER::OnIisReceiveComplete");
if (FAILED(hrCompletion)) if (FAILED_LOG(hrCompletion))
{ {
cleanupReason = ClientDisconnect; cleanupReason = ClientDisconnect;
hr = hrCompletion; hr = hrCompletion;
@ -1049,7 +1050,7 @@ Routine Description:
// //
hr = DoWinHttpWebSocketSend(cbIO, BufferType); hr = DoWinHttpWebSocketSend(cbIO, BufferType);
if (FAILED (hr)) if (FAILED_LOG(hr))
{ {
cleanupReason = ServerDisconnect; cleanupReason = ServerDisconnect;
goto Finished; goto Finished;
@ -1060,7 +1061,7 @@ Finished:
{ {
LeaveCriticalSection(&_RequestLock); LeaveCriticalSection(&_RequestLock);
} }
if (FAILED (hr)) if (FAILED_LOG(hr))
{ {
Cleanup (cleanupReason); Cleanup (cleanupReason);

View File

@ -2,6 +2,7 @@
// Licensed under the MIT License. See License.txt in the project root for license information. // Licensed under the MIT License. See License.txt in the project root for license information.
#include "winhttphelper.h" #include "winhttphelper.h"
#include "exceptions.h"
PFN_WINHTTP_WEBSOCKET_COMPLETE_UPGRADE PFN_WINHTTP_WEBSOCKET_COMPLETE_UPGRADE
WINHTTP_HELPER::sm_pfnWinHttpWebSocketCompleteUpgrade; WINHTTP_HELPER::sm_pfnWinHttpWebSocketCompleteUpgrade;
@ -24,8 +25,6 @@ WINHTTP_HELPER::StaticInitialize(
VOID VOID
) )
{ {
HRESULT hr = S_OK;
// //
// Initialize the function pointers for WinHttp Websocket API's. // Initialize the function pointers for WinHttp Websocket API's.
// //
@ -35,54 +34,29 @@ WINHTTP_HELPER::StaticInitialize(
} }
HMODULE hWinHttp = GetModuleHandleA("winhttp.dll"); HMODULE hWinHttp = GetModuleHandleA("winhttp.dll");
if (hWinHttp == NULL) RETURN_LAST_ERROR_IF (hWinHttp == NULL);
{
hr = HRESULT_FROM_WIN32(GetLastError());
goto Finished;
}
sm_pfnWinHttpWebSocketCompleteUpgrade = (PFN_WINHTTP_WEBSOCKET_COMPLETE_UPGRADE) sm_pfnWinHttpWebSocketCompleteUpgrade = (PFN_WINHTTP_WEBSOCKET_COMPLETE_UPGRADE)
GetProcAddress(hWinHttp, "WinHttpWebSocketCompleteUpgrade"); GetProcAddress(hWinHttp, "WinHttpWebSocketCompleteUpgrade");
if (sm_pfnWinHttpWebSocketCompleteUpgrade == NULL) RETURN_LAST_ERROR_IF (sm_pfnWinHttpWebSocketCompleteUpgrade == NULL);
{
hr = HRESULT_FROM_WIN32(GetLastError());
goto Finished;
}
sm_pfnWinHttpWebSocketQueryCloseStatus = (PFN_WINHTTP_WEBSOCKET_QUERY_CLOSE_STATUS) sm_pfnWinHttpWebSocketQueryCloseStatus = (PFN_WINHTTP_WEBSOCKET_QUERY_CLOSE_STATUS)
GetProcAddress(hWinHttp, "WinHttpWebSocketQueryCloseStatus"); GetProcAddress(hWinHttp, "WinHttpWebSocketQueryCloseStatus");
if (sm_pfnWinHttpWebSocketQueryCloseStatus == NULL) RETURN_LAST_ERROR_IF (sm_pfnWinHttpWebSocketQueryCloseStatus == NULL);
{
hr = HRESULT_FROM_WIN32(GetLastError());
goto Finished;
}
sm_pfnWinHttpWebSocketReceive = (PFN_WINHTTP_WEBSOCKET_RECEIVE) sm_pfnWinHttpWebSocketReceive = (PFN_WINHTTP_WEBSOCKET_RECEIVE)
GetProcAddress(hWinHttp, "WinHttpWebSocketReceive"); GetProcAddress(hWinHttp, "WinHttpWebSocketReceive");
if (sm_pfnWinHttpWebSocketReceive == NULL) RETURN_LAST_ERROR_IF (sm_pfnWinHttpWebSocketReceive == NULL);
{
hr = HRESULT_FROM_WIN32(GetLastError());
goto Finished;
}
sm_pfnWinHttpWebSocketSend = (PFN_WINHTTP_WEBSOCKET_SEND) sm_pfnWinHttpWebSocketSend = (PFN_WINHTTP_WEBSOCKET_SEND)
GetProcAddress(hWinHttp, "WinHttpWebSocketSend"); GetProcAddress(hWinHttp, "WinHttpWebSocketSend");
if (sm_pfnWinHttpWebSocketSend == NULL) RETURN_LAST_ERROR_IF (sm_pfnWinHttpWebSocketSend == NULL);
{
hr = HRESULT_FROM_WIN32(GetLastError());
goto Finished;
}
sm_pfnWinHttpWebSocketShutdown = (PFN_WINHTTP_WEBSOCKET_SHUTDOWN) sm_pfnWinHttpWebSocketShutdown = (PFN_WINHTTP_WEBSOCKET_SHUTDOWN)
GetProcAddress(hWinHttp, "WinHttpWebSocketShutdown"); GetProcAddress(hWinHttp, "WinHttpWebSocketShutdown");
if (sm_pfnWinHttpWebSocketShutdown == NULL) RETURN_LAST_ERROR_IF (sm_pfnWinHttpWebSocketShutdown == NULL);
{
hr = HRESULT_FROM_WIN32(GetLastError());
goto Finished;
}
Finished: return S_OK;
return hr;
} }
@ -170,6 +144,4 @@ WINHTTP_HELPER::GetBufferTypeFromFlags(
*pBufferType = WINHTTP_WEB_SOCKET_BINARY_FRAGMENT_BUFFER_TYPE; *pBufferType = WINHTTP_WEB_SOCKET_BINARY_FRAGMENT_BUFFER_TYPE;
} }
} }
return;
} }

View File

@ -1,195 +0,0 @@
// 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 "FileOutputManager.h"
#include "sttimer.h"
#include "exceptions.h"
#include "debugutil.h"
#include "SRWExclusiveLock.h"
#include "file_utility.h"
FileOutputManager::FileOutputManager() :
m_hLogFileHandle(INVALID_HANDLE_VALUE),
m_fdPreviousStdOut(-1),
m_fdPreviousStdErr(-1),
m_disposed(false)
{
InitializeSRWLock(&m_srwLock);
}
FileOutputManager::~FileOutputManager()
{
Stop();
}
HRESULT
FileOutputManager::Initialize(PCWSTR pwzStdOutLogFileName, PCWSTR pwzApplicationPath)
{
RETURN_IF_FAILED(m_wsApplicationPath.Copy(pwzApplicationPath));
RETURN_IF_FAILED(m_wsStdOutLogFileName.Copy(pwzStdOutLogFileName));
return S_OK;
}
bool FileOutputManager::GetStdOutContent(STRA* struStdOutput)
{
//
// Ungraceful shutdown, try to log an error message.
// This will be a common place for errors as it means the hostfxr_main returned
// or there was an exception.
//
CHAR pzFileContents[4096] = { 0 };
DWORD dwNumBytesRead;
LARGE_INTEGER li = { 0 };
BOOL fLogged = FALSE;
DWORD dwFilePointer = 0;
if (m_hLogFileHandle != INVALID_HANDLE_VALUE)
{
if (GetFileSizeEx(m_hLogFileHandle, &li) && li.LowPart > 0 && li.HighPart == 0)
{
if (li.LowPart > 4096)
{
dwFilePointer = SetFilePointer(m_hLogFileHandle, -4096, NULL, FILE_END);
}
else
{
dwFilePointer = SetFilePointer(m_hLogFileHandle, 0, NULL, FILE_BEGIN);
}
if (dwFilePointer != INVALID_SET_FILE_POINTER)
{
// Read file fails.
if (ReadFile(m_hLogFileHandle, pzFileContents, 4096, &dwNumBytesRead, NULL))
{
if (SUCCEEDED(struStdOutput->Copy(pzFileContents, dwNumBytesRead)))
{
fLogged = TRUE;
}
}
}
}
}
return fLogged;
}
HRESULT
FileOutputManager::Start()
{
SYSTEMTIME systemTime;
SECURITY_ATTRIBUTES saAttr = { 0 };
STRU struPath;
RETURN_IF_FAILED(FILE_UTILITY::ConvertPathToFullPath(
m_wsStdOutLogFileName.QueryStr(),
m_wsApplicationPath.QueryStr(),
&struPath));
RETURN_IF_FAILED(FILE_UTILITY::EnsureDirectoryPathExist(struPath.QueryStr()));
GetSystemTime(&systemTime);
RETURN_IF_FAILED(
m_struLogFilePath.SafeSnwprintf(L"%s_%d%02d%02d%02d%02d%02d_%d.log",
struPath.QueryStr(),
systemTime.wYear,
systemTime.wMonth,
systemTime.wDay,
systemTime.wHour,
systemTime.wMinute,
systemTime.wSecond,
GetCurrentProcessId()));
m_fdPreviousStdOut = _dup(_fileno(stdout));
m_fdPreviousStdErr = _dup(_fileno(stderr));
m_hLogFileHandle = CreateFileW(m_struLogFilePath.QueryStr(),
FILE_READ_DATA | FILE_WRITE_DATA,
FILE_SHARE_READ,
&saAttr,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (m_hLogFileHandle == INVALID_HANDLE_VALUE)
{
return LOG_IF_FAILED(HRESULT_FROM_WIN32(GetLastError()));
}
// There are a few options for redirecting stdout/stderr,
// but there are issues with most of them.
// AllocConsole()
// *stdout = *m_pStdFile;
// *stderr = *m_pStdFile;
// Calling _dup2 on stderr fails on IIS. IIS sets stderr to -2
// _dup2(_fileno(m_pStdFile), _fileno(stdout));
// _dup2(_fileno(m_pStdFile), _fileno(stderr));
// If we were okay setting stdout and stderr to separate files, we could use:
// _wfreopen_s(&m_pStdFile, struLogFileName.QueryStr(), L"w+", stdout);
// _wfreopen_s(&m_pStdFile, struLogFileName.QueryStr(), L"w+", stderr);
// Calling SetStdHandle works for redirecting managed logs, however you cannot
// capture native logs (including hostfxr failures).
RETURN_LAST_ERROR_IF(!SetStdHandle(STD_OUTPUT_HANDLE, m_hLogFileHandle));
RETURN_LAST_ERROR_IF(!SetStdHandle(STD_ERROR_HANDLE, m_hLogFileHandle));
// Periodically flush the log content to file
m_Timer.InitializeTimer(STTIMER::TimerCallback, &m_struLogFilePath, 3000, 3000);
LOG_INFOF("Created log file for inprocess application: %S",
m_struLogFilePath.QueryStr());
return S_OK;
}
HRESULT
FileOutputManager::Stop()
{
if (m_disposed)
{
return S_OK;
}
SRWExclusiveLock lock(m_srwLock);
if (m_disposed)
{
return S_OK;
}
m_disposed = true;
HANDLE handle = NULL;
WIN32_FIND_DATA fileData;
if (m_hLogFileHandle != INVALID_HANDLE_VALUE)
{
m_Timer.CancelTimer();
}
// delete empty log file
handle = FindFirstFile(m_struLogFilePath.QueryStr(), &fileData);
if (handle != INVALID_HANDLE_VALUE &&
handle != NULL &&
fileData.nFileSizeHigh == 0 &&
fileData.nFileSizeLow == 0) // skip check of nFileSizeHigh
{
FindClose(handle);
LOG_LAST_ERROR_IF(!DeleteFile(m_struLogFilePath.QueryStr()));
}
if (m_fdPreviousStdOut >= 0)
{
LOG_LAST_ERROR_IF(!SetStdHandle(STD_OUTPUT_HANDLE, (HANDLE)_get_osfhandle(m_fdPreviousStdOut)));
LOG_INFOF("Restoring original stdout: %d", m_fdPreviousStdOut);
}
if (m_fdPreviousStdErr >= 0)
{
LOG_LAST_ERROR_IF(!SetStdHandle(STD_ERROR_HANDLE, (HANDLE)_get_osfhandle(m_fdPreviousStdErr)));
LOG_INFOF("Restoring original stderr: %d", m_fdPreviousStdOut);
}
return S_OK;
}

View File

@ -193,22 +193,14 @@
<ClInclude Include="AppOfflineTrackingApplication.h" /> <ClInclude Include="AppOfflineTrackingApplication.h" />
<ClInclude Include="environmentvariablehelpers.h" /> <ClInclude Include="environmentvariablehelpers.h" />
<ClInclude Include="filewatcher.h" /> <ClInclude Include="filewatcher.h" />
<ClInclude Include="NullOutputManager.h" />
<ClInclude Include="FileOutputManager.h" />
<ClInclude Include="environmentvariablehash.h" /> <ClInclude Include="environmentvariablehash.h" />
<ClInclude Include="IOutputManager.h" />
<ClInclude Include="LoggingHelpers.h" />
<ClInclude Include="PipeOutputManager.h" />
<ClInclude Include="requesthandler_config.h" /> <ClInclude Include="requesthandler_config.h" />
<ClInclude Include="stdafx.h" /> <ClInclude Include="stdafx.h" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="AppOfflineTrackingApplication.cpp" /> <ClCompile Include="AppOfflineTrackingApplication.cpp" />
<ClCompile Include="FileOutputManager.cpp" />
<ClCompile Include="filewatcher.cpp" /> <ClCompile Include="filewatcher.cpp" />
<ClCompile Include="requesthandler_config.cpp" /> <ClCompile Include="requesthandler_config.cpp" />
<ClCompile Include="LoggingHelpers.cpp" />
<ClCompile Include="PipeOutputManager.cpp" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\CommonLib\CommonLib.vcxproj"> <ProjectReference Include="..\CommonLib\CommonLib.vcxproj">

View File

@ -44,6 +44,11 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting.IIS
} }
public override void Dispose() public override void Dispose()
{
Dispose(gracefulShutdown: false);
}
public override void Dispose(bool gracefulShutdown)
{ {
Stop(); Stop();
@ -128,6 +133,8 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting.IIS
} }
} }
private void GetLogsFromFile() private void GetLogsFromFile()
{ {
try try

View File

@ -151,5 +151,7 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting.IIS
.GetOrAdd("add", "name", ancmVersion) .GetOrAdd("add", "name", ancmVersion)
.SetAttributeValue("image", GetAncmLocation(DeploymentParameters.AncmVersion)); .SetAttributeValue("image", GetAncmLocation(DeploymentParameters.AncmVersion));
} }
public abstract void Dispose(bool gracefulShutdown);
} }
} }

View File

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; using System;
using System.IO;
using System.Linq; using System.Linq;
using System.Xml.Linq; using System.Xml.Linq;
@ -50,5 +51,14 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting.IIS
.SetAttributeValue("enabled", "true"); .SetAttributeValue("enabled", "true");
}); });
} }
public static void EnableLogging(this IISDeploymentParameters deploymentParameters, string path)
{
deploymentParameters.WebConfigActionList.Add(
WebConfigHelpers.AddOrModifyAspNetCoreSection("stdoutLogEnabled", "true"));
deploymentParameters.WebConfigActionList.Add(
WebConfigHelpers.AddOrModifyAspNetCoreSection("stdoutLogFile", Path.Combine(path, "std")));
}
} }
} }

View File

@ -37,7 +37,6 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting.IIS
ServerConfigActionList = tempParameters.ServerConfigActionList; ServerConfigActionList = tempParameters.ServerConfigActionList;
WebConfigBasedEnvironmentVariables = tempParameters.WebConfigBasedEnvironmentVariables; WebConfigBasedEnvironmentVariables = tempParameters.WebConfigBasedEnvironmentVariables;
HandlerSettings = tempParameters.HandlerSettings; HandlerSettings = tempParameters.HandlerSettings;
GracefulShutdown = tempParameters.GracefulShutdown;
} }
} }
@ -49,7 +48,5 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting.IIS
public IDictionary<string, string> HandlerSettings { get; set; } = new Dictionary<string, string>(); public IDictionary<string, string> HandlerSettings { get; set; } = new Dictionary<string, string>();
public bool GracefulShutdown { get; set; }
} }
} }

View File

@ -28,7 +28,7 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting.IIS
private const string FailedToInitializeBindingsMessage = "Failed to initialize site bindings"; private const string FailedToInitializeBindingsMessage = "Failed to initialize site bindings";
private const string UnableToStartIISExpressMessage = "Unable to start iisexpress."; private const string UnableToStartIISExpressMessage = "Unable to start iisexpress.";
private const int MaximumAttempts = 5; private const int MaximumAttempts = 5;
private readonly TimeSpan ShutdownTimeSpan = TimeSpan.FromSeconds(60); private readonly TimeSpan ShutdownTimeSpan = Debugger.IsAttached ? TimeSpan.FromMinutes(60) : TimeSpan.FromMinutes(1);
private static readonly Regex UrlDetectorRegex = new Regex(@"^\s*Successfully registered URL ""(?<url>[^""]+)"" for site.*$"); private static readonly Regex UrlDetectorRegex = new Regex(@"^\s*Successfully registered URL ""(?<url>[^""]+)"" for site.*$");
private Process _hostProcess; private Process _hostProcess;
@ -381,10 +381,15 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting.IIS
} }
public override void Dispose() public override void Dispose()
{
Dispose(gracefulShutdown: false);
}
public override void Dispose(bool gracefulShutdown)
{ {
using (Logger.BeginScope("Dispose")) using (Logger.BeginScope("Dispose"))
{ {
if (IISDeploymentParameters.GracefulShutdown) if (gracefulShutdown)
{ {
GracefullyShutdownProcess(_hostProcess); GracefullyShutdownProcess(_hostProcess);
} }

View File

@ -23,8 +23,9 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
public async Task CheckStartupEventLogMessage() public async Task CheckStartupEventLogMessage()
{ {
var deploymentParameters = _fixture.GetBaseDeploymentParameters(publish: true); var deploymentParameters = _fixture.GetBaseDeploymentParameters(publish: true);
var deploymentResult = await DeployAsync(deploymentParameters); var deploymentResult = await DeployAsync(deploymentParameters);
await Helpers.AssertStarts(deploymentResult); await deploymentResult.AssertStarts();
StopServer(); StopServer();
@ -35,9 +36,8 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
public async Task CheckShutdownEventLogMessage() public async Task CheckShutdownEventLogMessage()
{ {
var deploymentParameters = _fixture.GetBaseDeploymentParameters(publish: true); var deploymentParameters = _fixture.GetBaseDeploymentParameters(publish: true);
deploymentParameters.GracefulShutdown = true;
var deploymentResult = await DeployAsync(deploymentParameters); var deploymentResult = await DeployAsync(deploymentParameters);
await Helpers.AssertStarts(deploymentResult); await deploymentResult.AssertStarts();
StopServer(); StopServer();

View File

@ -2,7 +2,6 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; using System;
using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -47,20 +46,14 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
StopServer(); StopServer();
var fileInDirectory = Directory.GetFiles(pathToLogs).Single(); var fileInDirectory = Directory.GetFiles(pathToLogs).Single(fileName => fileName.Contains("inprocess"));
var contents = File.ReadAllText(fileInDirectory); var contents = File.ReadAllText(fileInDirectory);
Assert.NotNull(contents); Assert.NotNull(contents);
Assert.Contains("TEST MESSAGE", contents); Assert.Contains("TEST MESSAGE", contents);
Assert.DoesNotContain(TestSink.Writes, context => context.Message.Contains("TEST MESSAGE"));
// TODO we should check that debug logs are restored during graceful shutdown.
// The IIS Express deployer doesn't support graceful shutdown.
//Assert.Contains(TestSink.Writes, context => context.Message.Contains("Restoring original stdout: "));
} }
finally finally
{ {
RetryHelper.RetryOperation( RetryHelper.RetryOperation(
() => Directory.Delete(pathToLogs, true), () => Directory.Delete(pathToLogs, true),
e => Logger.LogWarning($"Failed to delete directory : {e.Message}"), e => Logger.LogWarning($"Failed to delete directory : {e.Message}"),
@ -132,7 +125,6 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
public async Task CheckStdoutLoggingToPipe_DoesNotCrashProcess(string path) public async Task CheckStdoutLoggingToPipe_DoesNotCrashProcess(string path)
{ {
var deploymentParameters = _fixture.GetBaseDeploymentParameters(publish: true); var deploymentParameters = _fixture.GetBaseDeploymentParameters(publish: true);
deploymentParameters.GracefulShutdown = true;
var deploymentResult = await DeployAsync(deploymentParameters); var deploymentResult = await DeployAsync(deploymentParameters);
await Helpers.AssertStarts(deploymentResult, path); await Helpers.AssertStarts(deploymentResult, path);
@ -151,7 +143,6 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
public async Task CheckStdoutLoggingToPipeWithFirstWrite(string path) public async Task CheckStdoutLoggingToPipeWithFirstWrite(string path)
{ {
var deploymentParameters = _fixture.GetBaseDeploymentParameters(publish: true); var deploymentParameters = _fixture.GetBaseDeploymentParameters(publish: true);
deploymentParameters.GracefulShutdown = true;
var firstWriteString = path + path; var firstWriteString = path + path;

View File

@ -44,6 +44,7 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
{ {
var parameters = _fixture.GetBaseDeploymentParameters(HostingModel.InProcess, publish: true); var parameters = _fixture.GetBaseDeploymentParameters(HostingModel.InProcess, publish: true);
parameters.ServerConfigActionList.Add(DuplicateApplication); parameters.ServerConfigActionList.Add(DuplicateApplication);
var result = await DeployAsync(parameters); var result = await DeployAsync(parameters);
var result1 = await result.HttpClient.GetAsync("/app1/HelloWorld"); var result1 = await result.HttpClient.GetAsync("/app1/HelloWorld");
var result2 = await result.HttpClient.GetAsync("/app2/HelloWorld"); var result2 = await result.HttpClient.GetAsync("/app2/HelloWorld");

View File

@ -3,6 +3,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Net; using System.Net;
using System.Net.Sockets; using System.Net.Sockets;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -16,6 +17,10 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
[Collection(PublishedSitesCollection.Name)] [Collection(PublishedSitesCollection.Name)]
public class AspNetCorePortTests : IISFunctionalTestBase public class AspNetCorePortTests : IISFunctionalTestBase
{ {
// Port range allowed by ANCM config
private const int _minPort = 1025;
private const int _maxPort = 48000;
private static readonly Random _random = new Random(); private static readonly Random _random = new Random();
private readonly PublishedSitesFixture _fixture; private readonly PublishedSitesFixture _fixture;
@ -31,9 +36,14 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
.WithApplicationTypes(ApplicationType.Portable) .WithApplicationTypes(ApplicationType.Portable)
.WithAllAncmVersions(); .WithAllAncmVersions();
public static IEnumerable<object[]> InvalidTestVariants
=> from v in TestVariants.Select(v => v.Single())
from s in new string[] { (_minPort - 1).ToString(), (_maxPort + 1).ToString(), "noninteger" }
select new object[] { v, s };
[ConditionalTheory] [ConditionalTheory]
[MemberData(nameof(TestVariants))] [MemberData(nameof(TestVariants))]
public async Task EnvVarInWebConfig(TestVariant variant) public async Task EnvVarInWebConfig_Valid(TestVariant variant)
{ {
// Must publish to set env vars in web.config // Must publish to set env vars in web.config
var deploymentParameters = _fixture.GetBaseDeploymentParameters(variant, publish: true); var deploymentParameters = _fixture.GetBaseDeploymentParameters(variant, publish: true);
@ -42,18 +52,44 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
var deploymentResult = await DeployAsync(deploymentParameters); var deploymentResult = await DeployAsync(deploymentParameters);
var response = await deploymentResult.HttpClient.GetAsync("/ServerAddresses"); var responseText = await deploymentResult.HttpClient.GetStringAsync("/ServerAddresses");
var responseText = await response.Content.ReadAsStringAsync();
Assert.Equal(port, new Uri(responseText).Port); Assert.Equal(port, new Uri(responseText).Port);
} }
[ConditionalTheory]
[MemberData(nameof(TestVariants))]
public async Task EnvVarInWebConfig_Empty(TestVariant variant)
{
// Must publish to set env vars in web.config
var deploymentParameters = _fixture.GetBaseDeploymentParameters(variant, publish: true);
deploymentParameters.WebConfigBasedEnvironmentVariables["ASPNETCORE_PORT"] = string.Empty;
var deploymentResult = await DeployAsync(deploymentParameters);
var responseText = await deploymentResult.HttpClient.GetStringAsync("/ServerAddresses");
// If env var is empty, ANCM should assign a random port (same as no env var)
Assert.InRange(new Uri(responseText).Port, _minPort, _maxPort);
}
[ConditionalTheory]
[MemberData(nameof(InvalidTestVariants))]
public async Task EnvVarInWebConfig_Invalid(TestVariant variant, string port)
{
// Must publish to set env vars in web.config
var deploymentParameters = _fixture.GetBaseDeploymentParameters(variant, publish: true);
deploymentParameters.WebConfigBasedEnvironmentVariables["ASPNETCORE_PORT"] = port;
var deploymentResult = await DeployAsync(deploymentParameters);
var response = await deploymentResult.HttpClient.GetAsync("/ServerAddresses");
Assert.Equal(HttpStatusCode.BadGateway, response.StatusCode);
}
private static int GetUnusedRandomPort() private static int GetUnusedRandomPort()
{ {
// Port range allowed by ANCM config
const int minPort = 1025;
const int maxPort = 48000;
// Large number of retries to prevent test failures due to port collisions, but not infinite // Large number of retries to prevent test failures due to port collisions, but not infinite
// to prevent infinite loop in case Bind() fails repeatedly for some other reason. // to prevent infinite loop in case Bind() fails repeatedly for some other reason.
const int retries = 100; const int retries = 100;
@ -62,7 +98,7 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
for (var i = 0; i < retries; i++) for (var i = 0; i < retries; i++)
{ {
var port = _random.Next(minPort, maxPort); var port = _random.Next(_minPort, _maxPort);
using (var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) using (var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
{ {

View File

@ -1,6 +1,8 @@
// Copyright (c) .NET Foundation. All rights reserved. // 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. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Linq;
using System.Text;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using Microsoft.AspNetCore.Server.IntegrationTesting.IIS; using Microsoft.AspNetCore.Server.IntegrationTesting.IIS;
using Microsoft.Extensions.Logging.Testing; using Microsoft.Extensions.Logging.Testing;
@ -14,17 +16,16 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
{ {
Assert.True(deploymentResult.HostProcess.HasExited); Assert.True(deploymentResult.HostProcess.HasExited);
var eventLogRegex = new Regex($"Event Log: {expectedRegexMatchString}"); var builder = new StringBuilder();
int count = 0;
foreach (var context in testSink.Writes) foreach (var context in testSink.Writes)
{ {
if (eventLogRegex.IsMatch(context.Message)) builder.Append(context.Message);
{
count++;
}
} }
Assert.Equal(1, count);
var eventLogRegex = new Regex($"Event Log: (.*?){expectedRegexMatchString}(.*?)End Event Log Message.", RegexOptions.Singleline);
Assert.Matches(eventLogRegex, builder.ToString());
} }
} }
} }

View File

@ -18,7 +18,7 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting
{ {
} }
protected ApplicationDeployer _deployer; protected IISDeployerBase _deployer;
protected ApplicationDeployer CreateDeployer(IISDeploymentParameters parameters) protected ApplicationDeployer CreateDeployer(IISDeploymentParameters parameters)
{ {
@ -38,18 +38,18 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting
protected virtual async Task<IISDeploymentResult> DeployAsync(IISDeploymentParameters parameters) protected virtual async Task<IISDeploymentResult> DeployAsync(IISDeploymentParameters parameters)
{ {
_deployer = CreateDeployer(parameters); _deployer = (IISDeployerBase)CreateDeployer(parameters);
return (IISDeploymentResult)await _deployer.DeployAsync(); return (IISDeploymentResult)await _deployer.DeployAsync();
} }
public override void Dispose() public override void Dispose()
{ {
StopServer(); StopServer(false);
} }
public void StopServer() public void StopServer(bool gracefulShutdown = true)
{ {
_deployer?.Dispose(); _deployer?.Dispose(gracefulShutdown);
_deployer = null; _deployer = null;
} }
} }

View File

@ -0,0 +1,22 @@
// 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;
using Microsoft.AspNetCore.Server.IntegrationTesting;
using Microsoft.AspNetCore.Testing.xunit;
namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
{
[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class | AttributeTargets.Method)]
public sealed class SkipIfDebugAttribute : Attribute, ITestCondition
{
public bool IsMet =>
#if DEBUG
false;
#else
true;
#endif
public string SkipReason => "Test cannot be run in Debug mode.";
}
}

View File

@ -34,6 +34,7 @@ namespace FileOutManagerStartupTests
auto tempDirectory = TempDirectory(); auto tempDirectory = TempDirectory();
FileOutputManager* pManager = new FileOutputManager; FileOutputManager* pManager = new FileOutputManager;
pManager->Initialize(fileNamePrefix.c_str(), tempDirectory.path().c_str()); pManager->Initialize(fileNamePrefix.c_str(), tempDirectory.path().c_str());
{ {
FileManagerWrapper wrapper(pManager); FileManagerWrapper wrapper(pManager);
@ -47,19 +48,17 @@ namespace FileOutManagerStartupTests
ASSERT_EQ(filename.substr(0, fileNamePrefix.size()), fileNamePrefix); ASSERT_EQ(filename.substr(0, fileNamePrefix.size()), fileNamePrefix);
std::wstring content = Helpers::ReadFileContent(std::wstring(p.path())); std::wstring content = Helpers::ReadFileContent(std::wstring(p.path()));
ASSERT_EQ(content.length(), DWORD(4));
ASSERT_STREQ(content.c_str(), expected);
} }
} }
}; };
TEST_F(FileOutputManagerTest, DISABLED_WriteToFileCheckContentsWritten) TEST_F(FileOutputManagerTest, WriteToFileCheckContentsWritten)
{ {
Test(L"", stdout); Test(L"", stdout);
Test(L"log", stdout); Test(L"log", stdout);
} }
TEST_F(FileOutputManagerTest, DISABLED_WriteToFileCheckContentsWrittenErr) TEST_F(FileOutputManagerTest, WriteToFileCheckContentsWrittenErr)
{ {
Test(L"", stderr); Test(L"", stderr);
Test(L"log", stderr); Test(L"log", stderr);
@ -68,8 +67,7 @@ namespace FileOutManagerStartupTests
namespace FileOutManagerOutputTests namespace FileOutManagerOutputTests
{ {
TEST(FileOutManagerOutputTest, StdOut)
TEST(FileOutManagerOutputTest, DISABLED_StdErr)
{ {
PCSTR expected = "test"; PCSTR expected = "test";
@ -80,7 +78,9 @@ namespace FileOutManagerOutputTests
{ {
FileManagerWrapper wrapper(pManager); FileManagerWrapper wrapper(pManager);
printf(expected, stderr); fprintf(stdout, expected);
pManager->Stop();
STRA straContent; STRA straContent;
ASSERT_TRUE(pManager->GetStdOutContent(&straContent)); ASSERT_TRUE(pManager->GetStdOutContent(&straContent));
@ -88,7 +88,7 @@ namespace FileOutManagerOutputTests
} }
} }
TEST(FileOutManagerOutputTest, DISABLED_CheckFileOutput) TEST(FileOutManagerOutputTest, StdErr)
{ {
PCSTR expected = "test"; PCSTR expected = "test";
@ -99,7 +99,9 @@ namespace FileOutManagerOutputTests
{ {
FileManagerWrapper wrapper(pManager); FileManagerWrapper wrapper(pManager);
printf(expected); fprintf(stderr, expected);
pManager->Stop();
STRA straContent; STRA straContent;
ASSERT_TRUE(pManager->GetStdOutContent(&straContent)); ASSERT_TRUE(pManager->GetStdOutContent(&straContent));
@ -107,9 +109,9 @@ namespace FileOutManagerOutputTests
} }
} }
TEST(FileOutManagerOutputTest, DISABLED_CapAt4KB) TEST(FileOutManagerOutputTest, CapAt30KB)
{ {
PCSTR expected = "test"; PCSTR expected = "hello world";
auto tempDirectory = TempDirectory(); auto tempDirectory = TempDirectory();
@ -118,16 +120,39 @@ namespace FileOutManagerOutputTests
{ {
FileManagerWrapper wrapper(pManager); FileManagerWrapper wrapper(pManager);
for (int i = 0; i < 1200; i++) for (int i = 0; i < 3000; i++)
{ {
printf(expected); printf(expected);
} }
pManager->Stop();
STRA straContent; STRA straContent;
ASSERT_TRUE(pManager->GetStdOutContent(&straContent)); ASSERT_TRUE(pManager->GetStdOutContent(&straContent));
ASSERT_EQ(straContent.QueryCCH(), 4096); ASSERT_EQ(straContent.QueryCCH(), 30000);
}
}
TEST(FileOutManagerOutputTest, StartStopRestoresCorrectly)
{
PCSTR expected = "test";
auto tempDirectory = TempDirectory();
for (int i = 0; i < 10; i++)
{
FileOutputManager* pManager = new FileOutputManager;
pManager->Initialize(L"", tempDirectory.path().c_str());
{
FileManagerWrapper wrapper(pManager);
printf(expected);
pManager->Stop();
STRA straContent;
ASSERT_TRUE(pManager->GetStdOutContent(&straContent));
ASSERT_STREQ(straContent.QueryStr(), expected);
}
} }
} }
} }

View File

@ -23,14 +23,58 @@ public:
namespace PipeOutputManagerTests namespace PipeOutputManagerTests
{ {
TEST(PipeManagerOutputTest, NotifyStartupCompleteCallsDispose) TEST(PipeManagerOutputTest, StdOut)
{ {
PCWSTR expected = L"test"; PCWSTR expected = L"test";
STRA output;
PipeOutputManager* pManager = new PipeOutputManager(true);
PipeOutputManager* pManager = new PipeOutputManager();
ASSERT_EQ(S_OK, pManager->Start()); ASSERT_EQ(S_OK, pManager->Start());
fwprintf(stdout, expected);
ASSERT_EQ(S_OK, pManager->Stop());
pManager->GetStdOutContent(&output);
ASSERT_STREQ(output.QueryStr(), "test");
delete pManager;
} }
TEST(PipeManagerOutputTest, StdErr)
{
PCWSTR expected = L"test";
STRA output;
PipeOutputManager* pManager = new PipeOutputManager();
ASSERT_EQ(S_OK, pManager->Start());
fwprintf(stderr, expected);
ASSERT_EQ(S_OK, pManager->Stop());
pManager->GetStdOutContent(&output);
ASSERT_STREQ(output.QueryStr(), "test");
delete pManager;
}
TEST(PipeManagerOutputTest, CheckMaxPipeSize)
{
std::wstring test;
STRA output;
for (int i = 0; i < 3000; i++)
{
test.append(L"hello world");
}
PipeOutputManager* pManager = new PipeOutputManager();
ASSERT_EQ(S_OK, pManager->Start());
wprintf(test.c_str());
ASSERT_EQ(S_OK, pManager->Stop());
pManager->GetStdOutContent(&output);
ASSERT_EQ(output.QueryCCH(), (DWORD)30000);
delete pManager;
}
TEST(PipeManagerOutputTest, SetInvalidHandlesForErrAndOut) TEST(PipeManagerOutputTest, SetInvalidHandlesForErrAndOut)
{ {
auto m_fdPreviousStdOut = _dup(_fileno(stdout)); auto m_fdPreviousStdOut = _dup(_fileno(stdout));
@ -50,6 +94,61 @@ namespace PipeOutputManagerTests
// Test will fail if we didn't redirect stdout back to a file descriptor. // Test will fail if we didn't redirect stdout back to a file descriptor.
// This is because gtest relies on console output to know if a test succeeded or failed. // This is because gtest relies on console output to know if a test succeeded or failed.
// If the output still points to a file/pipe, the test (and all other tests after it) will fail. // If the output still points to a file/pipe, the test (and all other tests after it) will fail.
delete pManager;
}
TEST(PipeManagerOutputTest, CreateDeleteMultipleTimesStdOutWorks)
{
for (int i = 0; i < 10; i++)
{
auto stdoutBefore = _fileno(stdout);
auto stderrBefore = _fileno(stderr);
PCWSTR expected = L"test";
STRA output;
PipeOutputManager* pManager = new PipeOutputManager();
ASSERT_EQ(S_OK, pManager->Start());
fwprintf(stdout, expected);
ASSERT_EQ(S_OK, pManager->Stop());
pManager->GetStdOutContent(&output);
ASSERT_STREQ(output.QueryStr(), "test");
ASSERT_EQ(stdoutBefore, _fileno(stdout));
ASSERT_EQ(stderrBefore, _fileno(stderr));
delete pManager;
}
// When this returns, we get an AV from gtest.
}
TEST(PipeManagerOutputTest, CreateDeleteKeepOriginalStdErr)
{
for (int i = 0; i < 10; i++)
{
auto stdoutBefore = _fileno(stdout);
auto stderrBefore = _fileno(stderr);
auto stdoutHandle = GetStdHandle(STD_OUTPUT_HANDLE);
auto stderrHandle = GetStdHandle(STD_ERROR_HANDLE);
PCWSTR expected = L"test";
STRA output;
PipeOutputManager* pManager = new PipeOutputManager();
ASSERT_EQ(S_OK, pManager->Start());
fwprintf(stderr, expected);
ASSERT_EQ(S_OK, pManager->Stop());
pManager->GetStdOutContent(&output);
ASSERT_STREQ(output.QueryStr(), "test");
ASSERT_EQ(stdoutBefore, _fileno(stdout));
ASSERT_EQ(stderrBefore, _fileno(stderr));
delete pManager;
}
wprintf(L"Hello!");
} }
} }

View File

@ -0,0 +1,171 @@
// 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;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Server.IIS.FunctionalTests.Utilities;
using Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests;
using Microsoft.AspNetCore.Server.IntegrationTesting;
using Microsoft.AspNetCore.Server.IntegrationTesting.IIS;
using Microsoft.AspNetCore.Testing.xunit;
using Newtonsoft.Json;
using Xunit;
namespace IIS.FunctionalTests.Inprocess
{
[Collection(PublishedSitesCollection.Name)]
public class StdOutRedirectionTests : IISFunctionalTestBase
{
private readonly PublishedSitesFixture _fixture;
private readonly string _logFolderPath;
public StdOutRedirectionTests(PublishedSitesFixture fixture)
{
_logFolderPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
_fixture = fixture;
}
public override void Dispose()
{
base.Dispose();
if (Directory.Exists(_logFolderPath))
{
Directory.Delete(_logFolderPath, true);
}
}
[ConditionalFact]
[SkipIfDebug]
public async Task FrameworkNotFoundExceptionLogged_Pipe()
{
var deploymentParameters = _fixture.GetBaseDeploymentParameters(_fixture.StartupExceptionWebsite, publish: true);
var deploymentResult = await DeployAsync(deploymentParameters);
InvalidateRuntimeConfig(deploymentResult);
var response = await deploymentResult.HttpClient.GetAsync("/");
Assert.False(response.IsSuccessStatusCode);
StopServer();
EventLogHelpers.VerifyEventLogEvent(deploymentResult, TestSink,
"The specified framework 'Microsoft.NETCore.App', version '2.9.9' was not found.");
}
[ConditionalFact]
[SkipIfDebug]
public async Task FrameworkNotFoundExceptionLogged_File()
{
var deploymentParameters =
_fixture.GetBaseDeploymentParameters(_fixture.StartupExceptionWebsite, publish: true);
deploymentParameters.EnableLogging(_logFolderPath);
var deploymentResult = await DeployAsync(deploymentParameters);
InvalidateRuntimeConfig(deploymentResult);
var response = await deploymentResult.HttpClient.GetAsync("/");
Assert.False(response.IsSuccessStatusCode);
StopServer();
var fileInDirectory = Directory.GetFiles(_logFolderPath).Single();
var contents = File.ReadAllText(fileInDirectory);
var expectedString = "The specified framework 'Microsoft.NETCore.App', version '2.9.9' was not found.";
EventLogHelpers.VerifyEventLogEvent(deploymentResult, TestSink, expectedString);
Assert.Contains(expectedString, contents);
}
[ConditionalFact]
[SkipIfDebug]
public async Task EnableCoreHostTraceLogging_TwoLogFilesCreated()
{
var deploymentParameters =
_fixture.GetBaseDeploymentParameters(_fixture.StartupExceptionWebsite, publish: true);
deploymentParameters.EnvironmentVariables["COREHOST_TRACE"] = "1";
deploymentParameters.EnableLogging(_logFolderPath);
var deploymentResult = await DeployAsync(deploymentParameters);
var response = await deploymentResult.HttpClient.GetAsync("/");
Assert.False(response.IsSuccessStatusCode);
StopServer();
var filesInDirectory = Directory.GetFiles(_logFolderPath);
Assert.Equal(2, filesInDirectory.Length);
foreach (var file in filesInDirectory)
{
var contents = File.ReadAllText(file);
EventLogHelpers.VerifyEventLogEvent(deploymentResult, TestSink, "Invoked hostfxr");
Assert.Contains("Invoked hostfxr", contents);
}
}
[ConditionalTheory]
[SkipIfDebug]
[InlineData("CheckLargeStdErrWrites")]
[InlineData("CheckLargeStdOutWrites")]
[InlineData("CheckOversizedStdErrWrites")]
[InlineData("CheckOversizedStdOutWrites")]
public async Task EnableCoreHostTraceLogging_PipeCaptureNativeLogs(string path)
{
var deploymentParameters = _fixture.GetBaseDeploymentParameters(_fixture.StartupExceptionWebsite, publish: true);
deploymentParameters.EnvironmentVariables["COREHOST_TRACE"] = "1";
deploymentParameters.WebConfigBasedEnvironmentVariables["ASPNETCORE_INPROCESS_STARTUP_VALUE"] = path;
var deploymentResult = await DeployAsync(deploymentParameters);
var response = await deploymentResult.HttpClient.GetAsync("/");
Assert.False(response.IsSuccessStatusCode);
StopServer();
EventLogHelpers.VerifyEventLogEvent(deploymentResult, TestSink, "Invoked hostfxr");
}
[ConditionalTheory]
[SkipIfDebug]
[InlineData("CheckLargeStdErrWrites")]
[InlineData("CheckLargeStdOutWrites")]
[InlineData("CheckOversizedStdErrWrites")]
[InlineData("CheckOversizedStdOutWrites")]
public async Task EnableCoreHostTraceLogging_FileCaptureNativeLogs(string path)
{
var deploymentParameters =
_fixture.GetBaseDeploymentParameters(_fixture.StartupExceptionWebsite, publish: true);
deploymentParameters.EnvironmentVariables["COREHOST_TRACE"] = "1";
deploymentParameters.WebConfigBasedEnvironmentVariables["ASPNETCORE_INPROCESS_STARTUP_VALUE"] = path;
deploymentParameters.EnableLogging(_logFolderPath);
var deploymentResult = await DeployAsync(deploymentParameters);
var response = await deploymentResult.HttpClient.GetAsync("/");
Assert.False(response.IsSuccessStatusCode);
StopServer();
var fileInDirectory = Directory.GetFiles(_logFolderPath).First();
var contents = File.ReadAllText(fileInDirectory);
EventLogHelpers.VerifyEventLogEvent(deploymentResult, TestSink, "Invoked hostfxr");
Assert.Contains("Invoked hostfxr", contents);
}
private static void InvalidateRuntimeConfig(IISDeploymentResult deploymentResult)
{
var path = Path.Combine(deploymentResult.ContentRoot, "StartupExceptionWebSite.runtimeconfig.json");
dynamic depsFileContent = JsonConvert.DeserializeObject(File.ReadAllText(path));
depsFileContent["runtimeOptions"]["framework"]["version"] = "2.9.9";
var output = JsonConvert.SerializeObject(depsFileContent);
File.WriteAllText(path, output);
}
}
}

View File

@ -42,22 +42,21 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
public async Task GracefulShutdown_DoesNotCrashProcess() public async Task GracefulShutdown_DoesNotCrashProcess()
{ {
var parameters = _fixture.GetBaseDeploymentParameters(publish: true); var parameters = _fixture.GetBaseDeploymentParameters(publish: true);
parameters.GracefulShutdown = true;
var result = await DeployAsync(parameters); var result = await DeployAsync(parameters);
var response = await result.HttpClient.GetAsync("/HelloWorld"); var response = await result.HttpClient.GetAsync("/HelloWorld");
StopServer(); StopServer(gracefulShutdown: true);
Assert.True(result.HostProcess.ExitCode == 0); Assert.True(result.HostProcess.ExitCode == 0);
} }
[ConditionalFact] [ConditionalFact]
public async Task ForcefulShutdown_DoesrashProcess() public async Task ForcefulShutdown_DoesCrashProcess()
{ {
var parameters = _fixture.GetBaseDeploymentParameters(publish: true); var parameters = _fixture.GetBaseDeploymentParameters(publish: true);
var result = await DeployAsync(parameters); var result = await DeployAsync(parameters);
var response = await result.HttpClient.GetAsync("/HelloWorld"); var response = await result.HttpClient.GetAsync("/HelloWorld");
StopServer(); StopServer(gracefulShutdown: false);
Assert.True(result.HostProcess.ExitCode == 1); Assert.True(result.HostProcess.ExitCode == 1);
} }
} }

View File

@ -8,8 +8,8 @@
<FeatureBranchVersionPrefix Condition="'$(FeatureBranchVersionPrefix)' == ''">a-</FeatureBranchVersionPrefix> <FeatureBranchVersionPrefix Condition="'$(FeatureBranchVersionPrefix)' == ''">a-</FeatureBranchVersionPrefix>
<VersionSuffix Condition="'$(VersionSuffix)' != '' And '$(FeatureBranchVersionSuffix)' != ''">$(FeatureBranchVersionPrefix)$(VersionSuffix)-$([System.Text.RegularExpressions.Regex]::Replace('$(FeatureBranchVersionSuffix)', '[^\w-]', '-'))</VersionSuffix> <VersionSuffix Condition="'$(VersionSuffix)' != '' And '$(FeatureBranchVersionSuffix)' != ''">$(FeatureBranchVersionPrefix)$(VersionSuffix)-$([System.Text.RegularExpressions.Regex]::Replace('$(FeatureBranchVersionSuffix)', '[^\w-]', '-'))</VersionSuffix>
<VersionSuffix Condition="'$(VersionSuffix)' != '' And '$(BuildNumber)' != ''">$(VersionSuffix)-$(BuildNumber)</VersionSuffix> <VersionSuffix Condition="'$(VersionSuffix)' != '' And '$(BuildNumber)' != ''">$(VersionSuffix)-$(BuildNumber)</VersionSuffix>
<AspNetCoreModuleVersionMajor>8</AspNetCoreModuleVersionMajor> <AspNetCoreModuleVersionMajor>12</AspNetCoreModuleVersionMajor>
<AspNetCoreModuleVersionMinor>1</AspNetCoreModuleVersionMinor> <AspNetCoreModuleVersionMinor>2</AspNetCoreModuleVersionMinor>
<AspNetCoreModuleVersionRevision>0</AspNetCoreModuleVersionRevision> <AspNetCoreModuleVersionRevision>0</AspNetCoreModuleVersionRevision>
<AspNetCoreModuleOutOfProcessVersion>2.0.0</AspNetCoreModuleOutOfProcessVersion> <AspNetCoreModuleOutOfProcessVersion>2.0.0</AspNetCoreModuleOutOfProcessVersion>
</PropertyGroup> </PropertyGroup>