add features: flowing authentication info, hosting environment variable support; fix client disconnect and app_offline issues (#102)
resubmit
This commit is contained in:
parent
88cc1c14d0
commit
bce531f61a
|
|
@ -157,7 +157,7 @@
|
|||
<ClInclude Include="Inc\application.h" />
|
||||
<ClInclude Include="Inc\applicationmanager.h" />
|
||||
<ClInclude Include="Inc\aspnetcoreconfig.h" />
|
||||
<ClInclude Include="Inc\aspnetcoreutils.h" />
|
||||
<ClInclude Include="Inc\environmentvariablehash.h" />
|
||||
<ClInclude Include="Inc\debugutil.h" />
|
||||
<ClInclude Include="Inc\filewatcher.h" />
|
||||
<ClInclude Include="Inc\forwarderconnection.h" />
|
||||
|
|
@ -177,7 +177,6 @@
|
|||
<ClCompile Include="Src\application.cxx" />
|
||||
<ClCompile Include="Src\applicationmanager.cxx" />
|
||||
<ClCompile Include="Src\aspnetcoreconfig.cxx" />
|
||||
<ClCompile Include="Src\aspnetcoreutils.cxx" />
|
||||
<ClCompile Include="Src\dllmain.cpp" />
|
||||
<ClCompile Include="Src\filewatcher.cxx" />
|
||||
<ClCompile Include="Src\forwarderconnection.cxx" />
|
||||
|
|
|
|||
|
|
@ -70,10 +70,12 @@ public:
|
|||
VOID
|
||||
)
|
||||
{
|
||||
BOOL fResult = FALSE;
|
||||
BOOL fResult = TRUE;
|
||||
LARGE_INTEGER li = {0};
|
||||
CHAR *pszBuff = NULL;
|
||||
HANDLE handle = CreateFile( m_Path.QueryStr(),
|
||||
HANDLE handle = INVALID_HANDLE_VALUE;
|
||||
|
||||
handle = CreateFile( m_Path.QueryStr(),
|
||||
GENERIC_READ,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||
NULL,
|
||||
|
|
@ -81,8 +83,15 @@ public:
|
|||
FILE_ATTRIBUTE_NORMAL,
|
||||
NULL );
|
||||
|
||||
if( handle == NULL )
|
||||
if( handle == INVALID_HANDLE_VALUE )
|
||||
{
|
||||
if ( GetLastError() == ERROR_FILE_NOT_FOUND )
|
||||
{
|
||||
fResult = FALSE;
|
||||
}
|
||||
|
||||
// This Load() member function is supposed be called only when the change notification event of file creation or file modification happens.
|
||||
// If file is currenlty locked exclusively by other processes, we might get INVALID_HANDLE_VALUE even though the file exists. In that case, we should return TRUE here.
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
|
|
@ -91,8 +100,6 @@ public:
|
|||
goto Finished;
|
||||
}
|
||||
|
||||
fResult = TRUE;
|
||||
|
||||
if( li.HighPart != 0 )
|
||||
{
|
||||
// > 4gb file size not supported
|
||||
|
|
@ -113,10 +120,10 @@ public:
|
|||
}
|
||||
|
||||
Finished:
|
||||
if( handle )
|
||||
if( handle != INVALID_HANDLE_VALUE )
|
||||
{
|
||||
CloseHandle(handle);
|
||||
handle = NULL;
|
||||
handle = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
if( pszBuff != NULL )
|
||||
|
|
|
|||
|
|
@ -5,6 +5,10 @@
|
|||
#define CS_ROOTWEB_CONFIG L"MACHINE/WEBROOT/APPHOST/"
|
||||
#define CS_ROOTWEB_CONFIG_LEN _countof(CS_ROOTWEB_CONFIG)-1
|
||||
#define CS_ASPNETCORE_SECTION L"system.webServer/aspNetCore"
|
||||
#define CS_WINDOWS_AUTHENTICATION_SECTION L"system.webServer/security/authentication/windowsAuthentication"
|
||||
#define CS_BASIC_AUTHENTICATION_SECTION L"system.webServer/security/authentication/basicAuthentication"
|
||||
#define CS_ANONYMOUS_AUTHENTICATION_SECTION L"system.webServer/security/authentication/anonymousAuthentication"
|
||||
#define CS_AUTHENTICATION_ENABLED L"enabled"
|
||||
#define CS_ASPNETCORE_PROCESS_EXE_PATH L"processPath"
|
||||
#define CS_ASPNETCORE_PROCESS_ARGUMENTS L"arguments"
|
||||
#define CS_ASPNETCORE_PROCESS_STARTUP_TIME_LIMIT L"startupTimeLimit"
|
||||
|
|
@ -34,7 +38,6 @@
|
|||
extern HTTP_MODULE_ID g_pModuleId;
|
||||
extern IHttpServer * g_pHttpServer;
|
||||
|
||||
|
||||
class ASPNETCORE_CONFIG : IHttpStoredContext
|
||||
{
|
||||
public:
|
||||
|
|
@ -54,13 +57,13 @@ public:
|
|||
_In_ IHttpContext *pHttpContext,
|
||||
_Out_ ASPNETCORE_CONFIG **ppAspNetCoreConfig
|
||||
);
|
||||
|
||||
MULTISZ*
|
||||
|
||||
ENVIRONMENT_VAR_HASH*
|
||||
QueryEnvironmentVariables(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
return &m_mszEnvironment;
|
||||
return m_pEnvironmentVariables;
|
||||
}
|
||||
|
||||
DWORD
|
||||
|
|
@ -139,6 +142,24 @@ public:
|
|||
return m_fForwardWindowsAuthToken;
|
||||
}
|
||||
|
||||
BOOL
|
||||
QueryWindowsAuthEnabled()
|
||||
{
|
||||
return m_fWindowsAuthEnabled;
|
||||
}
|
||||
|
||||
BOOL
|
||||
QueryBasicAuthEnabled()
|
||||
{
|
||||
return m_fBasicAuthEnabled;
|
||||
}
|
||||
|
||||
BOOL
|
||||
QueryAnonymousAuthEnabled()
|
||||
{
|
||||
return m_fAnonymousAuthEnabled;
|
||||
}
|
||||
|
||||
BOOL
|
||||
QueryDisableStartUpErrorPage()
|
||||
{
|
||||
|
|
@ -155,10 +176,10 @@ private:
|
|||
|
||||
//
|
||||
// private constructor
|
||||
//
|
||||
|
||||
//
|
||||
ASPNETCORE_CONFIG():
|
||||
m_fStdoutLogEnabled( FALSE )
|
||||
m_fStdoutLogEnabled( FALSE ),
|
||||
m_pEnvironmentVariables( NULL )
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -167,18 +188,20 @@ private:
|
|||
IHttpContext *pHttpContext
|
||||
);
|
||||
|
||||
DWORD m_dwRequestTimeoutInMS;
|
||||
DWORD m_dwStartupTimeLimitInMS;
|
||||
DWORD m_dwShutdownTimeLimitInMS;
|
||||
MULTISZ m_mszEnvironment;
|
||||
DWORD m_dwRapidFailsPerMinute;
|
||||
STRU m_struApplication;
|
||||
STRU m_struArguments;
|
||||
STRU m_struProcessPath;
|
||||
BOOL m_fStdoutLogEnabled;
|
||||
STRU m_struStdoutLogFile;
|
||||
DWORD m_dwProcessesPerApplication;
|
||||
BOOL m_fForwardWindowsAuthToken;
|
||||
BOOL m_fDisableStartUpErrorPage;
|
||||
MULTISZ m_mszRecycleOnFileChangeFiles;
|
||||
DWORD m_dwRequestTimeoutInMS;
|
||||
DWORD m_dwStartupTimeLimitInMS;
|
||||
DWORD m_dwShutdownTimeLimitInMS;
|
||||
DWORD m_dwRapidFailsPerMinute;
|
||||
DWORD m_dwProcessesPerApplication;
|
||||
STRU m_struApplication;
|
||||
STRU m_struArguments;
|
||||
STRU m_struProcessPath;
|
||||
STRU m_struStdoutLogFile;
|
||||
BOOL m_fStdoutLogEnabled;
|
||||
BOOL m_fForwardWindowsAuthToken;
|
||||
BOOL m_fDisableStartUpErrorPage;
|
||||
BOOL m_fWindowsAuthEnabled;
|
||||
BOOL m_fBasicAuthEnabled;
|
||||
BOOL m_fAnonymousAuthEnabled;
|
||||
ENVIRONMENT_VAR_HASH* m_pEnvironmentVariables;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,25 +0,0 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
class ASPNETCORE_UTILS
|
||||
{
|
||||
public:
|
||||
|
||||
static
|
||||
HRESULT
|
||||
ReplacePlaceHolderWithValue(
|
||||
_Inout_ LPWSTR pszStr,
|
||||
_In_ LPWSTR pszPlaceholder,
|
||||
_In_ DWORD cchPlaceholder,
|
||||
_In_ DWORD dwValue,
|
||||
_In_ DWORD dwNumDigitsInValue,
|
||||
_Out_ BOOL *pfReplaced
|
||||
);
|
||||
|
||||
private:
|
||||
ASPNETCORE_UTILS()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,146 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
//
|
||||
// The key used for hash-table lookups, consists of the port on which the http process is created.
|
||||
//
|
||||
|
||||
class ENVIRONMENT_VAR_ENTRY
|
||||
{
|
||||
public:
|
||||
ENVIRONMENT_VAR_ENTRY():
|
||||
_cRefs(1)
|
||||
{
|
||||
}
|
||||
|
||||
HRESULT
|
||||
Initialize(
|
||||
PCWSTR pszName,
|
||||
PCWSTR pszValue
|
||||
)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
if (FAILED(hr = _strName.Copy(pszName)) ||
|
||||
FAILED(hr = _strValue.Copy(pszValue)))
|
||||
{
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
VOID
|
||||
Reference() const
|
||||
{
|
||||
InterlockedIncrement(&_cRefs);
|
||||
}
|
||||
|
||||
VOID
|
||||
Dereference() const
|
||||
{
|
||||
if (InterlockedDecrement(&_cRefs) == 0)
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
}
|
||||
|
||||
PWSTR const
|
||||
QueryName()
|
||||
{
|
||||
return _strName.QueryStr();
|
||||
}
|
||||
|
||||
PWSTR const
|
||||
QueryValue()
|
||||
{
|
||||
return _strValue.QueryStr();
|
||||
}
|
||||
|
||||
private:
|
||||
~ENVIRONMENT_VAR_ENTRY()
|
||||
{
|
||||
}
|
||||
|
||||
STRU _strName;
|
||||
STRU _strValue;
|
||||
mutable LONG _cRefs;
|
||||
};
|
||||
|
||||
class ENVIRONMENT_VAR_HASH : public HASH_TABLE<ENVIRONMENT_VAR_ENTRY, PWSTR>
|
||||
{
|
||||
public:
|
||||
ENVIRONMENT_VAR_HASH()
|
||||
{}
|
||||
|
||||
PWSTR
|
||||
ExtractKey(
|
||||
ENVIRONMENT_VAR_ENTRY * pEntry
|
||||
)
|
||||
{
|
||||
return pEntry->QueryName();
|
||||
}
|
||||
|
||||
DWORD
|
||||
CalcKeyHash(
|
||||
PWSTR pszName
|
||||
)
|
||||
{
|
||||
return HashStringNoCase(pszName);
|
||||
}
|
||||
|
||||
BOOL
|
||||
EqualKeys(
|
||||
PWSTR pszName1,
|
||||
PWSTR pszName2
|
||||
)
|
||||
{
|
||||
return (_wcsicmp(pszName1, pszName2) == 0);
|
||||
}
|
||||
|
||||
VOID
|
||||
ReferenceRecord(
|
||||
ENVIRONMENT_VAR_ENTRY * pEntry
|
||||
)
|
||||
{
|
||||
pEntry->Reference();
|
||||
}
|
||||
|
||||
VOID
|
||||
DereferenceRecord(
|
||||
ENVIRONMENT_VAR_ENTRY * pEntry
|
||||
)
|
||||
{
|
||||
pEntry->Dereference();
|
||||
}
|
||||
|
||||
static
|
||||
VOID
|
||||
CopyToMultiSz(
|
||||
ENVIRONMENT_VAR_ENTRY * pEntry,
|
||||
PVOID pvData
|
||||
)
|
||||
{
|
||||
STRU strTemp;
|
||||
MULTISZ *pMultiSz = static_cast<MULTISZ *>(pvData);
|
||||
strTemp.Copy(pEntry->QueryName());
|
||||
strTemp.Append(pEntry->QueryValue());
|
||||
pMultiSz->Append(strTemp.QueryStr());
|
||||
}
|
||||
|
||||
static
|
||||
VOID
|
||||
CopyToTable(
|
||||
ENVIRONMENT_VAR_ENTRY * pEntry,
|
||||
PVOID pvData
|
||||
)
|
||||
{
|
||||
ENVIRONMENT_VAR_ENTRY * pNewEntry = new ENVIRONMENT_VAR_ENTRY();
|
||||
pNewEntry->Initialize(pEntry->QueryName(), pEntry->QueryValue());
|
||||
ENVIRONMENT_VAR_HASH *pHash = static_cast<ENVIRONMENT_VAR_HASH *>(pvData);
|
||||
pHash->InsertRecord(pNewEntry);
|
||||
}
|
||||
|
||||
private:
|
||||
ENVIRONMENT_VAR_HASH(const ENVIRONMENT_VAR_HASH &);
|
||||
void operator=(const ENVIRONMENT_VAR_HASH &);
|
||||
};
|
||||
|
|
@ -1,19 +1,8 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
/*++
|
||||
|
||||
Copyright (c) 2013 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
forwardinghandler.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Handler for handling URLs from out-of-box.
|
||||
|
||||
--*/
|
||||
|
||||
#include "forwarderconnection.h"
|
||||
#include "protocolconfig.h"
|
||||
#include "serverprocess.h"
|
||||
|
|
@ -109,7 +98,13 @@ public:
|
|||
DWORD dwStatusInformationLength
|
||||
)
|
||||
{
|
||||
|
||||
FORWARDING_HANDLER * pThis = static_cast<FORWARDING_HANDLER *>(reinterpret_cast<PVOID>(dwContext));
|
||||
if (pThis == NULL)
|
||||
{
|
||||
//error happened, nothing can be done here
|
||||
return;
|
||||
}
|
||||
DBG_ASSERT(pThis->m_Signature == FORWARDING_HANDLER_SIGNATURE);
|
||||
pThis->OnWinHttpCompletionInternal(hRequest,
|
||||
dwInternetStatus,
|
||||
|
|
@ -186,7 +181,6 @@ private:
|
|||
__in const PROTOCOL_CONFIG * pProtocol,
|
||||
__in HINTERNET hConnect,
|
||||
__inout STRU * pstrUrl,
|
||||
const STRU& strDestination,
|
||||
ASPNETCORE_CONFIG* pAspNetCoreConfig,
|
||||
SERVER_PROCESS* pServerProcess
|
||||
);
|
||||
|
|
@ -201,7 +195,6 @@ private:
|
|||
HRESULT
|
||||
GetHeaders(
|
||||
const PROTOCOL_CONFIG * pProtocol,
|
||||
PCWSTR pszDestination,
|
||||
PCWSTR * ppszHeaders,
|
||||
DWORD * pcchHeaders,
|
||||
ASPNETCORE_CONFIG* pAspNetCoreConfig,
|
||||
|
|
@ -325,6 +318,10 @@ private:
|
|||
bool m_fHandleClosedDueToClient;
|
||||
bool m_fResponseHeadersReceivedAndSet;
|
||||
BOOL m_fDoReverseRewriteHeaders;
|
||||
BOOL m_fErrorHandled;
|
||||
BOOL m_fWebSocketUpgrade;
|
||||
BOOL m_fFinishRequest;
|
||||
BOOL m_fClientDisconnected;
|
||||
DWORD m_msStartTime;
|
||||
|
||||
DWORD m_BytesToReceive;
|
||||
|
|
|
|||
|
|
@ -33,12 +33,6 @@ class PROTOCOL_CONFIG
|
|||
return m_msTimeout;
|
||||
}
|
||||
|
||||
BOOL
|
||||
QueryPreserveHostHeader() const
|
||||
{
|
||||
return m_fPreserveHostHeader;
|
||||
}
|
||||
|
||||
BOOL
|
||||
QueryReverseRewriteHeaders() const
|
||||
{
|
||||
|
|
@ -90,7 +84,6 @@ class PROTOCOL_CONFIG
|
|||
private:
|
||||
|
||||
BOOL m_fKeepAlive;
|
||||
BOOL m_fPreserveHostHeader;
|
||||
BOOL m_fReverseRewriteHeaders;
|
||||
BOOL m_fIncludePortInXForwardedFor;
|
||||
|
||||
|
|
|
|||
|
|
@ -6,14 +6,21 @@
|
|||
#define MIN_PORT 1025
|
||||
#define MAX_PORT 48000
|
||||
#define MAX_RETRY 10
|
||||
#define MAX_ACTIVE_CHILD_PROCESSES 16
|
||||
#define LOCALHOST "127.0.0.1"
|
||||
#define ASPNETCORE_PORT_STR L"ASPNETCORE_PORT"
|
||||
#define ASPNETCORE_PORT_PLACEHOLDER L"%ASPNETCORE_PORT%"
|
||||
#define ASPNETCORE_PORT_PLACEHOLDER_CCH 17
|
||||
#define ASPNETCORE_DEBUG_PORT_STR L"ASPNETCORE_DEBUG_PORT"
|
||||
#define ASPNETCORE_DEBUG_PORT_PLACEHOLDER L"%ASPNETCORE_DEBUG_PORT%"
|
||||
#define ASPNETCORE_DEBUG_PORT_PLACEHOLDER_CCH 23
|
||||
#define MAX_ACTIVE_CHILD_PROCESSES 16
|
||||
#define ASPNETCORE_PORT_ENV_STR L"ASPNETCORE_PORT="
|
||||
#define ASPNETCORE_APP_PATH_ENV_STR L"ASPNETCORE_APPL_PATH="
|
||||
#define ASPNETCORE_APP_TOKEN_ENV_STR L"ASPNETCORE_TOKEN="
|
||||
#define ASPNETCORE_APP_PATH_ENV_STR L"ASPNETCORE_APPL_PATH="
|
||||
#define HOSTING_STARTUP_ASSEMBLIES_ENV_STR L"ASPNETCORE_HOSTINGSTARTUPASSEMBLIES"
|
||||
#define HOSTING_STARTUP_ASSEMBLIES_NAME L"ASPNETCORE_HOSTINGSTARTUPASSEMBLIES="
|
||||
#define HOSTING_STARTUP_ASSEMBLIES_VALUE L"Microsoft.AspNetCore.Server.IISIntegration"
|
||||
#define ASPNETCORE_IIS_AUTH_ENV_STR L"ASPNETCORE_IIS_HTTPAUTH="
|
||||
#define ASPNETCORE_IIS_AUTH_WINDOWS L"windows;"
|
||||
#define ASPNETCORE_IIS_AUTH_BASIC L"basic;"
|
||||
#define ASPNETCORE_IIS_AUTH_ANONYMOUS L"anonymous;"
|
||||
#define ASPNETCORE_IIS_AUTH_NONE L"none"
|
||||
|
||||
class PROCESS_MANAGER;
|
||||
class FORWARDER_CONNECTION;
|
||||
|
|
@ -25,14 +32,17 @@ public:
|
|||
|
||||
HRESULT
|
||||
Initialize(
|
||||
_In_ PROCESS_MANAGER *pProcessManager,
|
||||
_In_ STRU *pszProcessExePath,
|
||||
_In_ STRU *pszArguments,
|
||||
_In_ DWORD dwStartupTimeLimitInMS,
|
||||
_In_ DWORD dwShtudownTimeLimitInMS,
|
||||
_In_ MULTISZ *pszEnvironment,
|
||||
_In_ BOOL fStdoutLogEnabled,
|
||||
_In_ STRU *pstruStdoutLogFile
|
||||
_In_ PROCESS_MANAGER *pProcessManager,
|
||||
_In_ STRU *pszProcessExePath,
|
||||
_In_ STRU *pszArguments,
|
||||
_In_ DWORD dwStartupTimeLimitInMS,
|
||||
_In_ DWORD dwShtudownTimeLimitInMS,
|
||||
_In_ BOOL fWindowsAuthEnabled,
|
||||
_In_ BOOL fBasicAuthEnabled,
|
||||
_In_ BOOL fAnonymousAuthEnabled,
|
||||
_In_ ENVIRONMENT_VAR_HASH* pEnvironmentVariables,
|
||||
_In_ BOOL fStdoutLogEnabled,
|
||||
_In_ STRU *pstruStdoutLogFile
|
||||
);
|
||||
|
||||
|
||||
|
|
@ -66,12 +76,6 @@ public:
|
|||
return m_dwPort;
|
||||
}
|
||||
|
||||
DWORD
|
||||
GetDebugPort()
|
||||
{
|
||||
return m_dwDebugPort;
|
||||
}
|
||||
|
||||
VOID
|
||||
ReferenceServerProcess(
|
||||
VOID
|
||||
|
|
@ -118,6 +122,12 @@ public:
|
|||
_In_ PTP_TIMER Timer
|
||||
);
|
||||
|
||||
LPCWSTR
|
||||
QueryPortStr()
|
||||
{
|
||||
return m_struPort.QueryStr();
|
||||
}
|
||||
|
||||
LPCWSTR
|
||||
QueryFullLogPath()
|
||||
{
|
||||
|
|
@ -159,12 +169,6 @@ private:
|
|||
_In_ LPSTARTUPINFOW pStartupInfo
|
||||
);
|
||||
|
||||
HRESULT
|
||||
CheckIfServerIsUp(
|
||||
_In_ DWORD dwPort,
|
||||
_Out_ BOOL *pfReady
|
||||
);
|
||||
|
||||
HRESULT
|
||||
CheckIfServerIsUp(
|
||||
_In_ DWORD dwPort,
|
||||
|
|
@ -182,13 +186,49 @@ private:
|
|||
GetChildProcessHandles(
|
||||
);
|
||||
|
||||
DWORD
|
||||
GenerateRandomPort(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
return (rand() % (MAX_PORT - MIN_PORT)) + MIN_PORT + 1;
|
||||
}
|
||||
HRESULT
|
||||
SetupListenPort(
|
||||
ENVIRONMENT_VAR_HASH *pEnvironmentVarTable
|
||||
);
|
||||
|
||||
HRESULT
|
||||
SetupAppPath(
|
||||
IHttpContext* pContext,
|
||||
ENVIRONMENT_VAR_HASH* pEnvironmentVarTable
|
||||
);
|
||||
|
||||
HRESULT
|
||||
SetupAppToken(
|
||||
ENVIRONMENT_VAR_HASH* pEnvironmentVarTable
|
||||
);
|
||||
|
||||
HRESULT
|
||||
InitEnvironmentVariablesTable(
|
||||
ENVIRONMENT_VAR_HASH** pEnvironmentVarTable
|
||||
);
|
||||
|
||||
HRESULT
|
||||
OutputEnvironmentVariables(
|
||||
MULTISZ* pmszOutput,
|
||||
ENVIRONMENT_VAR_HASH* pEnvironmentVarTable
|
||||
);
|
||||
|
||||
HRESULT
|
||||
SetupCommandLine(
|
||||
STRU* pstrCommandLine
|
||||
);
|
||||
|
||||
HRESULT
|
||||
PostStartCheck(
|
||||
const STRU* const pStruCommandline,
|
||||
STRU* pStruErrorMessage
|
||||
);
|
||||
|
||||
HRESULT
|
||||
GetRandomPort(
|
||||
DWORD* pdwPickedPort,
|
||||
DWORD dwExcludedPort
|
||||
);
|
||||
|
||||
DWORD
|
||||
GetNumberOfDigits(
|
||||
|
|
@ -213,44 +253,51 @@ private:
|
|||
}
|
||||
|
||||
FORWARDER_CONNECTION *m_pForwarderConnection;
|
||||
HANDLE m_hJobObject;
|
||||
BOOL m_fStdoutLogEnabled;
|
||||
BOOL m_fWindowsAuthEnabled;
|
||||
BOOL m_fBasicAuthEnabled;
|
||||
BOOL m_fAnonymousAuthEnabled;
|
||||
|
||||
STTIMER m_Timer;
|
||||
SOCKET m_socket;
|
||||
|
||||
STRU m_struLogFile;
|
||||
STRU m_struFullLogFile;
|
||||
STTIMER m_Timer;
|
||||
HANDLE m_hStdoutHandle;
|
||||
volatile LONG m_lStopping;
|
||||
volatile BOOL m_fReady;
|
||||
CRITICAL_SECTION m_csLock;
|
||||
SOCKET m_socket;
|
||||
DWORD m_dwPort;
|
||||
DWORD m_dwDebugPort;
|
||||
STRU m_ProcessPath;
|
||||
STRU m_Arguments;
|
||||
STRU m_struAppPath;
|
||||
STRU m_struAppFullPath;
|
||||
STRU m_struPort;
|
||||
STRU m_pszRootApplicationPath;
|
||||
volatile LONG m_lStopping;
|
||||
volatile BOOL m_fReady;
|
||||
mutable LONG m_cRefs;
|
||||
|
||||
DWORD m_dwPort;
|
||||
DWORD m_dwStartupTimeLimitInMS;
|
||||
DWORD m_dwShutdownTimeLimitInMS;
|
||||
MULTISZ m_Environment;
|
||||
mutable LONG m_cRefs;
|
||||
HANDLE m_hProcessWaitHandle;
|
||||
DWORD m_cChildProcess;
|
||||
HANDLE m_hChildProcessWaitHandles[MAX_ACTIVE_CHILD_PROCESSES];
|
||||
DWORD m_dwChildProcessIds[MAX_ACTIVE_CHILD_PROCESSES];
|
||||
DWORD m_dwProcessId;
|
||||
DWORD m_dwListeningProcessId;
|
||||
|
||||
STRA m_straGuid;
|
||||
|
||||
HANDLE m_hJobObject;
|
||||
HANDLE m_hStdoutHandle;
|
||||
//
|
||||
// m_hProcessHandle is the handle to process this object creates.
|
||||
//
|
||||
|
||||
HANDLE m_hProcessHandle;
|
||||
HANDLE m_hListeningProcessHandle;
|
||||
|
||||
HANDLE m_hProcessWaitHandle;
|
||||
//
|
||||
// m_hChildProcessHandle is the handle to process created by
|
||||
// m_hProcessHandle process if it does.
|
||||
//
|
||||
|
||||
HANDLE m_hChildProcessHandles[MAX_ACTIVE_CHILD_PROCESSES];
|
||||
DWORD m_dwChildProcessIds[MAX_ACTIVE_CHILD_PROCESSES];
|
||||
HANDLE m_hChildProcessWaitHandles[MAX_ACTIVE_CHILD_PROCESSES];
|
||||
|
||||
PROCESS_MANAGER *m_pProcessManager;
|
||||
ENVIRONMENT_VAR_HASH *m_pEnvironmentVarTable ;
|
||||
};
|
||||
|
|
@ -5,6 +5,12 @@
|
|||
|
||||
APPLICATION::~APPLICATION()
|
||||
{
|
||||
if (m_pAppOfflineHtm != NULL)
|
||||
{
|
||||
m_pAppOfflineHtm->DereferenceAppOfflineHtm();
|
||||
m_pAppOfflineHtm = NULL;
|
||||
}
|
||||
|
||||
if (m_pFileWatcherEntry != NULL)
|
||||
{
|
||||
// Mark the entry as invalid,
|
||||
|
|
@ -109,6 +115,7 @@ APPLICATION::UpdateAppOfflineFileHandle()
|
|||
STRU strFilePath;
|
||||
PATH::ConvertPathToFullPath(L".\\app_offline.htm", m_strAppPhysicalPath.QueryStr(), &strFilePath);
|
||||
APP_OFFLINE_HTM *pOldAppOfflineHtm = NULL;
|
||||
APP_OFFLINE_HTM *pNewAppOfflineHtm = NULL;
|
||||
|
||||
if (INVALID_FILE_ATTRIBUTES == GetFileAttributes(strFilePath.QueryStr()) && GetLastError() == ERROR_FILE_NOT_FOUND)
|
||||
{
|
||||
|
|
@ -117,30 +124,41 @@ APPLICATION::UpdateAppOfflineFileHandle()
|
|||
else
|
||||
{
|
||||
m_fAppOfflineFound = TRUE;
|
||||
APP_OFFLINE_HTM *pNewAppOfflineHtm = new APP_OFFLINE_HTM(strFilePath.QueryStr());
|
||||
|
||||
DBG_ASSERT(pNewAppOfflineHtm != NULL);
|
||||
//
|
||||
// send shutdown signal
|
||||
//
|
||||
|
||||
if (pNewAppOfflineHtm->Load())
|
||||
// The reason why we send the shutdown signal before loading the new app_offline file is because we want to make some delay
|
||||
// before reading the appoffline.htm so that the file change can be done on time.
|
||||
if (m_pProcessManager != NULL)
|
||||
{
|
||||
//
|
||||
// loaded new app offline htm
|
||||
//
|
||||
pOldAppOfflineHtm = (APP_OFFLINE_HTM *)InterlockedExchangePointer((VOID**)&m_pAppOfflineHtm, pNewAppOfflineHtm);
|
||||
m_pProcessManager->SendShutdownSignal();
|
||||
}
|
||||
|
||||
//
|
||||
// send shutdown signal to the app
|
||||
//
|
||||
if (m_pProcessManager != NULL)
|
||||
pNewAppOfflineHtm = new APP_OFFLINE_HTM(strFilePath.QueryStr());
|
||||
|
||||
if ( pNewAppOfflineHtm != NULL )
|
||||
{
|
||||
if (pNewAppOfflineHtm->Load())
|
||||
{
|
||||
m_pProcessManager->SendShutdownSignal();
|
||||
//
|
||||
// loaded the new app_offline.htm
|
||||
//
|
||||
pOldAppOfflineHtm = (APP_OFFLINE_HTM *)InterlockedExchangePointer((VOID**)&m_pAppOfflineHtm, pNewAppOfflineHtm);
|
||||
|
||||
if (pOldAppOfflineHtm != NULL)
|
||||
{
|
||||
pOldAppOfflineHtm->DereferenceAppOfflineHtm();
|
||||
pOldAppOfflineHtm = NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// ignored the new app_offline file because the file does not exist.
|
||||
pNewAppOfflineHtm->DereferenceAppOfflineHtm();
|
||||
pNewAppOfflineHtm = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (pOldAppOfflineHtm != NULL)
|
||||
{
|
||||
pOldAppOfflineHtm->DereferenceAppOfflineHtm();
|
||||
pOldAppOfflineHtm = NULL;
|
||||
}
|
||||
}
|
||||
|
|
@ -12,6 +12,12 @@ ASPNETCORE_CONFIG::~ASPNETCORE_CONFIG()
|
|||
{
|
||||
APPLICATION_MANAGER::GetInstance()->RecycleApplication(m_struApplication.QueryStr());
|
||||
}
|
||||
if(m_pEnvironmentVariables != NULL)
|
||||
{
|
||||
m_pEnvironmentVariables->Clear();
|
||||
delete m_pEnvironmentVariables;
|
||||
m_pEnvironmentVariables = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT
|
||||
|
|
@ -24,7 +30,7 @@ ASPNETCORE_CONFIG::GetConfig(
|
|||
IHttpApplication *pHttpApplication = pHttpContext->GetApplication();
|
||||
ASPNETCORE_CONFIG *pAspNetCoreConfig = NULL;
|
||||
|
||||
if( ppAspNetCoreConfig == NULL)
|
||||
if (ppAspNetCoreConfig == NULL)
|
||||
{
|
||||
hr = E_INVALIDARG;
|
||||
goto Finished;
|
||||
|
|
@ -33,10 +39,10 @@ ASPNETCORE_CONFIG::GetConfig(
|
|||
*ppAspNetCoreConfig = NULL;
|
||||
|
||||
// potential bug if user sepcific config at virtual dir level
|
||||
pAspNetCoreConfig = (ASPNETCORE_CONFIG*)
|
||||
pAspNetCoreConfig = (ASPNETCORE_CONFIG*)
|
||||
pHttpApplication->GetModuleContextContainer()->GetModuleContext(g_pModuleId);
|
||||
|
||||
if( pAspNetCoreConfig != NULL )
|
||||
if (pAspNetCoreConfig != NULL)
|
||||
{
|
||||
*ppAspNetCoreConfig = pAspNetCoreConfig;
|
||||
pAspNetCoreConfig = NULL;
|
||||
|
|
@ -44,31 +50,31 @@ ASPNETCORE_CONFIG::GetConfig(
|
|||
}
|
||||
|
||||
pAspNetCoreConfig = new ASPNETCORE_CONFIG;
|
||||
if( pAspNetCoreConfig == NULL )
|
||||
if (pAspNetCoreConfig == NULL)
|
||||
{
|
||||
hr = E_OUTOFMEMORY;
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
hr = pAspNetCoreConfig->Populate( pHttpContext );
|
||||
if( FAILED( hr ) )
|
||||
hr = pAspNetCoreConfig->Populate(pHttpContext);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
hr = pHttpApplication->GetModuleContextContainer()->
|
||||
SetModuleContext( pAspNetCoreConfig, g_pModuleId );
|
||||
if( FAILED( hr ) )
|
||||
SetModuleContext(pAspNetCoreConfig, g_pModuleId);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
if( hr == HRESULT_FROM_WIN32( ERROR_ALREADY_ASSIGNED ) )
|
||||
if (hr == HRESULT_FROM_WIN32(ERROR_ALREADY_ASSIGNED))
|
||||
{
|
||||
delete pAspNetCoreConfig;
|
||||
|
||||
pAspNetCoreConfig = (ASPNETCORE_CONFIG*) pHttpApplication->
|
||||
GetModuleContextContainer()->
|
||||
GetModuleContext( g_pModuleId );
|
||||
pAspNetCoreConfig = (ASPNETCORE_CONFIG*)pHttpApplication->
|
||||
GetModuleContextContainer()->
|
||||
GetModuleContext(g_pModuleId);
|
||||
|
||||
_ASSERT( pAspNetCoreConfig != NULL );
|
||||
_ASSERT(pAspNetCoreConfig != NULL);
|
||||
|
||||
hr = S_OK;
|
||||
}
|
||||
|
|
@ -79,8 +85,8 @@ ASPNETCORE_CONFIG::GetConfig(
|
|||
}
|
||||
else
|
||||
{
|
||||
// set appliction info here instead of inside Populate()
|
||||
// as the destructor will delete the backend process
|
||||
// set appliction info here instead of inside Populate()
|
||||
// as the destructor will delete the backend process
|
||||
hr = pAspNetCoreConfig->QueryApplicationPath()->Copy(pHttpApplication->GetApplicationId());
|
||||
if (FAILED(hr))
|
||||
{
|
||||
|
|
@ -93,7 +99,7 @@ ASPNETCORE_CONFIG::GetConfig(
|
|||
|
||||
Finished:
|
||||
|
||||
if( pAspNetCoreConfig != NULL )
|
||||
if (pAspNetCoreConfig != NULL)
|
||||
{
|
||||
delete pAspNetCoreConfig;
|
||||
pAspNetCoreConfig = NULL;
|
||||
|
|
@ -102,82 +108,134 @@ Finished:
|
|||
return hr;
|
||||
}
|
||||
|
||||
VOID ReverseMultisz( MULTISZ * pmszInput,
|
||||
LPCWSTR pszStr,
|
||||
MULTISZ * pmszOutput )
|
||||
{
|
||||
if(pszStr == NULL) return;
|
||||
|
||||
ReverseMultisz( pmszInput, pmszInput->Next( pszStr ), pmszOutput );
|
||||
|
||||
pmszOutput->Append( pszStr );
|
||||
}
|
||||
|
||||
HRESULT
|
||||
ASPNETCORE_CONFIG::Populate(
|
||||
IHttpContext *pHttpContext
|
||||
)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
STACK_STRU ( strSiteConfigPath, 256);
|
||||
STACK_STRU(strSiteConfigPath, 256);
|
||||
STRU strEnvName;
|
||||
STRU strEnvValue;
|
||||
STRU strFullEnvVar;
|
||||
STRU strExpandedEnvValue;
|
||||
IAppHostAdminManager *pAdminManager = NULL;
|
||||
IAppHostElement *pAspNetCoreElement = NULL;
|
||||
IAppHostElement *pWindowsAuthenticationElement = NULL;
|
||||
IAppHostElement *pBasicAuthenticationElement = NULL;
|
||||
IAppHostElement *pAnonymousAuthenticationElement = NULL;
|
||||
IAppHostElement *pEnvVarList = NULL;
|
||||
IAppHostElementCollection *pEnvVarCollection = NULL;
|
||||
IAppHostElement *pEnvVar = NULL;
|
||||
//IAppHostElement *pRecycleOnFileChangeFileList = NULL;
|
||||
//IAppHostElementCollection *pRecycleOnFileChangeFileCollection = NULL;
|
||||
//IAppHostElement *pRecycleOnFileChangeFile = NULL;
|
||||
IAppHostElementCollection *pEnvVarCollection = NULL;
|
||||
ULONGLONG ullRawTimeSpan = 0;
|
||||
ENUM_INDEX index;
|
||||
STRU strExpandedEnvValue;
|
||||
MULTISZ mszEnvironment;
|
||||
MULTISZ mszEnvironmentListReverse;
|
||||
MULTISZ mszEnvNames;
|
||||
LPWSTR pszEnvName;
|
||||
LPCWSTR pcszEnvName;
|
||||
LPCWSTR pszEnvString;
|
||||
STRU strFilePath;
|
||||
ENVIRONMENT_VAR_ENTRY* pEntry = NULL;
|
||||
|
||||
m_pEnvironmentVariables = new ENVIRONMENT_VAR_HASH();
|
||||
if (m_pEnvironmentVariables == NULL)
|
||||
{
|
||||
hr = E_OUTOFMEMORY;
|
||||
goto Finished;
|
||||
}
|
||||
if (FAILED(hr = m_pEnvironmentVariables->Initialize(37 /*prime*/)))
|
||||
{
|
||||
delete m_pEnvironmentVariables;
|
||||
m_pEnvironmentVariables = NULL;
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
pAdminManager = g_pHttpServer->GetAdminManager();
|
||||
|
||||
hr = strSiteConfigPath.Copy( pHttpContext->GetApplication()->GetAppConfigPath() );
|
||||
if( FAILED( hr ) )
|
||||
hr = strSiteConfigPath.Copy(pHttpContext->GetApplication()->GetAppConfigPath());
|
||||
if (FAILED(hr))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
hr = pAdminManager->GetAdminSection( CS_ASPNETCORE_SECTION,
|
||||
strSiteConfigPath.QueryStr(),
|
||||
&pAspNetCoreElement );
|
||||
if( FAILED( hr ) )
|
||||
hr = pAdminManager->GetAdminSection(CS_WINDOWS_AUTHENTICATION_SECTION,
|
||||
strSiteConfigPath.QueryStr(),
|
||||
&pWindowsAuthenticationElement);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
// assume the corresponding authen was not enabled
|
||||
// as the section may get deleted by user in some HWC case
|
||||
// ToDo: log a warning to event log
|
||||
m_fWindowsAuthEnabled = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
hr = GetElementBoolProperty(pWindowsAuthenticationElement,
|
||||
CS_AUTHENTICATION_ENABLED,
|
||||
&m_fWindowsAuthEnabled);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
}
|
||||
|
||||
hr = pAdminManager->GetAdminSection(CS_BASIC_AUTHENTICATION_SECTION,
|
||||
strSiteConfigPath.QueryStr(),
|
||||
&pBasicAuthenticationElement);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
m_fBasicAuthEnabled = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
hr = GetElementBoolProperty(pBasicAuthenticationElement,
|
||||
CS_AUTHENTICATION_ENABLED,
|
||||
&m_fBasicAuthEnabled);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
}
|
||||
|
||||
hr = pAdminManager->GetAdminSection(CS_ANONYMOUS_AUTHENTICATION_SECTION,
|
||||
strSiteConfigPath.QueryStr(),
|
||||
&pAnonymousAuthenticationElement);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
m_fAnonymousAuthEnabled = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
hr = GetElementBoolProperty(pAnonymousAuthenticationElement,
|
||||
CS_AUTHENTICATION_ENABLED,
|
||||
&m_fAnonymousAuthEnabled);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
}
|
||||
|
||||
hr = pAdminManager->GetAdminSection(CS_ASPNETCORE_SECTION,
|
||||
strSiteConfigPath.QueryStr(),
|
||||
&pAspNetCoreElement);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
hr = GetElementStringProperty( pAspNetCoreElement,
|
||||
CS_ASPNETCORE_PROCESS_EXE_PATH,
|
||||
&m_struProcessPath );
|
||||
if( FAILED( hr ) )
|
||||
hr = GetElementStringProperty(pAspNetCoreElement,
|
||||
CS_ASPNETCORE_PROCESS_EXE_PATH,
|
||||
&m_struProcessPath);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
hr = GetElementStringProperty( pAspNetCoreElement,
|
||||
CS_ASPNETCORE_PROCESS_ARGUMENTS,
|
||||
&m_struArguments );
|
||||
if( FAILED( hr ) )
|
||||
hr = GetElementStringProperty(pAspNetCoreElement,
|
||||
CS_ASPNETCORE_PROCESS_ARGUMENTS,
|
||||
&m_struArguments);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
hr = GetElementDWORDProperty( pAspNetCoreElement,
|
||||
CS_ASPNETCORE_RAPID_FAILS_PER_MINUTE,
|
||||
&m_dwRapidFailsPerMinute );
|
||||
if( FAILED( hr ) )
|
||||
hr = GetElementDWORDProperty(pAspNetCoreElement,
|
||||
CS_ASPNETCORE_RAPID_FAILS_PER_MINUTE,
|
||||
&m_dwRapidFailsPerMinute);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
|
@ -185,298 +243,173 @@ ASPNETCORE_CONFIG::Populate(
|
|||
//
|
||||
// rapidFailsPerMinute cannot be greater than 100.
|
||||
//
|
||||
|
||||
if(m_dwRapidFailsPerMinute > MAX_RAPID_FAILS_PER_MINUTE)
|
||||
if (m_dwRapidFailsPerMinute > MAX_RAPID_FAILS_PER_MINUTE)
|
||||
{
|
||||
m_dwRapidFailsPerMinute = MAX_RAPID_FAILS_PER_MINUTE;
|
||||
}
|
||||
|
||||
hr = GetElementDWORDProperty( pAspNetCoreElement,
|
||||
CS_ASPNETCORE_PROCESSES_PER_APPLICATION,
|
||||
&m_dwProcessesPerApplication );
|
||||
if( FAILED( hr ) )
|
||||
hr = GetElementDWORDProperty(pAspNetCoreElement,
|
||||
CS_ASPNETCORE_PROCESSES_PER_APPLICATION,
|
||||
&m_dwProcessesPerApplication);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
hr = GetElementDWORDProperty(
|
||||
pAspNetCoreElement,
|
||||
CS_ASPNETCORE_PROCESS_STARTUP_TIME_LIMIT,
|
||||
&m_dwStartupTimeLimitInMS
|
||||
);
|
||||
if( FAILED( hr ) )
|
||||
hr = GetElementDWORDProperty(
|
||||
pAspNetCoreElement,
|
||||
CS_ASPNETCORE_PROCESS_STARTUP_TIME_LIMIT,
|
||||
&m_dwStartupTimeLimitInMS
|
||||
);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
|
||||
m_dwStartupTimeLimitInMS *= MILLISECONDS_IN_ONE_SECOND;
|
||||
|
||||
hr = GetElementDWORDProperty(
|
||||
pAspNetCoreElement,
|
||||
CS_ASPNETCORE_PROCESS_SHUTDOWN_TIME_LIMIT,
|
||||
&m_dwShutdownTimeLimitInMS
|
||||
);
|
||||
);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
m_dwShutdownTimeLimitInMS *= MILLISECONDS_IN_ONE_SECOND;
|
||||
|
||||
hr = GetElementBoolProperty( pAspNetCoreElement,
|
||||
CS_ASPNETCORE_FORWARD_WINDOWS_AUTH_TOKEN,
|
||||
&m_fForwardWindowsAuthToken );
|
||||
if( FAILED( hr ) )
|
||||
hr = GetElementBoolProperty(pAspNetCoreElement,
|
||||
CS_ASPNETCORE_FORWARD_WINDOWS_AUTH_TOKEN,
|
||||
&m_fForwardWindowsAuthToken);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
hr = GetElementBoolProperty(pAspNetCoreElement,
|
||||
CS_ASPNETCORE_DISABLE_START_UP_ERROR_PAGE,
|
||||
&m_fDisableStartUpErrorPage);
|
||||
CS_ASPNETCORE_DISABLE_START_UP_ERROR_PAGE,
|
||||
&m_fDisableStartUpErrorPage);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
hr = GetElementRawTimeSpanProperty(
|
||||
pAspNetCoreElement,
|
||||
CS_ASPNETCORE_WINHTTP_REQUEST_TIMEOUT,
|
||||
&ullRawTimeSpan
|
||||
);
|
||||
if( FAILED( hr ) )
|
||||
|
||||
hr = GetElementRawTimeSpanProperty(
|
||||
pAspNetCoreElement,
|
||||
CS_ASPNETCORE_WINHTTP_REQUEST_TIMEOUT,
|
||||
&ullRawTimeSpan
|
||||
);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
|
||||
m_dwRequestTimeoutInMS = (DWORD)TIMESPAN_IN_MILLISECONDS(ullRawTimeSpan);
|
||||
|
||||
hr = GetElementBoolProperty( pAspNetCoreElement,
|
||||
CS_ASPNETCORE_STDOUT_LOG_ENABLED,
|
||||
&m_fStdoutLogEnabled );
|
||||
if( FAILED( hr ) )
|
||||
hr = GetElementBoolProperty(pAspNetCoreElement,
|
||||
CS_ASPNETCORE_STDOUT_LOG_ENABLED,
|
||||
&m_fStdoutLogEnabled);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
hr = GetElementStringProperty( pAspNetCoreElement,
|
||||
CS_ASPNETCORE_STDOUT_LOG_FILE,
|
||||
&m_struStdoutLogFile );
|
||||
if( FAILED( hr ) )
|
||||
hr = GetElementStringProperty(pAspNetCoreElement,
|
||||
CS_ASPNETCORE_STDOUT_LOG_FILE,
|
||||
&m_struStdoutLogFile);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
hr = GetElementChildByName( pAspNetCoreElement,
|
||||
CS_ASPNETCORE_ENVIRONMENT_VARIABLES,
|
||||
&pEnvVarList );
|
||||
if( FAILED( hr ) )
|
||||
hr = GetElementChildByName(pAspNetCoreElement,
|
||||
CS_ASPNETCORE_ENVIRONMENT_VARIABLES,
|
||||
&pEnvVarList);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
hr = pEnvVarList->get_Collection( &pEnvVarCollection );
|
||||
if( FAILED( hr ) )
|
||||
hr = pEnvVarList->get_Collection(&pEnvVarCollection);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
for( hr = FindFirstElement( pEnvVarCollection, &index, &pEnvVar ) ;
|
||||
SUCCEEDED( hr ) ;
|
||||
hr = FindNextElement( pEnvVarCollection, &index, &pEnvVar ) )
|
||||
for (hr = FindFirstElement(pEnvVarCollection, &index, &pEnvVar);
|
||||
SUCCEEDED(hr);
|
||||
hr = FindNextElement(pEnvVarCollection, &index, &pEnvVar))
|
||||
{
|
||||
if( hr == S_FALSE )
|
||||
if (hr == S_FALSE)
|
||||
{
|
||||
hr = S_OK;
|
||||
break;
|
||||
}
|
||||
|
||||
hr = GetElementStringProperty( pEnvVar,
|
||||
CS_ASPNETCORE_ENVIRONMENT_VARIABLE_NAME,
|
||||
&strEnvName);
|
||||
if( FAILED( hr ) )
|
||||
if (FAILED(hr = GetElementStringProperty(pEnvVar,
|
||||
CS_ASPNETCORE_ENVIRONMENT_VARIABLE_NAME,
|
||||
&strEnvName)) ||
|
||||
FAILED(hr = GetElementStringProperty(pEnvVar,
|
||||
CS_ASPNETCORE_ENVIRONMENT_VARIABLE_VALUE,
|
||||
&strEnvValue)) ||
|
||||
FAILED(hr = strEnvName.Append(L"=")) ||
|
||||
FAILED(hr = STRU::ExpandEnvironmentVariables(strEnvValue.QueryStr(), &strExpandedEnvValue)))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
hr = GetElementStringProperty( pEnvVar,
|
||||
CS_ASPNETCORE_ENVIRONMENT_VARIABLE_VALUE,
|
||||
&strEnvValue);
|
||||
if( FAILED( hr ) )
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
hr = strFullEnvVar.Append(strEnvName);
|
||||
if( FAILED( hr ) )
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
hr = strFullEnvVar.Append(L"=");
|
||||
if( FAILED( hr ) )
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
pszEnvName = strFullEnvVar.QueryStr();
|
||||
while( pszEnvName != NULL && *pszEnvName != '\0')
|
||||
{
|
||||
*pszEnvName = towupper( *pszEnvName );
|
||||
pszEnvName++;
|
||||
}
|
||||
|
||||
if( !mszEnvNames.FindString( strFullEnvVar ) )
|
||||
{
|
||||
if( !mszEnvNames.Append( strFullEnvVar ) )
|
||||
{
|
||||
hr = E_OUTOFMEMORY;
|
||||
goto Finished;
|
||||
}
|
||||
}
|
||||
|
||||
hr = STRU::ExpandEnvironmentVariables( strEnvValue.QueryStr(), &strExpandedEnvValue );
|
||||
if( FAILED( hr ) )
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
hr = strFullEnvVar.Append(strExpandedEnvValue);
|
||||
if( FAILED( hr ) )
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
if( !mszEnvironment.Append(strFullEnvVar) )
|
||||
pEntry = new ENVIRONMENT_VAR_ENTRY();
|
||||
if (pEntry == NULL)
|
||||
{
|
||||
hr = E_OUTOFMEMORY;
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
if (FAILED(hr = pEntry->Initialize(strEnvName.QueryStr(), strExpandedEnvValue.QueryStr())) ||
|
||||
FAILED(hr = m_pEnvironmentVariables->InsertRecord(pEntry)))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
strEnvName.Reset();
|
||||
strEnvValue.Reset();
|
||||
strExpandedEnvValue.Reset();
|
||||
strFullEnvVar.Reset();
|
||||
|
||||
pEnvVar->Release();
|
||||
pEnvVar = NULL;
|
||||
pEntry = NULL;
|
||||
}
|
||||
|
||||
// basically the following logic is to select
|
||||
|
||||
ReverseMultisz( &mszEnvironment,
|
||||
mszEnvironment.First(),
|
||||
&mszEnvironmentListReverse );
|
||||
|
||||
pcszEnvName = mszEnvNames.First();
|
||||
while(pcszEnvName != NULL)
|
||||
{
|
||||
pszEnvString = mszEnvironmentListReverse.First();
|
||||
while( pszEnvString != NULL )
|
||||
{
|
||||
if(wcsstr(pszEnvString, pcszEnvName) != NULL)
|
||||
{
|
||||
if(!m_mszEnvironment.Append(pszEnvString))
|
||||
{
|
||||
hr = E_OUTOFMEMORY;
|
||||
goto Finished;
|
||||
}
|
||||
break;
|
||||
}
|
||||
pszEnvString = mszEnvironmentListReverse.Next(pszEnvString);
|
||||
}
|
||||
pcszEnvName = mszEnvNames.Next(pcszEnvName);
|
||||
}
|
||||
|
||||
//
|
||||
// let's disable this feature for now
|
||||
//
|
||||
// get all files listed in recycleOnFileChange
|
||||
/*
|
||||
hr = GetElementChildByName( pAspNetCoreElement,
|
||||
CS_ASPNETCORE_RECYCLE_ON_FILE_CHANGE,
|
||||
&pRecycleOnFileChangeFileList );
|
||||
if( FAILED( hr ) )
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
hr = pRecycleOnFileChangeFileList->get_Collection( &pRecycleOnFileChangeFileCollection );
|
||||
if( FAILED( hr ) )
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
for( hr = FindFirstElement( pRecycleOnFileChangeFileCollection, &index, &pRecycleOnFileChangeFile ) ;
|
||||
SUCCEEDED( hr ) ;
|
||||
hr = FindNextElement( pRecycleOnFileChangeFileCollection, &index, &pRecycleOnFileChangeFile ) )
|
||||
{
|
||||
if( hr == S_FALSE )
|
||||
{
|
||||
hr = S_OK;
|
||||
break;
|
||||
}
|
||||
|
||||
hr = GetElementStringProperty( pRecycleOnFileChangeFile,
|
||||
CS_ASPNETCORE_RECYCLE_ON_FILE_CHANGE_FILE_PATH,
|
||||
&strFilePath);
|
||||
if( FAILED( hr ) )
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
if(!m_mszRecycleOnFileChangeFiles.Append( strFilePath ))
|
||||
{
|
||||
hr = E_OUTOFMEMORY;
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
strFilePath.Reset();
|
||||
pRecycleOnFileChangeFile->Release();
|
||||
pRecycleOnFileChangeFile = NULL;
|
||||
}
|
||||
*/
|
||||
|
||||
Finished:
|
||||
|
||||
if( pAspNetCoreElement != NULL )
|
||||
if (pAspNetCoreElement != NULL)
|
||||
{
|
||||
pAspNetCoreElement->Release();
|
||||
pAspNetCoreElement = NULL;
|
||||
}
|
||||
|
||||
if( pEnvVarList != NULL )
|
||||
if (pEnvVarList != NULL)
|
||||
{
|
||||
pEnvVarList->Release();
|
||||
pEnvVarList = NULL;
|
||||
}
|
||||
|
||||
if( pEnvVar != NULL )
|
||||
if (pEnvVar != NULL)
|
||||
{
|
||||
pEnvVar->Release();
|
||||
pEnvVar = NULL;
|
||||
}
|
||||
|
||||
if( pEnvVarCollection != NULL )
|
||||
if (pEnvVarCollection != NULL)
|
||||
{
|
||||
pEnvVarCollection->Release();
|
||||
pEnvVarCollection = NULL;
|
||||
}
|
||||
|
||||
/* if( pRecycleOnFileChangeFileCollection != NULL )
|
||||
if (pEntry != NULL)
|
||||
{
|
||||
pRecycleOnFileChangeFileCollection->Release();
|
||||
pRecycleOnFileChangeFileCollection = NULL;
|
||||
pEntry->Dereference();
|
||||
pEntry = NULL;
|
||||
}
|
||||
|
||||
if( pRecycleOnFileChangeFileList != NULL )
|
||||
{
|
||||
pRecycleOnFileChangeFileList->Release();
|
||||
pRecycleOnFileChangeFileList = NULL;
|
||||
}
|
||||
|
||||
if( pRecycleOnFileChangeFile != NULL )
|
||||
{
|
||||
pRecycleOnFileChangeFile->Release();
|
||||
pRecycleOnFileChangeFile = NULL;
|
||||
}*/
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
|
@ -1,55 +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 "precomp.hxx"
|
||||
|
||||
//
|
||||
// ReplacePlaceHolderWithValue replaces a placeholder found in
|
||||
// pszStr with dwValue.
|
||||
// If replace is successful, pfReplaced is TRUE else FALSE.
|
||||
//
|
||||
|
||||
HRESULT
|
||||
ASPNETCORE_UTILS::ReplacePlaceHolderWithValue(
|
||||
_Inout_ LPWSTR pszStr,
|
||||
_In_ LPWSTR pszPlaceholder,
|
||||
_In_ DWORD cchPlaceholder,
|
||||
_In_ DWORD dwValue,
|
||||
_In_ DWORD dwNumDigitsInValue,
|
||||
_Out_ BOOL *pfReplaced
|
||||
)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
LPWSTR pszPortPlaceHolder = NULL;
|
||||
|
||||
DBG_ASSERT( pszStr != NULL );
|
||||
DBG_ASSERT( pszPlaceholder != NULL );
|
||||
DBG_ASSERT( pfReplaced != NULL );
|
||||
|
||||
*pfReplaced = FALSE;
|
||||
|
||||
if((pszPortPlaceHolder = wcsstr(pszStr, pszPlaceholder)) != NULL)
|
||||
{
|
||||
if( swprintf_s( pszPortPlaceHolder,
|
||||
cchPlaceholder,
|
||||
L"%u",
|
||||
dwValue ) == -1 )
|
||||
{
|
||||
hr = HRESULT_FROM_WIN32( ERROR_INSUFFICIENT_BUFFER );
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
if( wmemcpy_s( pszPortPlaceHolder + dwNumDigitsInValue,
|
||||
cchPlaceholder,
|
||||
L" ",
|
||||
cchPlaceholder - dwNumDigitsInValue ) != 0 )
|
||||
{
|
||||
hr = HRESULT_FROM_WIN32( EINVAL );
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
*pfReplaced = TRUE;
|
||||
}
|
||||
Finished:
|
||||
return hr;
|
||||
}
|
||||
|
|
@ -318,7 +318,7 @@ FILE_WATCHER_ENTRY::Monitor(VOID)
|
|||
_buffDirectoryChanges.QueryPtr(),
|
||||
_buffDirectoryChanges.QuerySize(),
|
||||
FALSE, // Watching sub dirs. Set to False now as only monitoring app_offline
|
||||
FILE_NOTIFY_VALID_MASK & ~FILE_NOTIFY_CHANGE_LAST_ACCESS & ~FILE_NOTIFY_CHANGE_ATTRIBUTES,
|
||||
FILE_NOTIFY_VALID_MASK & ~FILE_NOTIFY_CHANGE_LAST_ACCESS,
|
||||
&cbRead,
|
||||
&_overlapped,
|
||||
NULL))
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -86,7 +86,7 @@ inline bool IsSpace(char ch)
|
|||
#include <acache.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "aspnetcoreutils.h"
|
||||
#include "environmentvariablehash.h"
|
||||
#include "..\aspnetcore_msg.h"
|
||||
#include "aspnetcoreconfig.h"
|
||||
#include "serverprocess.h"
|
||||
|
|
|
|||
|
|
@ -238,6 +238,9 @@ PROCESS_MANAGER::GetProcess(
|
|||
pConfig->QueryArguments(),
|
||||
pConfig->QueryStartupTimeLimitInMS(),
|
||||
pConfig->QueryShutdownTimeLimitInMS(),
|
||||
pConfig->QueryWindowsAuthEnabled(),
|
||||
pConfig->QueryBasicAuthEnabled(),
|
||||
pConfig->QueryAnonymousAuthEnabled(),
|
||||
pConfig->QueryEnvironmentVariables(),
|
||||
pConfig->QueryStdoutLogEnabled(),
|
||||
pConfig->QueryStdoutLogFile()
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@ PROTOCOL_CONFIG::Initialize()
|
|||
|
||||
m_fKeepAlive = TRUE;
|
||||
m_msTimeout = 120000;
|
||||
m_fPreserveHostHeader = TRUE;
|
||||
m_fReverseRewriteHeaders = FALSE;
|
||||
|
||||
if (FAILED(hr = m_strXForwardedForName.CopyW(L"X-Forwarded-For")))
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -212,7 +212,10 @@ WEBSOCKET_HANDLER::IndicateCompletionToIIS(
|
|||
|
||||
_pHandler->SetStatus(FORWARDER_DONE);
|
||||
|
||||
_pHttpContext->IndicateCompletion(RQ_NOTIFICATION_PENDING);
|
||||
// do not call IndicateCompletion here
|
||||
// wait for handle close callback and then call IndicateCompletion
|
||||
// otherwise we may release W3Context too early and cause AV
|
||||
//_pHttpContext->IndicateCompletion(RQ_NOTIFICATION_PENDING);
|
||||
}
|
||||
|
||||
HRESULT
|
||||
|
|
@ -744,18 +747,25 @@ Routine Description:
|
|||
++*/
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
BOOL fLocked = FALSE;
|
||||
CleanupReason cleanupReason = CleanupReasonUnknown;
|
||||
|
||||
DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO,
|
||||
"WEBSOCKET_HANDLER::OnWinHttpSendComplete");
|
||||
|
||||
EnterCriticalSection (&_RequestLock);
|
||||
|
||||
if (_fCleanupInProgress)
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
EnterCriticalSection (&_RequestLock);
|
||||
|
||||
fLocked = TRUE;
|
||||
|
||||
if (_fCleanupInProgress)
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
//
|
||||
// Data was successfully sent to backend.
|
||||
// Initiate next receive from IIS.
|
||||
|
|
@ -768,8 +778,10 @@ Routine Description:
|
|||
}
|
||||
|
||||
Finished:
|
||||
|
||||
LeaveCriticalSection(&_RequestLock);
|
||||
if (fLocked)
|
||||
{
|
||||
LeaveCriticalSection(&_RequestLock);
|
||||
}
|
||||
|
||||
if (FAILED (hr))
|
||||
{
|
||||
|
|
@ -840,18 +852,24 @@ Routine Description:
|
|||
--*/
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
BOOL fLocked = FALSE;
|
||||
CleanupReason cleanupReason = CleanupReasonUnknown;
|
||||
|
||||
DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO,
|
||||
"WEBSOCKET_HANDLER::OnWinHttpReceiveComplete");
|
||||
|
||||
EnterCriticalSection(&_RequestLock);
|
||||
|
||||
if (_fCleanupInProgress)
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
EnterCriticalSection(&_RequestLock);
|
||||
|
||||
fLocked = TRUE;
|
||||
if (_fCleanupInProgress)
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
hr = DoIisWebSocketSend(
|
||||
pCompletionStatus->dwBytesTransferred,
|
||||
pCompletionStatus->eBufferType
|
||||
|
|
@ -864,9 +882,10 @@ Routine Description:
|
|||
}
|
||||
|
||||
Finished:
|
||||
|
||||
LeaveCriticalSection(&_RequestLock);
|
||||
|
||||
if (fLocked)
|
||||
{
|
||||
LeaveCriticalSection(&_RequestLock);
|
||||
}
|
||||
if (FAILED (hr))
|
||||
{
|
||||
Cleanup (cleanupReason);
|
||||
|
|
@ -902,21 +921,26 @@ Routine Description:
|
|||
--*/
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
BOOL fLocked = FALSE;
|
||||
CleanupReason cleanupReason = CleanupReasonUnknown;
|
||||
|
||||
UNREFERENCED_PARAMETER(cbIo);
|
||||
|
||||
DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO, "WEBSOCKET_HANDLER::OnIisSendComplete");
|
||||
|
||||
EnterCriticalSection(&_RequestLock);
|
||||
|
||||
if (FAILED (hrCompletion))
|
||||
if (FAILED(hrCompletion))
|
||||
{
|
||||
hr = hrCompletion;
|
||||
cleanupReason = ClientDisconnect;
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
if (_fCleanupInProgress)
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
EnterCriticalSection(&_RequestLock);
|
||||
fLocked = TRUE;
|
||||
if (_fCleanupInProgress)
|
||||
{
|
||||
goto Finished;
|
||||
|
|
@ -934,9 +958,10 @@ Routine Description:
|
|||
}
|
||||
|
||||
Finished:
|
||||
|
||||
LeaveCriticalSection(&_RequestLock);
|
||||
|
||||
if (fLocked)
|
||||
{
|
||||
LeaveCriticalSection(&_RequestLock);
|
||||
}
|
||||
if (FAILED (hr))
|
||||
{
|
||||
Cleanup (cleanupReason);
|
||||
|
|
@ -977,15 +1002,14 @@ Routine Description:
|
|||
--*/
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
BOOL fLocked = FALSE;
|
||||
CleanupReason cleanupReason = CleanupReasonUnknown;
|
||||
WINHTTP_WEB_SOCKET_BUFFER_TYPE BufferType;
|
||||
|
||||
DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO,
|
||||
"WEBSOCKET_HANDLER::OnIisReceiveComplete");
|
||||
|
||||
EnterCriticalSection(&_RequestLock);
|
||||
|
||||
if (FAILED (hrCompletion))
|
||||
if (FAILED(hrCompletion))
|
||||
{
|
||||
cleanupReason = ClientDisconnect;
|
||||
hr = hrCompletion;
|
||||
|
|
@ -997,6 +1021,13 @@ Routine Description:
|
|||
goto Finished;
|
||||
}
|
||||
|
||||
EnterCriticalSection(&_RequestLock);
|
||||
|
||||
fLocked = TRUE;
|
||||
if (_fCleanupInProgress)
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
//
|
||||
// Get Buffer Type from flags.
|
||||
//
|
||||
|
|
@ -1018,9 +1049,10 @@ Routine Description:
|
|||
}
|
||||
|
||||
Finished:
|
||||
|
||||
LeaveCriticalSection(&_RequestLock);
|
||||
|
||||
if (fLocked)
|
||||
{
|
||||
LeaveCriticalSection(&_RequestLock);
|
||||
}
|
||||
if (FAILED (hr))
|
||||
{
|
||||
Cleanup (cleanupReason);
|
||||
|
|
@ -1042,7 +1074,7 @@ Finished:
|
|||
VOID
|
||||
WEBSOCKET_HANDLER::Cleanup(
|
||||
CleanupReason reason
|
||||
)
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
|
@ -1056,11 +1088,18 @@ Arguments:
|
|||
CleanupReason
|
||||
--*/
|
||||
{
|
||||
DebugPrintf (ASPNETCORE_DEBUG_FLAG_INFO,
|
||||
"WEBSOCKET_HANDLER::Cleanup Initiated with reason %d", reason);
|
||||
BOOL fLocked = FALSE;
|
||||
DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO,
|
||||
"WEBSOCKET_HANDLER::Cleanup Initiated with reason %d", reason);
|
||||
|
||||
if (_fCleanupInProgress)
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
EnterCriticalSection(&_RequestLock);
|
||||
|
||||
fLocked = TRUE;
|
||||
if (_fCleanupInProgress)
|
||||
{
|
||||
goto Finished;
|
||||
|
|
@ -1080,5 +1119,8 @@ Arguments:
|
|||
_pHttpContext->CancelIo();
|
||||
|
||||
Finished:
|
||||
LeaveCriticalSection(&_RequestLock);
|
||||
if (fLocked)
|
||||
{
|
||||
LeaveCriticalSection(&_RequestLock);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue