Merge branch 'merge/release/2.2-to-master'
This commit is contained in:
commit
453d488095
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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."
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
;
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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">
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
@ -4,6 +4,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <Windows.h>
|
||||
#include <ntassert.h>
|
||||
|
||||
struct InvalidHandleTraits
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
@ -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&)
|
||||
|
|
@ -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
|
||||
);
|
||||
};
|
||||
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
@ -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
|
||||
.
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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."
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#ifndef _STTIMER_H
|
||||
#define _STTIMER_H
|
||||
#include "stringu.h"
|
||||
|
||||
class STTIMER
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -224,7 +224,6 @@
|
|||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="aspnetcore_event.h" />
|
||||
<ClInclude Include="disconnectcontext.h" />
|
||||
<ClInclude Include="environmentvariablehelpers.h" />
|
||||
<ClInclude Include="forwarderconnection.h" />
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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">
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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")));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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; }
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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.";
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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!");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
Loading…
Reference in New Issue