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>
<XunitRunnerVisualStudioPackageVersion>2.4.0</XunitRunnerVisualStudioPackageVersion>
</PropertyGroup>
<PropertyGroup Label="Package Versions: Pinned" />
<Import Project="$(DotNetPackageVersionPropsPath)" Condition=" '$(DotNetPackageVersionPropsPath)' != '' " />
<PropertyGroup Label="Package Versions: Pinned" />
</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_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_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_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."

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:
;

View File

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

View File

@ -132,7 +132,7 @@ SERVER_PROCESS::SetupListenPort(
pEnvironmentVarTable->FindKey(ASPNETCORE_PORT_ENV_STR, &pEntry);
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());
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
//
pEnvironmentVarTable->DeleteKey(ASPNETCORE_PORT_ENV_STR);
pEntry->Dereference();
pEntry = NULL;
}
}
@ -1068,8 +1070,8 @@ Finished:
{
if (!fDonePrepareCommandLine)
strEventMsg.SafeSnwprintf(
m_struAppFullPath.QueryStr(),
ASPNETCORE_EVENT_PROCESS_START_INTERNAL_ERROR_MSG,
m_struAppFullPath.QueryStr(),
hr);
else
strEventMsg.SafeSnwprintf(

View File

@ -10,6 +10,8 @@
#include "GlobalVersionUtility.h"
#include "HandleWrapper.h"
#include "file_utility.h"
#include "LoggingHelpers.h"
#include "resources.h"
const PCWSTR HandlerResolver::s_pwzAspnetcoreInProcessRequestHandlerName = L"aspnetcorev2_inprocess.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)
{
std::unique_ptr<HOSTFXR_OPTIONS> options;
std::unique_ptr<IOutputManager> outputManager;
RETURN_IF_FAILED(HOSTFXR_OPTIONS::Create(
NULL,
@ -56,14 +59,35 @@ HandlerResolver::LoadRequestHandlerAssembly(IHttpApplication &pApplication, STRU
RETURN_IF_FAILED(location.Copy(options->GetExeLocation()));
if (FAILED_LOG(hr = FindNativeAssemblyFromHostfxr(options.get(), pstrHandlerDllName, &struFileName)))
{
EventLog::Error(
ASPNETCORE_EVENT_INPROCESS_RH_MISSING,
ASPNETCORE_EVENT_INPROCESS_RH_MISSING_MSG,
struFileName.IsEmpty() ? s_pwzAspnetcoreInProcessRequestHandlerName : struFileName.QueryStr());
RETURN_IF_FAILED(LoggingHelpers::CreateLoggingProvider(
pConfiguration->QueryStdoutLogEnabled(),
!m_pServer.IsCommandLineLaunch(),
pConfiguration->QueryStdoutLogFile()->QueryStr(),
pApplication.GetApplicationPhysicalPath(),
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
@ -188,12 +212,23 @@ HandlerResolver::FindNativeAssemblyFromHostfxr(
BOOL fFound = FALSE;
DWORD dwBufferSize = 1024 * 10;
DWORD dwRequiredBufferSize = 0;
STRA output;
DBG_ASSERT(struFilename != NULL);
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"));
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_IF_FAILED(struNativeSearchPaths.Resize(dwBufferSize));

View File

@ -29,7 +29,7 @@ ASPNETCORE_SHIM_CONFIG::Populate(
CS_ASPNETCORE_PROCESS_EXE_PATH,
&m_struProcessPath));
// Swallow this error for backward compatability
// Swallow this error for backward compatibility
// Use default behavior for empty string
GetElementStringProperty(pAspNetCoreElement,
CS_ASPNETCORE_HOSTING_MODEL,
@ -50,7 +50,7 @@ ASPNETCORE_SHIM_CONFIG::Populate(
ASPNETCORE_EVENT_UNKNOWN_HOSTING_MODEL_ERROR,
ASPNETCORE_EVENT_UNKNOWN_HOSTING_MODEL_ERROR_MSG,
strHostingModel.QueryStr());
RETURN_IF_FAILED(HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED));
RETURN_HR(HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED));
}
RETURN_IF_FAILED(GetElementStringProperty(pAspNetCoreElement,
@ -62,5 +62,13 @@ ASPNETCORE_SHIM_CONFIG::Populate(
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;
}

View File

@ -12,6 +12,8 @@
#define CS_ASPNETCORE_PROCESS_EXE_PATH L"processPath"
#define CS_ASPNETCORE_PROCESS_ARGUMENTS L"arguments"
#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
{
@ -56,6 +58,18 @@ public:
return &m_struHandlerVersion;
}
BOOL
QueryStdoutLogEnabled()
{
return m_fStdoutLogEnabled;
}
STRU*
QueryStdoutLogFile()
{
return &m_struStdoutLogFile;
}
ASPNETCORE_SHIM_CONFIG() :
m_hostingModel(HOSTING_UNKNOWN)
{
@ -67,5 +81,6 @@ private:
STRU m_struProcessPath;
APP_HOSTING_MODEL m_hostingModel;
STRU m_struHandlerVersion;
BOOL m_fStdoutLogEnabled;
STRU m_struStdoutLogFile;
};

View File

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

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 "IOutputManager.h"
#include "HandleWrapper.h"
#include "StdWrapper.h"
#include "stringa.h"
#include "stringu.h"
class FileOutputManager : public IOutputManager
{
#define FILE_FLUSH_TIMEOUT 3000
#define MAX_FILE_READ_SIZE 30000
public:
FileOutputManager();
FileOutputManager(bool fEnableNativeLogging);
~FileOutputManager();
HRESULT
@ -27,9 +32,10 @@ private:
STRU m_wsStdOutLogFileName;
STRU m_wsApplicationPath;
STRU m_struLogFilePath;
int m_fdPreviousStdOut;
int m_fdPreviousStdErr;
STRA m_straFileContent;
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
#include <Windows.h>
#include <ntassert.h>
struct InvalidHandleTraits
{

View File

@ -1,9 +1,11 @@
// 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"
#pragma once
#include "stdafx.h"
#include "stringa.h"
class IOutputManager
{
public:

View File

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

View File

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

View File

@ -5,63 +5,74 @@
#include "PipeOutputManager.h"
#include "exceptions.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_ERRNO(err) do { if (err != 0) { LOG_IF_FAILED(HRESULT_FROM_WIN32(_doserrno)); } } while (0, 0);
PipeOutputManager::PipeOutputManager() :
m_dwStdErrReadTotal(0),
PipeOutputManager::PipeOutputManager()
: PipeOutputManager( /* fEnableNativeLogging */ true)
{
}
PipeOutputManager::PipeOutputManager(bool fEnableNativeLogging) :
m_hErrReadPipe(INVALID_HANDLE_VALUE),
m_hErrWritePipe(INVALID_HANDLE_VALUE),
m_hErrThread(NULL),
m_hErrThread(nullptr),
m_dwStdErrReadTotal(0),
m_disposed(FALSE),
m_fdPreviousStdOut(-1),
m_fdPreviousStdErr(-1)
m_fEnableNativeRedirection(fEnableNativeLogging),
stdoutWrapper(nullptr),
stderrWrapper(nullptr)
{
InitializeSRWLock(&m_srwLock);
}
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()
{
SECURITY_ATTRIBUTES saAttr = { 0 };
HANDLE hStdErrReadPipe;
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*/));
// 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_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(
NULL, // default security attributes
nullptr, // default security attributes
0, // default stack size
(LPTHREAD_START_ROUTINE)ReadStdErrHandle,
reinterpret_cast<LPTHREAD_START_ROUTINE>(ReadStdErrHandle),
this, // thread function arguments
0, // default creation flags
NULL); // receive thread identifier
nullptr); // receive thread identifier
RETURN_LAST_ERROR_IF_NULL(m_hErrThread);
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()
{
DWORD dwThreadStatus = 0;
@ -71,57 +82,53 @@ HRESULT PipeOutputManager::Stop()
{
return S_OK;
}
SRWExclusiveLock lock(m_srwLock);
if (m_disposed)
{
return S_OK;
}
m_disposed = true;
fflush(stdout);
fflush(stderr);
// 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));
}
// Both pipe wrappers duplicate the pipe writer handle
// meaning we are fine to close the handle too.
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);
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.
if (m_hErrThread != NULL &&
if (m_hErrThread != nullptr &&
!LOG_LAST_ERROR_IF(GetExitCodeThread(m_hErrThread, &dwThreadStatus) == 0) &&
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 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) &&
dwThreadStatus == STILL_ACTIVE)
{
@ -131,42 +138,38 @@ HRESULT PipeOutputManager::Stop()
}
}
if (m_hErrThread != NULL)
if (m_hErrThread != nullptr)
{
CloseHandle(m_hErrThread);
m_hErrThread = NULL;
m_hErrThread = nullptr;
}
if (m_hErrReadPipe != INVALID_HANDLE_VALUE)
{
CloseHandle(m_hErrReadPipe);
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))
{
printf(straStdOutput.QueryStr());
// Need to flush contents for the new stdout and stderr
_flushall();
// printf will fail in in full IIS
if (printf(straStdOutput.QueryStr()) != -1)
{
// Need to flush contents for the new stdout and stderr
_flushall();
}
}
return S_OK;
}
VOID
PipeOutputManager::ReadStdErrHandle(
LPVOID pContext
)
{
PipeOutputManager *pLoggingProvider = (PipeOutputManager*)pContext;
DBG_ASSERT(pLoggingProvider != NULL);
pLoggingProvider->ReadStdErrHandleInternal();
}
bool PipeOutputManager::GetStdOutContent(STRA* straStdOutput)
{
bool fLogged = false;
// TODO consider returning the file contents rather than copying.
if (m_dwStdErrReadTotal > 0)
{
if (SUCCEEDED(straStdOutput->Copy(m_pzFileContents, m_dwStdErrReadTotal)))
@ -178,15 +181,29 @@ bool PipeOutputManager::GetStdOutContent(STRA* straStdOutput)
return fLogged;
}
VOID
PipeOutputManager::ReadStdErrHandleInternal(
VOID
void
PipeOutputManager::ReadStdErrHandle(
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;
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;
if (m_dwStdErrReadTotal >= MAX_PIPE_READ_SIZE)
@ -194,19 +211,21 @@ PipeOutputManager::ReadStdErrHandleInternal(
break;
}
}
else if (GetLastError() == ERROR_BROKEN_PIPE)
else
{
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)
{
if (ReadFile(m_hErrReadPipe, tempBuffer, MAX_PIPE_READ_SIZE, &dwNumBytesRead, NULL))
{
}
else if (GetLastError() == ERROR_BROKEN_PIPE)
if (!ReadFile(m_hErrReadPipe, tempBuffer.data(), MAX_PIPE_READ_SIZE, &dwNumBytesRead, nullptr))
{
return;
}

View File

@ -4,35 +4,41 @@
#pragma once
#include "IOutputManager.h"
#include "StdWrapper.h"
#include "stringu.h"
class PipeOutputManager : public IOutputManager
{
// Timeout to be used if a thread never exits
#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:
PipeOutputManager();
PipeOutputManager(bool fEnableNativeLogging);
~PipeOutputManager();
virtual HRESULT Start() override;
virtual HRESULT Stop() override;
virtual bool GetStdOutContent(STRA* struStdOutput) override;
HRESULT Start() override;
HRESULT Stop() override;
bool GetStdOutContent(STRA* straStdOutput) override;
// Thread functions
VOID ReadStdErrHandleInternal(VOID);
void ReadStdErrHandleInternal();
static
VOID ReadStdErrHandle(LPVOID pContext);
static void ReadStdErrHandle(LPVOID pContext);
private:
HANDLE m_hErrReadPipe;
HANDLE m_hErrWritePipe;
STRU m_struLogFilePath;
HANDLE m_hErrThread;
CHAR m_pzFileContents[MAX_PIPE_READ_SIZE] = { 0 };
DWORD m_dwStdErrReadTotal;
SRWLOCK m_srwLock;
int m_fdPreviousStdOut;
int m_fdPreviousStdErr;
SRWLOCK m_srwLock {};
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
SymbolicName=ASPNETCORE_EVENT_GENERAL_INFO_MSG
SymbolicName=ASPNETCORE_EVENT_GENERAL_INFO
Language=English
%1
.
Messageid=1026
SymbolicName=ASPNETCORE_EVENT_GENERAL_WARNING_MSG
SymbolicName=ASPNETCORE_EVENT_GENERAL_WARNING
Language=English
%1
.
Messageid=1027
SymbolicName=ASPNETCORE_EVENT_GENERAL_ERROR_MSG
SymbolicName=ASPNETCORE_EVENT_GENERAL_ERROR
Language=English
%1
.

View File

@ -26,6 +26,8 @@
#endif
#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_CAUGHT_EXCEPTION() return CaughtExceptionHResult(LOCATION_INFO);
#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_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_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_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'"
@ -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_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_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_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_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_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_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_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_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_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_INPROCESS_START_SUCCESS_MSG L"Application '%s' started the coreclr in-process successfully."

View File

@ -6,6 +6,7 @@
#ifndef _STTIMER_H
#define _STTIMER_H
#include "stringu.h"
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:
if (FAILED(hr))
@ -256,24 +250,7 @@ IN_PROCESS_APPLICATION::LoadManagedApplication
}
{
// Set up stdout redirect
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)
{
@ -461,6 +438,20 @@ IN_PROCESS_APPLICATION::ExecuteApplication(
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
// 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
@ -482,7 +473,7 @@ Finished:
//
m_status = MANAGED_APPLICATION_STATUS::SHUTDOWN;
m_fShutdownCalledFromManaged = TRUE;
FreeLibrary(hModule);
m_pLoggerProvider->Stop();
if (!m_fShutdownCalledFromNative)
@ -545,7 +536,6 @@ IN_PROCESS_APPLICATION::RunDotnetApplication(DWORD argc, CONST PCWSTR* argv, hos
__try
{
LOG_INFO("Starting managed application");
m_ProcessExitCode = pProc(argc, argv);
if (m_ProcessExitCode != 0)
{

View File

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

View File

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

View File

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

View File

@ -2,12 +2,13 @@
// Licensed under the MIT License. See License.txt in the project root for license information.
#include "forwarderconnection.h"
#include "exceptions.h"
FORWARDER_CONNECTION::FORWARDER_CONNECTION(
VOID
) : m_cRefs (1),
m_hConnection (NULL)
{
{
}
HRESULT
@ -15,38 +16,19 @@ FORWARDER_CONNECTION::Initialize(
DWORD dwPort
)
{
HRESULT hr = S_OK;
hr = m_ConnectionKey.Initialize( dwPort );
if ( FAILED( hr ) )
{
goto Finished;
}
RETURN_IF_FAILED(m_ConnectionKey.Initialize( dwPort ));
m_hConnection = WinHttpConnect(g_hWinhttpSession,
L"127.0.0.1",
(USHORT) dwPort,
0);
if (m_hConnection == NULL)
{
hr = HRESULT_FROM_WIN32(GetLastError());
goto Finished;
}
RETURN_LAST_ERROR_IF_NULL(m_hConnection);
//
// Since WinHttp will not emit WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING
// 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,
WINHTTP_CALLBACK_FLAG_HANDLES,
NULL) == WINHTTP_INVALID_STATUS_CALLBACK)
{
hr = HRESULT_FROM_WIN32(GetLastError());
goto Finished;
}
Finished:
return hr;
NULL) == WINHTTP_INVALID_STATUS_CALLBACK);
return S_OK;
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -28,6 +28,7 @@ This prevents the need for data buffering at the Asp.Net Core Module level.
--*/
#include "websockethandler.h"
#include "exceptions.h"
SRWLOCK WEBSOCKET_HANDLER::sm_RequestsListLock;
@ -86,7 +87,7 @@ HRESULT
WEBSOCKET_HANDLER::StaticInitialize(
BOOL fEnableReferenceCountTracing
)
/*++
/*++
Routine Description:
@ -145,7 +146,7 @@ WEBSOCKET_HANDLER::InsertRequest(
}
}
//static
//static
VOID
WEBSOCKET_HANDLER::RemoveRequest(
VOID
@ -244,11 +245,11 @@ WEBSOCKET_HANDLER::ProcessRequest(
Routine Description:
Entry point to WebSocket Handler:
This routine is called after the 101 response was successfully sent to
the client.
This routine get's a websocket handle to winhttp,
websocket handle to IIS's websocket context, and initiates IO
the client.
This routine get's a websocket handle to winhttp,
websocket handle to IIS's websocket context, and initiates IO
in these two endpoints.
@ -267,10 +268,10 @@ Routine Description:
//
// Cache the points to IHttpContext3
//
hr = HttpGetExtendedInterface(g_pHttpServer,
pHttpContext,
hr = HttpGetExtendedInterface(g_pHttpServer,
pHttpContext,
&_pHttpContext);
if (FAILED (hr))
if (FAILED_LOG(hr))
{
goto Finished;
}
@ -338,7 +339,7 @@ Routine Description:
// Initiate Read on IIS
//
hr = DoIisWebSocketReceive();
if (FAILED(hr))
if (FAILED_LOG(hr))
{
goto Finished;
}
@ -348,7 +349,7 @@ Routine Description:
//
hr = DoWinHttpWebSocketReceive();
if (FAILED(hr))
if (FAILED_LOG(hr))
{
goto Finished;
}
@ -356,7 +357,7 @@ Routine Description:
Finished:
LeaveCriticalSection(&_RequestLock);
if (FAILED (hr))
if (FAILED_LOG(hr))
{
DebugPrintf (ASPNETCORE_DEBUG_FLAG_ERROR,
"Process Request Failed with HR=%08x", hr);
@ -399,7 +400,7 @@ Routine Description:
OnReadIoCompletion,
this,
NULL);
if (FAILED(hr))
if (FAILED_LOG(hr))
{
DecrementOutstandingIo();
DebugPrintf(ASPNETCORE_DEBUG_FLAG_ERROR,
@ -498,7 +499,7 @@ Routine Description:
//
hr = strCloseReason.CopyA((PCSTR)&_WinHttpReceiveBuffer,
dwReceived);
if (FAILED(hr))
if (FAILED_LOG(hr))
{
goto Finished;
}
@ -549,13 +550,13 @@ Routine Description:
NULL);
}
if (FAILED(hr))
if (FAILED_LOG(hr))
{
DecrementOutstandingIo();
}
Finished:
if (FAILED(hr))
if (FAILED_LOG(hr))
{
DebugPrintf(ASPNETCORE_DEBUG_FLAG_ERROR,
"WEBSOCKET_HANDLER::DoIisWebSocketSend failed with %08x", hr);
@ -592,10 +593,10 @@ Routine Description:
//
// Get Close status from IIS.
//
hr = _pWebSocketContext->GetCloseStatus(&uStatus,
hr = _pWebSocketContext->GetCloseStatus(&uStatus,
&pszReason);
if (FAILED(hr))
if (FAILED_LOG(hr))
{
goto Finished;
}
@ -604,7 +605,7 @@ Routine Description:
// Convert status to UTF8
//
hr = strCloseReason.CopyWToUTF8Unescaped(pszReason);
if (FAILED(hr))
if (FAILED_LOG(hr))
{
goto Finished;
}
@ -663,7 +664,7 @@ Routine Description:
}
Finished:
if (FAILED(hr))
if (FAILED_LOG(hr))
{
DebugPrintf(ASPNETCORE_DEBUG_FLAG_ERROR,
"WEBSOCKET_HANDLER::DoWinHttpWebSocketSend failed with %08x", hr);
@ -691,7 +692,7 @@ WEBSOCKET_HANDLER::OnReadIoCompletion(
--*/
{
WEBSOCKET_HANDLER * pHandler = (WEBSOCKET_HANDLER *)
WEBSOCKET_HANDLER * pHandler = (WEBSOCKET_HANDLER *)
pvCompletionContext;
pHandler->OnIisReceiveComplete(
@ -721,7 +722,7 @@ WEBSOCKET_HANDLER::OnWriteIoCompletion(
--*/
{
WEBSOCKET_HANDLER * pHandler = (WEBSOCKET_HANDLER *)
WEBSOCKET_HANDLER * pHandler = (WEBSOCKET_HANDLER *)
pvCompletionContext;
UNREFERENCED_PARAMETER(fUTF8Encoded);
@ -776,18 +777,18 @@ Routine Description:
//
hr = DoIisWebSocketReceive();
if (FAILED(hr))
if (FAILED_LOG(hr))
{
goto Finished;
}
Finished:
if (fLocked)
if (fLocked)
{
LeaveCriticalSection(&_RequestLock);
}
if (FAILED (hr))
if (FAILED_LOG(hr))
{
Cleanup (cleanupReason);
@ -848,7 +849,7 @@ Routine Description:
Issue send on the Client(IIS) if the receive was
successful.
If the receive completed with zero bytes, that
If the receive completed with zero bytes, that
indicates that the server has disconnected the connection.
Issue cleanup for the websocket handler.
--*/
@ -877,18 +878,18 @@ Routine Description:
pCompletionStatus->eBufferType
);
if (FAILED (hr))
if (FAILED_LOG(hr))
{
cleanupReason = ClientDisconnect;
goto Finished;
}
Finished:
if (fLocked)
if (fLocked)
{
LeaveCriticalSection(&_RequestLock);
}
if (FAILED (hr))
if (FAILED_LOG(hr))
{
Cleanup (cleanupReason);
@ -917,7 +918,7 @@ Routine Description:
Completion callback executed when a send
completes from the client.
If send was successful,issue read on the
If send was successful,issue read on the
server endpoint, to continue the readloop.
--*/
@ -930,7 +931,7 @@ Routine Description:
DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO, "WEBSOCKET_HANDLER::OnIisSendComplete");
if (FAILED(hrCompletion))
if (FAILED_LOG(hrCompletion))
{
hr = hrCompletion;
cleanupReason = ClientDisconnect;
@ -957,7 +958,7 @@ Routine Description:
// Write Completed, initiate next read from backend server.
//
hr = DoWinHttpWebSocketReceive();
if (FAILED(hr))
if (FAILED_LOG(hr))
{
cleanupReason = ServerDisconnect;
goto Finished;
@ -969,7 +970,7 @@ Finished:
{
LeaveCriticalSection(&_RequestLock);
}
if (FAILED (hr))
if (FAILED_LOG(hr))
{
Cleanup (cleanupReason);
@ -1016,7 +1017,7 @@ Routine Description:
DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO,
"WEBSOCKET_HANDLER::OnIisReceiveComplete");
if (FAILED(hrCompletion))
if (FAILED_LOG(hrCompletion))
{
cleanupReason = ClientDisconnect;
hr = hrCompletion;
@ -1029,7 +1030,7 @@ Routine Description:
}
EnterCriticalSection(&_RequestLock);
fLocked = TRUE;
if (_fCleanupInProgress)
{
@ -1049,7 +1050,7 @@ Routine Description:
//
hr = DoWinHttpWebSocketSend(cbIO, BufferType);
if (FAILED (hr))
if (FAILED_LOG(hr))
{
cleanupReason = ServerDisconnect;
goto Finished;
@ -1060,7 +1061,7 @@ Finished:
{
LeaveCriticalSection(&_RequestLock);
}
if (FAILED (hr))
if (FAILED_LOG(hr))
{
Cleanup (cleanupReason);

View File

@ -2,6 +2,7 @@
// Licensed under the MIT License. See License.txt in the project root for license information.
#include "winhttphelper.h"
#include "exceptions.h"
PFN_WINHTTP_WEBSOCKET_COMPLETE_UPGRADE
WINHTTP_HELPER::sm_pfnWinHttpWebSocketCompleteUpgrade;
@ -24,8 +25,6 @@ WINHTTP_HELPER::StaticInitialize(
VOID
)
{
HRESULT hr = S_OK;
//
// Initialize the function pointers for WinHttp Websocket API's.
//
@ -35,54 +34,29 @@ WINHTTP_HELPER::StaticInitialize(
}
HMODULE hWinHttp = GetModuleHandleA("winhttp.dll");
if (hWinHttp == NULL)
{
hr = HRESULT_FROM_WIN32(GetLastError());
goto Finished;
}
RETURN_LAST_ERROR_IF (hWinHttp == NULL);
sm_pfnWinHttpWebSocketCompleteUpgrade = (PFN_WINHTTP_WEBSOCKET_COMPLETE_UPGRADE)
sm_pfnWinHttpWebSocketCompleteUpgrade = (PFN_WINHTTP_WEBSOCKET_COMPLETE_UPGRADE)
GetProcAddress(hWinHttp, "WinHttpWebSocketCompleteUpgrade");
if (sm_pfnWinHttpWebSocketCompleteUpgrade == NULL)
{
hr = HRESULT_FROM_WIN32(GetLastError());
goto Finished;
}
RETURN_LAST_ERROR_IF (sm_pfnWinHttpWebSocketCompleteUpgrade == NULL);
sm_pfnWinHttpWebSocketQueryCloseStatus = (PFN_WINHTTP_WEBSOCKET_QUERY_CLOSE_STATUS)
GetProcAddress(hWinHttp, "WinHttpWebSocketQueryCloseStatus");
if (sm_pfnWinHttpWebSocketQueryCloseStatus == NULL)
{
hr = HRESULT_FROM_WIN32(GetLastError());
goto Finished;
}
RETURN_LAST_ERROR_IF (sm_pfnWinHttpWebSocketQueryCloseStatus == NULL);
sm_pfnWinHttpWebSocketReceive = (PFN_WINHTTP_WEBSOCKET_RECEIVE)
GetProcAddress(hWinHttp, "WinHttpWebSocketReceive");
if (sm_pfnWinHttpWebSocketReceive == NULL)
{
hr = HRESULT_FROM_WIN32(GetLastError());
goto Finished;
}
RETURN_LAST_ERROR_IF (sm_pfnWinHttpWebSocketReceive == NULL);
sm_pfnWinHttpWebSocketSend = (PFN_WINHTTP_WEBSOCKET_SEND)
GetProcAddress(hWinHttp, "WinHttpWebSocketSend");
if (sm_pfnWinHttpWebSocketSend == NULL)
{
hr = HRESULT_FROM_WIN32(GetLastError());
goto Finished;
}
RETURN_LAST_ERROR_IF (sm_pfnWinHttpWebSocketSend == NULL);
sm_pfnWinHttpWebSocketShutdown = (PFN_WINHTTP_WEBSOCKET_SHUTDOWN)
GetProcAddress(hWinHttp, "WinHttpWebSocketShutdown");
if (sm_pfnWinHttpWebSocketShutdown == NULL)
{
hr = HRESULT_FROM_WIN32(GetLastError());
goto Finished;
}
RETURN_LAST_ERROR_IF (sm_pfnWinHttpWebSocketShutdown == NULL);
Finished:
return hr;
return S_OK;
}
@ -170,6 +144,4 @@ WINHTTP_HELPER::GetBufferTypeFromFlags(
*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="environmentvariablehelpers.h" />
<ClInclude Include="filewatcher.h" />
<ClInclude Include="NullOutputManager.h" />
<ClInclude Include="FileOutputManager.h" />
<ClInclude Include="environmentvariablehash.h" />
<ClInclude Include="IOutputManager.h" />
<ClInclude Include="LoggingHelpers.h" />
<ClInclude Include="PipeOutputManager.h" />
<ClInclude Include="requesthandler_config.h" />
<ClInclude Include="stdafx.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="AppOfflineTrackingApplication.cpp" />
<ClCompile Include="FileOutputManager.cpp" />
<ClCompile Include="filewatcher.cpp" />
<ClCompile Include="requesthandler_config.cpp" />
<ClCompile Include="LoggingHelpers.cpp" />
<ClCompile Include="PipeOutputManager.cpp" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\CommonLib\CommonLib.vcxproj">

View File

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

View File

@ -151,5 +151,7 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting.IIS
.GetOrAdd("add", "name", 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.
using System;
using System.IO;
using System.Linq;
using System.Xml.Linq;
@ -50,5 +51,14 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting.IIS
.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;
WebConfigBasedEnvironmentVariables = tempParameters.WebConfigBasedEnvironmentVariables;
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 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 UnableToStartIISExpressMessage = "Unable to start iisexpress.";
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 Process _hostProcess;
@ -381,10 +381,15 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting.IIS
}
public override void Dispose()
{
Dispose(gracefulShutdown: false);
}
public override void Dispose(bool gracefulShutdown)
{
using (Logger.BeginScope("Dispose"))
{
if (IISDeploymentParameters.GracefulShutdown)
if (gracefulShutdown)
{
GracefullyShutdownProcess(_hostProcess);
}

View File

@ -23,8 +23,9 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
public async Task CheckStartupEventLogMessage()
{
var deploymentParameters = _fixture.GetBaseDeploymentParameters(publish: true);
var deploymentResult = await DeployAsync(deploymentParameters);
await Helpers.AssertStarts(deploymentResult);
await deploymentResult.AssertStarts();
StopServer();
@ -35,9 +36,8 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
public async Task CheckShutdownEventLogMessage()
{
var deploymentParameters = _fixture.GetBaseDeploymentParameters(publish: true);
deploymentParameters.GracefulShutdown = true;
var deploymentResult = await DeployAsync(deploymentParameters);
await Helpers.AssertStarts(deploymentResult);
await deploymentResult.AssertStarts();
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.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
@ -47,20 +46,14 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
StopServer();
var fileInDirectory = Directory.GetFiles(pathToLogs).Single();
var fileInDirectory = Directory.GetFiles(pathToLogs).Single(fileName => fileName.Contains("inprocess"));
var contents = File.ReadAllText(fileInDirectory);
Assert.NotNull(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
{
RetryHelper.RetryOperation(
() => Directory.Delete(pathToLogs, true),
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)
{
var deploymentParameters = _fixture.GetBaseDeploymentParameters(publish: true);
deploymentParameters.GracefulShutdown = true;
var deploymentResult = await DeployAsync(deploymentParameters);
await Helpers.AssertStarts(deploymentResult, path);
@ -151,7 +143,6 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
public async Task CheckStdoutLoggingToPipeWithFirstWrite(string path)
{
var deploymentParameters = _fixture.GetBaseDeploymentParameters(publish: true);
deploymentParameters.GracefulShutdown = true;
var firstWriteString = path + path;

View File

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

View File

@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Threading.Tasks;
@ -16,6 +17,10 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
[Collection(PublishedSitesCollection.Name)]
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 readonly PublishedSitesFixture _fixture;
@ -31,9 +36,14 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
.WithApplicationTypes(ApplicationType.Portable)
.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]
[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
var deploymentParameters = _fixture.GetBaseDeploymentParameters(variant, publish: true);
@ -42,18 +52,44 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
var deploymentResult = await DeployAsync(deploymentParameters);
var response = await deploymentResult.HttpClient.GetAsync("/ServerAddresses");
var responseText = await response.Content.ReadAsStringAsync();
var responseText = await deploymentResult.HttpClient.GetStringAsync("/ServerAddresses");
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()
{
// 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
// to prevent infinite loop in case Bind() fails repeatedly for some other reason.
const int retries = 100;
@ -62,7 +98,7 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
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))
{

View File

@ -1,6 +1,8 @@
// 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.Linq;
using System.Text;
using System.Text.RegularExpressions;
using Microsoft.AspNetCore.Server.IntegrationTesting.IIS;
using Microsoft.Extensions.Logging.Testing;
@ -14,17 +16,16 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
{
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)
{
if (eventLogRegex.IsMatch(context.Message))
{
count++;
}
builder.Append(context.Message);
}
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)
{
@ -38,18 +38,18 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting
protected virtual async Task<IISDeploymentResult> DeployAsync(IISDeploymentParameters parameters)
{
_deployer = CreateDeployer(parameters);
_deployer = (IISDeployerBase)CreateDeployer(parameters);
return (IISDeploymentResult)await _deployer.DeployAsync();
}
public override void Dispose()
{
StopServer();
StopServer(false);
}
public void StopServer()
public void StopServer(bool gracefulShutdown = true)
{
_deployer?.Dispose();
_deployer?.Dispose(gracefulShutdown);
_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();
FileOutputManager* pManager = new FileOutputManager;
pManager->Initialize(fileNamePrefix.c_str(), tempDirectory.path().c_str());
{
FileManagerWrapper wrapper(pManager);
@ -47,19 +48,17 @@ namespace FileOutManagerStartupTests
ASSERT_EQ(filename.substr(0, fileNamePrefix.size()), fileNamePrefix);
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"log", stdout);
}
TEST_F(FileOutputManagerTest, DISABLED_WriteToFileCheckContentsWrittenErr)
TEST_F(FileOutputManagerTest, WriteToFileCheckContentsWrittenErr)
{
Test(L"", stderr);
Test(L"log", stderr);
@ -68,8 +67,7 @@ namespace FileOutManagerStartupTests
namespace FileOutManagerOutputTests
{
TEST(FileOutManagerOutputTest, DISABLED_StdErr)
TEST(FileOutManagerOutputTest, StdOut)
{
PCSTR expected = "test";
@ -80,7 +78,9 @@ namespace FileOutManagerOutputTests
{
FileManagerWrapper wrapper(pManager);
printf(expected, stderr);
fprintf(stdout, expected);
pManager->Stop();
STRA straContent;
ASSERT_TRUE(pManager->GetStdOutContent(&straContent));
@ -88,7 +88,7 @@ namespace FileOutManagerOutputTests
}
}
TEST(FileOutManagerOutputTest, DISABLED_CheckFileOutput)
TEST(FileOutManagerOutputTest, StdErr)
{
PCSTR expected = "test";
@ -99,7 +99,9 @@ namespace FileOutManagerOutputTests
{
FileManagerWrapper wrapper(pManager);
printf(expected);
fprintf(stderr, expected);
pManager->Stop();
STRA 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();
@ -118,16 +120,39 @@ namespace FileOutManagerOutputTests
{
FileManagerWrapper wrapper(pManager);
for (int i = 0; i < 1200; i++)
for (int i = 0; i < 3000; i++)
{
printf(expected);
}
pManager->Stop();
STRA 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
{
TEST(PipeManagerOutputTest, NotifyStartupCompleteCallsDispose)
TEST(PipeManagerOutputTest, StdOut)
{
PCWSTR expected = L"test";
STRA output;
PipeOutputManager* pManager = new PipeOutputManager(true);
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");
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)
{
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.
// 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.
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()
{
var parameters = _fixture.GetBaseDeploymentParameters(publish: true);
parameters.GracefulShutdown = true;
var result = await DeployAsync(parameters);
var response = await result.HttpClient.GetAsync("/HelloWorld");
StopServer();
StopServer(gracefulShutdown: true);
Assert.True(result.HostProcess.ExitCode == 0);
}
[ConditionalFact]
public async Task ForcefulShutdown_DoesrashProcess()
public async Task ForcefulShutdown_DoesCrashProcess()
{
var parameters = _fixture.GetBaseDeploymentParameters(publish: true);
var result = await DeployAsync(parameters);
var response = await result.HttpClient.GetAsync("/HelloWorld");
StopServer();
StopServer(gracefulShutdown: false);
Assert.True(result.HostProcess.ExitCode == 1);
}
}

View File

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