add features: flowing authentication info, hosting environment variable support; fix client disconnect and app_offline issues (#102)

resubmit
This commit is contained in:
pan-wang 2017-05-23 17:25:45 -07:00 committed by GitHub
parent 88cc1c14d0
commit bce531f61a
18 changed files with 2254 additions and 1825 deletions

View File

@ -157,7 +157,7 @@
<ClInclude Include="Inc\application.h" /> <ClInclude Include="Inc\application.h" />
<ClInclude Include="Inc\applicationmanager.h" /> <ClInclude Include="Inc\applicationmanager.h" />
<ClInclude Include="Inc\aspnetcoreconfig.h" /> <ClInclude Include="Inc\aspnetcoreconfig.h" />
<ClInclude Include="Inc\aspnetcoreutils.h" /> <ClInclude Include="Inc\environmentvariablehash.h" />
<ClInclude Include="Inc\debugutil.h" /> <ClInclude Include="Inc\debugutil.h" />
<ClInclude Include="Inc\filewatcher.h" /> <ClInclude Include="Inc\filewatcher.h" />
<ClInclude Include="Inc\forwarderconnection.h" /> <ClInclude Include="Inc\forwarderconnection.h" />
@ -177,7 +177,6 @@
<ClCompile Include="Src\application.cxx" /> <ClCompile Include="Src\application.cxx" />
<ClCompile Include="Src\applicationmanager.cxx" /> <ClCompile Include="Src\applicationmanager.cxx" />
<ClCompile Include="Src\aspnetcoreconfig.cxx" /> <ClCompile Include="Src\aspnetcoreconfig.cxx" />
<ClCompile Include="Src\aspnetcoreutils.cxx" />
<ClCompile Include="Src\dllmain.cpp" /> <ClCompile Include="Src\dllmain.cpp" />
<ClCompile Include="Src\filewatcher.cxx" /> <ClCompile Include="Src\filewatcher.cxx" />
<ClCompile Include="Src\forwarderconnection.cxx" /> <ClCompile Include="Src\forwarderconnection.cxx" />

View File

@ -70,10 +70,12 @@ public:
VOID VOID
) )
{ {
BOOL fResult = FALSE; BOOL fResult = TRUE;
LARGE_INTEGER li = {0}; LARGE_INTEGER li = {0};
CHAR *pszBuff = NULL; CHAR *pszBuff = NULL;
HANDLE handle = CreateFile( m_Path.QueryStr(), HANDLE handle = INVALID_HANDLE_VALUE;
handle = CreateFile( m_Path.QueryStr(),
GENERIC_READ, GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
NULL, NULL,
@ -81,8 +83,15 @@ public:
FILE_ATTRIBUTE_NORMAL, FILE_ATTRIBUTE_NORMAL,
NULL ); 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; goto Finished;
} }
@ -91,8 +100,6 @@ public:
goto Finished; goto Finished;
} }
fResult = TRUE;
if( li.HighPart != 0 ) if( li.HighPart != 0 )
{ {
// > 4gb file size not supported // > 4gb file size not supported
@ -113,10 +120,10 @@ public:
} }
Finished: Finished:
if( handle ) if( handle != INVALID_HANDLE_VALUE )
{ {
CloseHandle(handle); CloseHandle(handle);
handle = NULL; handle = INVALID_HANDLE_VALUE;
} }
if( pszBuff != NULL ) if( pszBuff != NULL )

View File

@ -5,6 +5,10 @@
#define CS_ROOTWEB_CONFIG L"MACHINE/WEBROOT/APPHOST/" #define CS_ROOTWEB_CONFIG L"MACHINE/WEBROOT/APPHOST/"
#define CS_ROOTWEB_CONFIG_LEN _countof(CS_ROOTWEB_CONFIG)-1 #define CS_ROOTWEB_CONFIG_LEN _countof(CS_ROOTWEB_CONFIG)-1
#define CS_ASPNETCORE_SECTION L"system.webServer/aspNetCore" #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_EXE_PATH L"processPath"
#define CS_ASPNETCORE_PROCESS_ARGUMENTS L"arguments" #define CS_ASPNETCORE_PROCESS_ARGUMENTS L"arguments"
#define CS_ASPNETCORE_PROCESS_STARTUP_TIME_LIMIT L"startupTimeLimit" #define CS_ASPNETCORE_PROCESS_STARTUP_TIME_LIMIT L"startupTimeLimit"
@ -34,7 +38,6 @@
extern HTTP_MODULE_ID g_pModuleId; extern HTTP_MODULE_ID g_pModuleId;
extern IHttpServer * g_pHttpServer; extern IHttpServer * g_pHttpServer;
class ASPNETCORE_CONFIG : IHttpStoredContext class ASPNETCORE_CONFIG : IHttpStoredContext
{ {
public: public:
@ -55,12 +58,12 @@ public:
_Out_ ASPNETCORE_CONFIG **ppAspNetCoreConfig _Out_ ASPNETCORE_CONFIG **ppAspNetCoreConfig
); );
MULTISZ* ENVIRONMENT_VAR_HASH*
QueryEnvironmentVariables( QueryEnvironmentVariables(
VOID VOID
) )
{ {
return &m_mszEnvironment; return m_pEnvironmentVariables;
} }
DWORD DWORD
@ -139,6 +142,24 @@ public:
return m_fForwardWindowsAuthToken; return m_fForwardWindowsAuthToken;
} }
BOOL
QueryWindowsAuthEnabled()
{
return m_fWindowsAuthEnabled;
}
BOOL
QueryBasicAuthEnabled()
{
return m_fBasicAuthEnabled;
}
BOOL
QueryAnonymousAuthEnabled()
{
return m_fAnonymousAuthEnabled;
}
BOOL BOOL
QueryDisableStartUpErrorPage() QueryDisableStartUpErrorPage()
{ {
@ -156,9 +177,9 @@ private:
// //
// private constructor // private constructor
// //
ASPNETCORE_CONFIG(): ASPNETCORE_CONFIG():
m_fStdoutLogEnabled( FALSE ) m_fStdoutLogEnabled( FALSE ),
m_pEnvironmentVariables( NULL )
{ {
} }
@ -170,15 +191,17 @@ private:
DWORD m_dwRequestTimeoutInMS; DWORD m_dwRequestTimeoutInMS;
DWORD m_dwStartupTimeLimitInMS; DWORD m_dwStartupTimeLimitInMS;
DWORD m_dwShutdownTimeLimitInMS; DWORD m_dwShutdownTimeLimitInMS;
MULTISZ m_mszEnvironment;
DWORD m_dwRapidFailsPerMinute; DWORD m_dwRapidFailsPerMinute;
DWORD m_dwProcessesPerApplication;
STRU m_struApplication; STRU m_struApplication;
STRU m_struArguments; STRU m_struArguments;
STRU m_struProcessPath; STRU m_struProcessPath;
BOOL m_fStdoutLogEnabled;
STRU m_struStdoutLogFile; STRU m_struStdoutLogFile;
DWORD m_dwProcessesPerApplication; BOOL m_fStdoutLogEnabled;
BOOL m_fForwardWindowsAuthToken; BOOL m_fForwardWindowsAuthToken;
BOOL m_fDisableStartUpErrorPage; BOOL m_fDisableStartUpErrorPage;
MULTISZ m_mszRecycleOnFileChangeFiles; BOOL m_fWindowsAuthEnabled;
BOOL m_fBasicAuthEnabled;
BOOL m_fAnonymousAuthEnabled;
ENVIRONMENT_VAR_HASH* m_pEnvironmentVariables;
}; };

View File

@ -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()
{
}
};

View File

@ -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 &);
};

View File

@ -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 #pragma once
/*++
Copyright (c) 2013 Microsoft Corporation
Module Name:
forwardinghandler.h
Abstract:
Handler for handling URLs from out-of-box.
--*/
#include "forwarderconnection.h" #include "forwarderconnection.h"
#include "protocolconfig.h" #include "protocolconfig.h"
#include "serverprocess.h" #include "serverprocess.h"
@ -109,7 +98,13 @@ public:
DWORD dwStatusInformationLength DWORD dwStatusInformationLength
) )
{ {
FORWARDING_HANDLER * pThis = static_cast<FORWARDING_HANDLER *>(reinterpret_cast<PVOID>(dwContext)); 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); DBG_ASSERT(pThis->m_Signature == FORWARDING_HANDLER_SIGNATURE);
pThis->OnWinHttpCompletionInternal(hRequest, pThis->OnWinHttpCompletionInternal(hRequest,
dwInternetStatus, dwInternetStatus,
@ -186,7 +181,6 @@ private:
__in const PROTOCOL_CONFIG * pProtocol, __in const PROTOCOL_CONFIG * pProtocol,
__in HINTERNET hConnect, __in HINTERNET hConnect,
__inout STRU * pstrUrl, __inout STRU * pstrUrl,
const STRU& strDestination,
ASPNETCORE_CONFIG* pAspNetCoreConfig, ASPNETCORE_CONFIG* pAspNetCoreConfig,
SERVER_PROCESS* pServerProcess SERVER_PROCESS* pServerProcess
); );
@ -201,7 +195,6 @@ private:
HRESULT HRESULT
GetHeaders( GetHeaders(
const PROTOCOL_CONFIG * pProtocol, const PROTOCOL_CONFIG * pProtocol,
PCWSTR pszDestination,
PCWSTR * ppszHeaders, PCWSTR * ppszHeaders,
DWORD * pcchHeaders, DWORD * pcchHeaders,
ASPNETCORE_CONFIG* pAspNetCoreConfig, ASPNETCORE_CONFIG* pAspNetCoreConfig,
@ -325,6 +318,10 @@ private:
bool m_fHandleClosedDueToClient; bool m_fHandleClosedDueToClient;
bool m_fResponseHeadersReceivedAndSet; bool m_fResponseHeadersReceivedAndSet;
BOOL m_fDoReverseRewriteHeaders; BOOL m_fDoReverseRewriteHeaders;
BOOL m_fErrorHandled;
BOOL m_fWebSocketUpgrade;
BOOL m_fFinishRequest;
BOOL m_fClientDisconnected;
DWORD m_msStartTime; DWORD m_msStartTime;
DWORD m_BytesToReceive; DWORD m_BytesToReceive;

View File

@ -33,12 +33,6 @@ class PROTOCOL_CONFIG
return m_msTimeout; return m_msTimeout;
} }
BOOL
QueryPreserveHostHeader() const
{
return m_fPreserveHostHeader;
}
BOOL BOOL
QueryReverseRewriteHeaders() const QueryReverseRewriteHeaders() const
{ {
@ -90,7 +84,6 @@ class PROTOCOL_CONFIG
private: private:
BOOL m_fKeepAlive; BOOL m_fKeepAlive;
BOOL m_fPreserveHostHeader;
BOOL m_fReverseRewriteHeaders; BOOL m_fReverseRewriteHeaders;
BOOL m_fIncludePortInXForwardedFor; BOOL m_fIncludePortInXForwardedFor;

View File

@ -6,14 +6,21 @@
#define MIN_PORT 1025 #define MIN_PORT 1025
#define MAX_PORT 48000 #define MAX_PORT 48000
#define MAX_RETRY 10 #define MAX_RETRY 10
#define MAX_ACTIVE_CHILD_PROCESSES 16
#define LOCALHOST "127.0.0.1" #define LOCALHOST "127.0.0.1"
#define ASPNETCORE_PORT_STR L"ASPNETCORE_PORT" #define ASPNETCORE_PORT_STR L"ASPNETCORE_PORT"
#define ASPNETCORE_PORT_PLACEHOLDER L"%ASPNETCORE_PORT%" #define ASPNETCORE_PORT_ENV_STR L"ASPNETCORE_PORT="
#define ASPNETCORE_PORT_PLACEHOLDER_CCH 17 #define ASPNETCORE_APP_PATH_ENV_STR L"ASPNETCORE_APPL_PATH="
#define ASPNETCORE_DEBUG_PORT_STR L"ASPNETCORE_DEBUG_PORT" #define ASPNETCORE_APP_TOKEN_ENV_STR L"ASPNETCORE_TOKEN="
#define ASPNETCORE_DEBUG_PORT_PLACEHOLDER L"%ASPNETCORE_DEBUG_PORT%" #define ASPNETCORE_APP_PATH_ENV_STR L"ASPNETCORE_APPL_PATH="
#define ASPNETCORE_DEBUG_PORT_PLACEHOLDER_CCH 23 #define HOSTING_STARTUP_ASSEMBLIES_ENV_STR L"ASPNETCORE_HOSTINGSTARTUPASSEMBLIES"
#define MAX_ACTIVE_CHILD_PROCESSES 16 #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 PROCESS_MANAGER;
class FORWARDER_CONNECTION; class FORWARDER_CONNECTION;
@ -30,7 +37,10 @@ public:
_In_ STRU *pszArguments, _In_ STRU *pszArguments,
_In_ DWORD dwStartupTimeLimitInMS, _In_ DWORD dwStartupTimeLimitInMS,
_In_ DWORD dwShtudownTimeLimitInMS, _In_ DWORD dwShtudownTimeLimitInMS,
_In_ MULTISZ *pszEnvironment, _In_ BOOL fWindowsAuthEnabled,
_In_ BOOL fBasicAuthEnabled,
_In_ BOOL fAnonymousAuthEnabled,
_In_ ENVIRONMENT_VAR_HASH* pEnvironmentVariables,
_In_ BOOL fStdoutLogEnabled, _In_ BOOL fStdoutLogEnabled,
_In_ STRU *pstruStdoutLogFile _In_ STRU *pstruStdoutLogFile
); );
@ -66,12 +76,6 @@ public:
return m_dwPort; return m_dwPort;
} }
DWORD
GetDebugPort()
{
return m_dwDebugPort;
}
VOID VOID
ReferenceServerProcess( ReferenceServerProcess(
VOID VOID
@ -118,6 +122,12 @@ public:
_In_ PTP_TIMER Timer _In_ PTP_TIMER Timer
); );
LPCWSTR
QueryPortStr()
{
return m_struPort.QueryStr();
}
LPCWSTR LPCWSTR
QueryFullLogPath() QueryFullLogPath()
{ {
@ -159,12 +169,6 @@ private:
_In_ LPSTARTUPINFOW pStartupInfo _In_ LPSTARTUPINFOW pStartupInfo
); );
HRESULT
CheckIfServerIsUp(
_In_ DWORD dwPort,
_Out_ BOOL *pfReady
);
HRESULT HRESULT
CheckIfServerIsUp( CheckIfServerIsUp(
_In_ DWORD dwPort, _In_ DWORD dwPort,
@ -182,13 +186,49 @@ private:
GetChildProcessHandles( GetChildProcessHandles(
); );
DWORD HRESULT
GenerateRandomPort( SetupListenPort(
VOID ENVIRONMENT_VAR_HASH *pEnvironmentVarTable
) );
{
return (rand() % (MAX_PORT - MIN_PORT)) + MIN_PORT + 1; 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 DWORD
GetNumberOfDigits( GetNumberOfDigits(
@ -213,44 +253,51 @@ private:
} }
FORWARDER_CONNECTION *m_pForwarderConnection; FORWARDER_CONNECTION *m_pForwarderConnection;
HANDLE m_hJobObject;
BOOL m_fStdoutLogEnabled; BOOL m_fStdoutLogEnabled;
BOOL m_fWindowsAuthEnabled;
BOOL m_fBasicAuthEnabled;
BOOL m_fAnonymousAuthEnabled;
STTIMER m_Timer;
SOCKET m_socket;
STRU m_struLogFile; STRU m_struLogFile;
STRU m_struFullLogFile; 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_ProcessPath;
STRU m_Arguments; 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_dwStartupTimeLimitInMS;
DWORD m_dwShutdownTimeLimitInMS; DWORD m_dwShutdownTimeLimitInMS;
MULTISZ m_Environment;
mutable LONG m_cRefs;
HANDLE m_hProcessWaitHandle;
DWORD m_cChildProcess; DWORD m_cChildProcess;
HANDLE m_hChildProcessWaitHandles[MAX_ACTIVE_CHILD_PROCESSES]; DWORD m_dwChildProcessIds[MAX_ACTIVE_CHILD_PROCESSES];
DWORD m_dwProcessId; DWORD m_dwProcessId;
DWORD m_dwListeningProcessId; DWORD m_dwListeningProcessId;
STRA m_straGuid; STRA m_straGuid;
HANDLE m_hJobObject;
HANDLE m_hStdoutHandle;
// //
// m_hProcessHandle is the handle to process this object creates. // m_hProcessHandle is the handle to process this object creates.
// //
HANDLE m_hProcessHandle; HANDLE m_hProcessHandle;
HANDLE m_hListeningProcessHandle; HANDLE m_hListeningProcessHandle;
HANDLE m_hProcessWaitHandle;
// //
// m_hChildProcessHandle is the handle to process created by // m_hChildProcessHandle is the handle to process created by
// m_hProcessHandle process if it does. // m_hProcessHandle process if it does.
// //
HANDLE m_hChildProcessHandles[MAX_ACTIVE_CHILD_PROCESSES]; 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; PROCESS_MANAGER *m_pProcessManager;
ENVIRONMENT_VAR_HASH *m_pEnvironmentVarTable ;
}; };

View File

@ -5,6 +5,12 @@
APPLICATION::~APPLICATION() APPLICATION::~APPLICATION()
{ {
if (m_pAppOfflineHtm != NULL)
{
m_pAppOfflineHtm->DereferenceAppOfflineHtm();
m_pAppOfflineHtm = NULL;
}
if (m_pFileWatcherEntry != NULL) if (m_pFileWatcherEntry != NULL)
{ {
// Mark the entry as invalid, // Mark the entry as invalid,
@ -109,6 +115,7 @@ APPLICATION::UpdateAppOfflineFileHandle()
STRU strFilePath; STRU strFilePath;
PATH::ConvertPathToFullPath(L".\\app_offline.htm", m_strAppPhysicalPath.QueryStr(), &strFilePath); PATH::ConvertPathToFullPath(L".\\app_offline.htm", m_strAppPhysicalPath.QueryStr(), &strFilePath);
APP_OFFLINE_HTM *pOldAppOfflineHtm = NULL; APP_OFFLINE_HTM *pOldAppOfflineHtm = NULL;
APP_OFFLINE_HTM *pNewAppOfflineHtm = NULL;
if (INVALID_FILE_ATTRIBUTES == GetFileAttributes(strFilePath.QueryStr()) && GetLastError() == ERROR_FILE_NOT_FOUND) if (INVALID_FILE_ATTRIBUTES == GetFileAttributes(strFilePath.QueryStr()) && GetLastError() == ERROR_FILE_NOT_FOUND)
{ {
@ -117,30 +124,41 @@ APPLICATION::UpdateAppOfflineFileHandle()
else else
{ {
m_fAppOfflineFound = TRUE; m_fAppOfflineFound = TRUE;
APP_OFFLINE_HTM *pNewAppOfflineHtm = new APP_OFFLINE_HTM(strFilePath.QueryStr());
DBG_ASSERT(pNewAppOfflineHtm != NULL);
if (pNewAppOfflineHtm->Load())
{
//
// loaded new app offline htm
//
pOldAppOfflineHtm = (APP_OFFLINE_HTM *)InterlockedExchangePointer((VOID**)&m_pAppOfflineHtm, pNewAppOfflineHtm);
// //
// send shutdown signal to the app // send shutdown signal
// //
// 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) if (m_pProcessManager != NULL)
{ {
m_pProcessManager->SendShutdownSignal(); m_pProcessManager->SendShutdownSignal();
} }
}
} pNewAppOfflineHtm = new APP_OFFLINE_HTM(strFilePath.QueryStr());
if ( pNewAppOfflineHtm != NULL )
{
if (pNewAppOfflineHtm->Load())
{
//
// loaded the new app_offline.htm
//
pOldAppOfflineHtm = (APP_OFFLINE_HTM *)InterlockedExchangePointer((VOID**)&m_pAppOfflineHtm, pNewAppOfflineHtm);
if (pOldAppOfflineHtm != NULL) if (pOldAppOfflineHtm != NULL)
{ {
pOldAppOfflineHtm->DereferenceAppOfflineHtm(); pOldAppOfflineHtm->DereferenceAppOfflineHtm();
pOldAppOfflineHtm = NULL; pOldAppOfflineHtm = NULL;
} }
}
else
{
// ignored the new app_offline file because the file does not exist.
pNewAppOfflineHtm->DereferenceAppOfflineHtm();
pNewAppOfflineHtm = NULL;
}
}
}
} }

View File

@ -12,6 +12,12 @@ ASPNETCORE_CONFIG::~ASPNETCORE_CONFIG()
{ {
APPLICATION_MANAGER::GetInstance()->RecycleApplication(m_struApplication.QueryStr()); APPLICATION_MANAGER::GetInstance()->RecycleApplication(m_struApplication.QueryStr());
} }
if(m_pEnvironmentVariables != NULL)
{
m_pEnvironmentVariables->Clear();
delete m_pEnvironmentVariables;
m_pEnvironmentVariables = NULL;
}
} }
HRESULT HRESULT
@ -24,7 +30,7 @@ ASPNETCORE_CONFIG::GetConfig(
IHttpApplication *pHttpApplication = pHttpContext->GetApplication(); IHttpApplication *pHttpApplication = pHttpContext->GetApplication();
ASPNETCORE_CONFIG *pAspNetCoreConfig = NULL; ASPNETCORE_CONFIG *pAspNetCoreConfig = NULL;
if( ppAspNetCoreConfig == NULL) if (ppAspNetCoreConfig == NULL)
{ {
hr = E_INVALIDARG; hr = E_INVALIDARG;
goto Finished; goto Finished;
@ -36,7 +42,7 @@ ASPNETCORE_CONFIG::GetConfig(
pAspNetCoreConfig = (ASPNETCORE_CONFIG*) pAspNetCoreConfig = (ASPNETCORE_CONFIG*)
pHttpApplication->GetModuleContextContainer()->GetModuleContext(g_pModuleId); pHttpApplication->GetModuleContextContainer()->GetModuleContext(g_pModuleId);
if( pAspNetCoreConfig != NULL ) if (pAspNetCoreConfig != NULL)
{ {
*ppAspNetCoreConfig = pAspNetCoreConfig; *ppAspNetCoreConfig = pAspNetCoreConfig;
pAspNetCoreConfig = NULL; pAspNetCoreConfig = NULL;
@ -44,31 +50,31 @@ ASPNETCORE_CONFIG::GetConfig(
} }
pAspNetCoreConfig = new ASPNETCORE_CONFIG; pAspNetCoreConfig = new ASPNETCORE_CONFIG;
if( pAspNetCoreConfig == NULL ) if (pAspNetCoreConfig == NULL)
{ {
hr = E_OUTOFMEMORY; hr = E_OUTOFMEMORY;
goto Finished; goto Finished;
} }
hr = pAspNetCoreConfig->Populate( pHttpContext ); hr = pAspNetCoreConfig->Populate(pHttpContext);
if( FAILED( hr ) ) if (FAILED(hr))
{ {
goto Finished; goto Finished;
} }
hr = pHttpApplication->GetModuleContextContainer()-> hr = pHttpApplication->GetModuleContextContainer()->
SetModuleContext( pAspNetCoreConfig, g_pModuleId ); SetModuleContext(pAspNetCoreConfig, g_pModuleId);
if( FAILED( hr ) ) if (FAILED(hr))
{ {
if( hr == HRESULT_FROM_WIN32( ERROR_ALREADY_ASSIGNED ) ) if (hr == HRESULT_FROM_WIN32(ERROR_ALREADY_ASSIGNED))
{ {
delete pAspNetCoreConfig; delete pAspNetCoreConfig;
pAspNetCoreConfig = (ASPNETCORE_CONFIG*) pHttpApplication-> pAspNetCoreConfig = (ASPNETCORE_CONFIG*)pHttpApplication->
GetModuleContextContainer()-> GetModuleContextContainer()->
GetModuleContext( g_pModuleId ); GetModuleContext(g_pModuleId);
_ASSERT( pAspNetCoreConfig != NULL ); _ASSERT(pAspNetCoreConfig != NULL);
hr = S_OK; hr = S_OK;
} }
@ -93,7 +99,7 @@ ASPNETCORE_CONFIG::GetConfig(
Finished: Finished:
if( pAspNetCoreConfig != NULL ) if (pAspNetCoreConfig != NULL)
{ {
delete pAspNetCoreConfig; delete pAspNetCoreConfig;
pAspNetCoreConfig = NULL; pAspNetCoreConfig = NULL;
@ -102,82 +108,134 @@ Finished:
return hr; return hr;
} }
VOID ReverseMultisz( MULTISZ * pmszInput,
LPCWSTR pszStr,
MULTISZ * pmszOutput )
{
if(pszStr == NULL) return;
ReverseMultisz( pmszInput, pmszInput->Next( pszStr ), pmszOutput );
pmszOutput->Append( pszStr );
}
HRESULT HRESULT
ASPNETCORE_CONFIG::Populate( ASPNETCORE_CONFIG::Populate(
IHttpContext *pHttpContext IHttpContext *pHttpContext
) )
{ {
HRESULT hr = S_OK; HRESULT hr = S_OK;
STACK_STRU ( strSiteConfigPath, 256); STACK_STRU(strSiteConfigPath, 256);
STRU strEnvName; STRU strEnvName;
STRU strEnvValue; STRU strEnvValue;
STRU strFullEnvVar; STRU strExpandedEnvValue;
IAppHostAdminManager *pAdminManager = NULL; IAppHostAdminManager *pAdminManager = NULL;
IAppHostElement *pAspNetCoreElement = NULL; IAppHostElement *pAspNetCoreElement = NULL;
IAppHostElement *pWindowsAuthenticationElement = NULL;
IAppHostElement *pBasicAuthenticationElement = NULL;
IAppHostElement *pAnonymousAuthenticationElement = NULL;
IAppHostElement *pEnvVarList = NULL; IAppHostElement *pEnvVarList = NULL;
IAppHostElementCollection *pEnvVarCollection = NULL;
IAppHostElement *pEnvVar = NULL; IAppHostElement *pEnvVar = NULL;
//IAppHostElement *pRecycleOnFileChangeFileList = NULL; IAppHostElementCollection *pEnvVarCollection = NULL;
//IAppHostElementCollection *pRecycleOnFileChangeFileCollection = NULL;
//IAppHostElement *pRecycleOnFileChangeFile = NULL;
ULONGLONG ullRawTimeSpan = 0; ULONGLONG ullRawTimeSpan = 0;
ENUM_INDEX index; ENUM_INDEX index;
STRU strExpandedEnvValue; ENVIRONMENT_VAR_ENTRY* pEntry = NULL;
MULTISZ mszEnvironment;
MULTISZ mszEnvironmentListReverse; m_pEnvironmentVariables = new ENVIRONMENT_VAR_HASH();
MULTISZ mszEnvNames; if (m_pEnvironmentVariables == NULL)
LPWSTR pszEnvName; {
LPCWSTR pcszEnvName; hr = E_OUTOFMEMORY;
LPCWSTR pszEnvString; goto Finished;
STRU strFilePath; }
if (FAILED(hr = m_pEnvironmentVariables->Initialize(37 /*prime*/)))
{
delete m_pEnvironmentVariables;
m_pEnvironmentVariables = NULL;
goto Finished;
}
pAdminManager = g_pHttpServer->GetAdminManager(); pAdminManager = g_pHttpServer->GetAdminManager();
hr = strSiteConfigPath.Copy( pHttpContext->GetApplication()->GetAppConfigPath() ); hr = strSiteConfigPath.Copy(pHttpContext->GetApplication()->GetAppConfigPath());
if( FAILED( hr ) ) if (FAILED(hr))
{ {
goto Finished; goto Finished;
} }
hr = pAdminManager->GetAdminSection( CS_ASPNETCORE_SECTION, hr = pAdminManager->GetAdminSection(CS_WINDOWS_AUTHENTICATION_SECTION,
strSiteConfigPath.QueryStr(), strSiteConfigPath.QueryStr(),
&pAspNetCoreElement ); &pWindowsAuthenticationElement);
if( FAILED( hr ) ) 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; goto Finished;
} }
hr = GetElementStringProperty( pAspNetCoreElement, hr = GetElementStringProperty(pAspNetCoreElement,
CS_ASPNETCORE_PROCESS_EXE_PATH, CS_ASPNETCORE_PROCESS_EXE_PATH,
&m_struProcessPath ); &m_struProcessPath);
if( FAILED( hr ) ) if (FAILED(hr))
{ {
goto Finished; goto Finished;
} }
hr = GetElementStringProperty( pAspNetCoreElement, hr = GetElementStringProperty(pAspNetCoreElement,
CS_ASPNETCORE_PROCESS_ARGUMENTS, CS_ASPNETCORE_PROCESS_ARGUMENTS,
&m_struArguments ); &m_struArguments);
if( FAILED( hr ) ) if (FAILED(hr))
{ {
goto Finished; goto Finished;
} }
hr = GetElementDWORDProperty( pAspNetCoreElement, hr = GetElementDWORDProperty(pAspNetCoreElement,
CS_ASPNETCORE_RAPID_FAILS_PER_MINUTE, CS_ASPNETCORE_RAPID_FAILS_PER_MINUTE,
&m_dwRapidFailsPerMinute ); &m_dwRapidFailsPerMinute);
if( FAILED( hr ) ) if (FAILED(hr))
{ {
goto Finished; goto Finished;
} }
@ -185,16 +243,15 @@ ASPNETCORE_CONFIG::Populate(
// //
// rapidFailsPerMinute cannot be greater than 100. // 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; m_dwRapidFailsPerMinute = MAX_RAPID_FAILS_PER_MINUTE;
} }
hr = GetElementDWORDProperty( pAspNetCoreElement, hr = GetElementDWORDProperty(pAspNetCoreElement,
CS_ASPNETCORE_PROCESSES_PER_APPLICATION, CS_ASPNETCORE_PROCESSES_PER_APPLICATION,
&m_dwProcessesPerApplication ); &m_dwProcessesPerApplication);
if( FAILED( hr ) ) if (FAILED(hr))
{ {
goto Finished; goto Finished;
} }
@ -204,7 +261,7 @@ ASPNETCORE_CONFIG::Populate(
CS_ASPNETCORE_PROCESS_STARTUP_TIME_LIMIT, CS_ASPNETCORE_PROCESS_STARTUP_TIME_LIMIT,
&m_dwStartupTimeLimitInMS &m_dwStartupTimeLimitInMS
); );
if( FAILED( hr ) ) if (FAILED(hr))
{ {
goto Finished; goto Finished;
} }
@ -222,10 +279,10 @@ ASPNETCORE_CONFIG::Populate(
} }
m_dwShutdownTimeLimitInMS *= MILLISECONDS_IN_ONE_SECOND; m_dwShutdownTimeLimitInMS *= MILLISECONDS_IN_ONE_SECOND;
hr = GetElementBoolProperty( pAspNetCoreElement, hr = GetElementBoolProperty(pAspNetCoreElement,
CS_ASPNETCORE_FORWARD_WINDOWS_AUTH_TOKEN, CS_ASPNETCORE_FORWARD_WINDOWS_AUTH_TOKEN,
&m_fForwardWindowsAuthToken ); &m_fForwardWindowsAuthToken);
if( FAILED( hr ) ) if (FAILED(hr))
{ {
goto Finished; goto Finished;
} }
@ -243,240 +300,116 @@ ASPNETCORE_CONFIG::Populate(
CS_ASPNETCORE_WINHTTP_REQUEST_TIMEOUT, CS_ASPNETCORE_WINHTTP_REQUEST_TIMEOUT,
&ullRawTimeSpan &ullRawTimeSpan
); );
if( FAILED( hr ) ) if (FAILED(hr))
{ {
goto Finished; goto Finished;
} }
m_dwRequestTimeoutInMS = (DWORD)TIMESPAN_IN_MILLISECONDS(ullRawTimeSpan); m_dwRequestTimeoutInMS = (DWORD)TIMESPAN_IN_MILLISECONDS(ullRawTimeSpan);
hr = GetElementBoolProperty( pAspNetCoreElement, hr = GetElementBoolProperty(pAspNetCoreElement,
CS_ASPNETCORE_STDOUT_LOG_ENABLED, CS_ASPNETCORE_STDOUT_LOG_ENABLED,
&m_fStdoutLogEnabled ); &m_fStdoutLogEnabled);
if( FAILED( hr ) ) if (FAILED(hr))
{ {
goto Finished; goto Finished;
} }
hr = GetElementStringProperty( pAspNetCoreElement, hr = GetElementStringProperty(pAspNetCoreElement,
CS_ASPNETCORE_STDOUT_LOG_FILE, CS_ASPNETCORE_STDOUT_LOG_FILE,
&m_struStdoutLogFile ); &m_struStdoutLogFile);
if( FAILED( hr ) ) if (FAILED(hr))
{ {
goto Finished; goto Finished;
} }
hr = GetElementChildByName( pAspNetCoreElement, hr = GetElementChildByName(pAspNetCoreElement,
CS_ASPNETCORE_ENVIRONMENT_VARIABLES, CS_ASPNETCORE_ENVIRONMENT_VARIABLES,
&pEnvVarList ); &pEnvVarList);
if( FAILED( hr ) ) if (FAILED(hr))
{ {
goto Finished; goto Finished;
} }
hr = pEnvVarList->get_Collection( &pEnvVarCollection ); hr = pEnvVarList->get_Collection(&pEnvVarCollection);
if( FAILED( hr ) ) if (FAILED(hr))
{ {
goto Finished; goto Finished;
} }
for( hr = FindFirstElement( pEnvVarCollection, &index, &pEnvVar ) ; for (hr = FindFirstElement(pEnvVarCollection, &index, &pEnvVar);
SUCCEEDED( hr ) ; SUCCEEDED(hr);
hr = FindNextElement( pEnvVarCollection, &index, &pEnvVar ) ) hr = FindNextElement(pEnvVarCollection, &index, &pEnvVar))
{ {
if( hr == S_FALSE ) if (hr == S_FALSE)
{ {
hr = S_OK; hr = S_OK;
break; break;
} }
hr = GetElementStringProperty( pEnvVar, if (FAILED(hr = GetElementStringProperty(pEnvVar,
CS_ASPNETCORE_ENVIRONMENT_VARIABLE_NAME, CS_ASPNETCORE_ENVIRONMENT_VARIABLE_NAME,
&strEnvName); &strEnvName)) ||
if( FAILED( hr ) ) FAILED(hr = GetElementStringProperty(pEnvVar,
{
goto Finished;
}
hr = GetElementStringProperty( pEnvVar,
CS_ASPNETCORE_ENVIRONMENT_VARIABLE_VALUE, CS_ASPNETCORE_ENVIRONMENT_VARIABLE_VALUE,
&strEnvValue); &strEnvValue)) ||
if( FAILED( hr ) ) FAILED(hr = strEnvName.Append(L"=")) ||
FAILED(hr = STRU::ExpandEnvironmentVariables(strEnvValue.QueryStr(), &strExpandedEnvValue)))
{ {
goto Finished; goto Finished;
} }
hr = strFullEnvVar.Append(strEnvName); pEntry = new ENVIRONMENT_VAR_ENTRY();
if( FAILED( hr ) ) if (pEntry == NULL)
{
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) )
{ {
hr = E_OUTOFMEMORY; hr = E_OUTOFMEMORY;
goto Finished; 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(); strExpandedEnvValue.Reset();
strFullEnvVar.Reset();
pEnvVar->Release(); pEnvVar->Release();
pEnvVar = NULL; 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: Finished:
if( pAspNetCoreElement != NULL ) if (pAspNetCoreElement != NULL)
{ {
pAspNetCoreElement->Release(); pAspNetCoreElement->Release();
pAspNetCoreElement = NULL; pAspNetCoreElement = NULL;
} }
if( pEnvVarList != NULL ) if (pEnvVarList != NULL)
{ {
pEnvVarList->Release(); pEnvVarList->Release();
pEnvVarList = NULL; pEnvVarList = NULL;
} }
if( pEnvVar != NULL ) if (pEnvVar != NULL)
{ {
pEnvVar->Release(); pEnvVar->Release();
pEnvVar = NULL; pEnvVar = NULL;
} }
if( pEnvVarCollection != NULL ) if (pEnvVarCollection != NULL)
{ {
pEnvVarCollection->Release(); pEnvVarCollection->Release();
pEnvVarCollection = NULL; pEnvVarCollection = NULL;
} }
/* if( pRecycleOnFileChangeFileCollection != NULL ) if (pEntry != NULL)
{ {
pRecycleOnFileChangeFileCollection->Release(); pEntry->Dereference();
pRecycleOnFileChangeFileCollection = NULL; pEntry = NULL;
} }
if( pRecycleOnFileChangeFileList != NULL )
{
pRecycleOnFileChangeFileList->Release();
pRecycleOnFileChangeFileList = NULL;
}
if( pRecycleOnFileChangeFile != NULL )
{
pRecycleOnFileChangeFile->Release();
pRecycleOnFileChangeFile = NULL;
}*/
return hr; return hr;
} }

View File

@ -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;
}

View File

@ -318,7 +318,7 @@ FILE_WATCHER_ENTRY::Monitor(VOID)
_buffDirectoryChanges.QueryPtr(), _buffDirectoryChanges.QueryPtr(),
_buffDirectoryChanges.QuerySize(), _buffDirectoryChanges.QuerySize(),
FALSE, // Watching sub dirs. Set to False now as only monitoring app_offline 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, &cbRead,
&_overlapped, &_overlapped,
NULL)) NULL))

View File

@ -22,32 +22,36 @@ PROTOCOL_CONFIG FORWARDING_HANDLER::sm_ProtocolConfig;
FORWARDING_HANDLER::FORWARDING_HANDLER( FORWARDING_HANDLER::FORWARDING_HANDLER(
__in IHttpContext * pW3Context __in IHttpContext * pW3Context
) : m_Signature ( FORWARDING_HANDLER_SIGNATURE ), ) : m_Signature(FORWARDING_HANDLER_SIGNATURE),
m_cRefs ( 1 ), m_cRefs(1),
m_pW3Context ( pW3Context ), m_pW3Context(pW3Context),
m_pChildRequestContext ( NULL ), m_pChildRequestContext(NULL),
m_hRequest ( NULL ), m_hRequest(NULL),
m_fHandleClosedDueToClient( FALSE ), m_fHandleClosedDueToClient(FALSE),
m_fResponseHeadersReceivedAndSet( FALSE ), m_fResponseHeadersReceivedAndSet(FALSE),
m_fDoReverseRewriteHeaders ( FALSE ), m_fDoReverseRewriteHeaders(FALSE),
m_msStartTime ( 0 ), m_msStartTime(0),
m_BytesToReceive ( 0 ), m_BytesToReceive(0),
m_BytesToSend ( 0 ), m_BytesToSend(0),
m_pEntityBuffer ( NULL ), m_pEntityBuffer(NULL),
m_cchLastSend ( 0 ), m_cchLastSend(0),
m_cEntityBuffers ( 0 ), m_cEntityBuffers(0),
m_cBytesBuffered ( 0 ), m_cBytesBuffered(0),
m_cMinBufferLimit ( 0 ), m_cMinBufferLimit(0),
m_pszOriginalHostHeader ( NULL ), m_pszOriginalHostHeader(NULL),
m_RequestStatus ( FORWARDER_START ), m_RequestStatus(FORWARDER_START),
m_pDisconnect ( NULL ), m_pDisconnect(NULL),
m_pszHeaders ( NULL ), m_pszHeaders(NULL),
m_cchHeaders ( 0 ), m_cchHeaders(0),
m_fWebSocketEnabled ( FALSE ), m_fWebSocketEnabled(FALSE),
m_cContentLength ( 0 ), m_cContentLength(0),
m_pWebSocket ( NULL ), m_pWebSocket(NULL),
m_pApplication( NULL ), m_pApplication(NULL),
m_pAppOfflineHtm( NULL ) m_pAppOfflineHtm(NULL),
m_fErrorHandled(FALSE),
m_fWebSocketUpgrade(FALSE),
m_fFinishRequest(FALSE),
m_fClientDisconnected(FALSE)
{ {
InitializeSRWLock(&m_RequestLock); InitializeSRWLock(&m_RequestLock);
} }
@ -95,6 +99,10 @@ FORWARDING_HANDLER::~FORWARDING_HANDLER(
if (m_hRequest != NULL) if (m_hRequest != NULL)
{ {
// m_hRequest should have already been closed and set to NULL
// if not, we cannot close it as it may callback and cause AV
// let's do our best job here
WinHttpSetStatusCallback(m_hRequest, NULL, NULL, NULL);
WinHttpCloseHandle(m_hRequest); WinHttpCloseHandle(m_hRequest);
m_hRequest = NULL; m_hRequest = NULL;
} }
@ -105,7 +113,7 @@ FORWARDING_HANDLER::~FORWARDING_HANDLER(
m_pApplication = NULL; m_pApplication = NULL;
} }
if( m_pAppOfflineHtm != NULL ) if(m_pAppOfflineHtm != NULL)
{ {
m_pAppOfflineHtm->DereferenceAppOfflineHtm(); m_pAppOfflineHtm->DereferenceAppOfflineHtm();
m_pAppOfflineHtm = NULL; m_pAppOfflineHtm = NULL;
@ -154,10 +162,10 @@ FORWARDING_HANDLER::DereferenceForwardingHandler(
VOID VOID
) const ) const
{ {
DBG_ASSERT(m_cRefs != 0 ); DBG_ASSERT(m_cRefs != 0);
LONG cRefs = 0; LONG cRefs = 0;
if ( (cRefs = InterlockedDecrement(&m_cRefs) ) == 0) if ((cRefs = InterlockedDecrement(&m_cRefs)) == 0)
{ {
delete this; delete this;
} }
@ -179,8 +187,8 @@ FORWARDING_HANDLER::SetStatusAndHeaders(
HRESULT hr; HRESULT hr;
IHttpResponse * pResponse = m_pW3Context->GetResponse(); IHttpResponse * pResponse = m_pW3Context->GetResponse();
IHttpRequest * pRequest = m_pW3Context->GetRequest(); IHttpRequest * pRequest = m_pW3Context->GetRequest();
STACK_STRA ( strHeaderName, 128); STACK_STRA(strHeaderName, 128);
STACK_STRA ( strHeaderValue, 2048); STACK_STRA(strHeaderValue, 2048);
DWORD index = 0; DWORD index = 0;
PSTR pchNewline; PSTR pchNewline;
PCSTR pchEndofHeaderValue; PCSTR pchEndofHeaderValue;
@ -341,7 +349,7 @@ FORWARDING_HANDLER::SetStatusAndHeaders(
// //
// Copy the header value // Copy the header value
// //
if (pchEndofHeaderValue == pszHeaders+index) if (pchEndofHeaderValue == pszHeaders + index)
{ {
strHeaderValue.Reset(); strHeaderValue.Reset();
} }
@ -405,7 +413,7 @@ FORWARDING_HANDLER::SetStatusAndHeaders(
// Explicitly remove the Server header if the back-end didn't set one. // Explicitly remove the Server header if the back-end didn't set one.
// //
if ( !fServerHeaderPresent ) if (!fServerHeaderPresent)
{ {
pResponse->DeleteHeader("Server"); pResponse->DeleteHeader("Server");
} }
@ -525,7 +533,7 @@ SetCookie:
// syntax name=value ; ... ; Domain=.host ; ... // syntax name=value ; ... ; Domain=.host ; ...
// //
pHeaders = &pResponse->GetRawHttpResponse()->Headers; pHeaders = &pResponse->GetRawHttpResponse()->Headers;
for (DWORD i=0; i<pHeaders->UnknownHeaderCount; i++) for (DWORD i = 0; i<pHeaders->UnknownHeaderCount; i++)
{ {
if (_stricmp(pHeaders->pUnknownHeaders[i].pName, "Set-Cookie") != 0) if (_stricmp(pHeaders->pUnknownHeaders[i].pName, "Set-Cookie") != 0)
{ {
@ -567,7 +575,7 @@ SetCookie:
pszStartHost++; pszStartHost++;
} }
pszEndHost = pszStartHost; pszEndHost = pszStartHost;
while(!IsSpace(*pszEndHost) && while (!IsSpace(*pszEndHost) &&
*pszEndHost != ';' && *pszEndHost != ';' &&
*pszEndHost != '\0') *pszEndHost != '\0')
{ {
@ -600,39 +608,45 @@ SetCookie:
HRESULT HRESULT
FORWARDING_HANDLER::GetHeaders( FORWARDING_HANDLER::GetHeaders(
const PROTOCOL_CONFIG * pProtocol, const PROTOCOL_CONFIG * pProtocol,
PCWSTR pszDestination,
PCWSTR * ppszHeaders, PCWSTR * ppszHeaders,
DWORD * pcchHeaders, DWORD * pcchHeaders,
ASPNETCORE_CONFIG* pAspNetCoreConfig, ASPNETCORE_CONFIG* pAspNetCoreConfig,
SERVER_PROCESS* pServerProcess SERVER_PROCESS* pServerProcess
) )
{ {
IHttpRequest *pRequest = m_pW3Context->GetRequest();
HRESULT hr = S_OK; HRESULT hr = S_OK;
PCSTR pszCurrentHeader; PCSTR pszCurrentHeader;
USHORT cchCurrentHeader;
PCSTR pszFinalHeader;
DWORD cchFinalHeader;
STACK_STRA( strTemp, 64);
HTTP_REQUEST_HEADERS *pHeaders;
PCSTR ppHeadersToBeRemoved; PCSTR ppHeadersToBeRemoved;
PCSTR pszFinalHeader;
USHORT cchCurrentHeader;
DWORD cchFinalHeader;
BOOL fSecure = FALSE; // dummy. Used in SplitUrl. Value will not be used
// as ANCM always use http protocol to communicate with backend
STRU struDestination;
STRU struUrl;
STACK_STRA(strTemp, 64);
HTTP_REQUEST_HEADERS *pHeaders;
IHttpRequest *pRequest = m_pW3Context->GetRequest();
MULTISZA mszMsAspNetCoreHeaders; MULTISZA mszMsAspNetCoreHeaders;
// //
// Update host header if so configured // We historically set the host section in request url to the new host header
// this is wrong but Kestrel has dependency on it.
// should change it in the future
// //
if (!pProtocol->QueryPreserveHostHeader()) if (FAILED(hr = PATH::SplitUrl(pRequest->GetRawHttpRequest()->CookedUrl.pFullUrl,
{ &fSecure,
STACK_STRA( straTemp, 256 ); &struDestination,
if (FAILED(hr = straTemp.CopyW(pszDestination)) || &struUrl)) ||
FAILED(hr = strTemp.CopyW(struDestination.QueryStr())) ||
FAILED(hr = pRequest->SetHeader(HttpHeaderHost, FAILED(hr = pRequest->SetHeader(HttpHeaderHost,
straTemp.QueryStr(), strTemp.QueryStr(),
static_cast<USHORT>(straTemp.QueryCCH()), static_cast<USHORT>(strTemp.QueryCCH()),
TRUE))) // fReplace TRUE))) // fReplace
{ {
return hr; return hr;
} }
}
// //
// Strip all headers starting with MS-ASPNETCORE. // Strip all headers starting with MS-ASPNETCORE.
@ -641,11 +655,11 @@ FORWARDING_HANDLER::GetHeaders(
// //
pHeaders = &m_pW3Context->GetRequest()->GetRawHttpRequest()->Headers; pHeaders = &m_pW3Context->GetRequest()->GetRawHttpRequest()->Headers;
for (DWORD i=0; i<pHeaders->UnknownHeaderCount; i++) for (DWORD i = 0; i<pHeaders->UnknownHeaderCount; i++)
{ {
if (_strnicmp(pHeaders->pUnknownHeaders[i].pName, "MS-ASPNETCORE", 13) == 0) if (_strnicmp(pHeaders->pUnknownHeaders[i].pName, "MS-ASPNETCORE", 13) == 0)
{ {
mszMsAspNetCoreHeaders.Append( pHeaders->pUnknownHeaders[i].pName, (DWORD) pHeaders->pUnknownHeaders[i].NameLength ); mszMsAspNetCoreHeaders.Append(pHeaders->pUnknownHeaders[i].pName, (DWORD)pHeaders->pUnknownHeaders[i].NameLength);
} }
} }
@ -655,35 +669,35 @@ FORWARDING_HANDLER::GetHeaders(
// iterate the list of headers to be removed and delete them from the request. // iterate the list of headers to be removed and delete them from the request.
// //
while(ppHeadersToBeRemoved != NULL) while (ppHeadersToBeRemoved != NULL)
{ {
m_pW3Context->GetRequest()->DeleteHeader( ppHeadersToBeRemoved ); m_pW3Context->GetRequest()->DeleteHeader(ppHeadersToBeRemoved);
ppHeadersToBeRemoved = mszMsAspNetCoreHeaders.Next( ppHeadersToBeRemoved ); ppHeadersToBeRemoved = mszMsAspNetCoreHeaders.Next(ppHeadersToBeRemoved);
} }
if( pServerProcess->QueryGuid() != NULL ) if (pServerProcess->QueryGuid() != NULL)
{ {
hr = m_pW3Context->GetRequest()->SetHeader( "MS-ASPNETCORE-TOKEN", hr = m_pW3Context->GetRequest()->SetHeader("MS-ASPNETCORE-TOKEN",
pServerProcess->QueryGuid(), pServerProcess->QueryGuid(),
(USHORT)strlen(pServerProcess->QueryGuid()), (USHORT)strlen(pServerProcess->QueryGuid()),
TRUE ); TRUE);
if(FAILED(hr)) if (FAILED(hr))
{ {
return hr; return hr;
} }
} }
if( pAspNetCoreConfig->QueryForwardWindowsAuthToken() && if (pAspNetCoreConfig->QueryForwardWindowsAuthToken() &&
(_wcsicmp(m_pW3Context->GetUser()->GetAuthenticationType(), L"negotiate") == 0 || (_wcsicmp(m_pW3Context->GetUser()->GetAuthenticationType(), L"negotiate") == 0 ||
_wcsicmp(m_pW3Context->GetUser()->GetAuthenticationType(), L"ntlm") == 0) ) _wcsicmp(m_pW3Context->GetUser()->GetAuthenticationType(), L"ntlm") == 0))
{ {
if( m_pW3Context->GetUser()->GetPrimaryToken() != NULL && if (m_pW3Context->GetUser()->GetPrimaryToken() != NULL &&
m_pW3Context->GetUser()->GetPrimaryToken() != INVALID_HANDLE_VALUE ) m_pW3Context->GetUser()->GetPrimaryToken() != INVALID_HANDLE_VALUE)
{ {
HANDLE hTargetTokenHandle = NULL; HANDLE hTargetTokenHandle = NULL;
hr = pServerProcess->SetWindowsAuthToken( m_pW3Context->GetUser()->GetPrimaryToken(), hr = pServerProcess->SetWindowsAuthToken(m_pW3Context->GetUser()->GetPrimaryToken(),
&hTargetTokenHandle ); &hTargetTokenHandle);
if(FAILED(hr)) if (FAILED(hr))
{ {
return hr; return hr;
} }
@ -691,18 +705,18 @@ FORWARDING_HANDLER::GetHeaders(
// //
// set request header with target token value // set request header with target token value
// //
CHAR pszHandleStr[16] = {0}; CHAR pszHandleStr[16] = { 0 };
if(_ui64toa_s( (UINT64) hTargetTokenHandle, pszHandleStr, 16, 16 ) != 0) if (_ui64toa_s((UINT64)hTargetTokenHandle, pszHandleStr, 16, 16) != 0)
{ {
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA); hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
return hr; return hr;
} }
hr = m_pW3Context->GetRequest()->SetHeader( "MS-ASPNETCORE-WINAUTHTOKEN", hr = m_pW3Context->GetRequest()->SetHeader("MS-ASPNETCORE-WINAUTHTOKEN",
pszHandleStr, pszHandleStr,
(USHORT)strlen(pszHandleStr), (USHORT)strlen(pszHandleStr),
TRUE ); TRUE);
if(FAILED(hr)) if (FAILED(hr))
{ {
return hr; return hr;
} }
@ -793,14 +807,14 @@ FORWARDING_HANDLER::GetHeaders(
} }
} }
if(FAILED(hr = strTemp.Append(pszScheme))) if (FAILED(hr = strTemp.Append(pszScheme)))
{ {
return hr; return hr;
} }
if(FAILED(pRequest->SetHeader(pProtocol->QuerySslHeaderName()->QueryStr(), if (FAILED(pRequest->SetHeader(pProtocol->QuerySslHeaderName()->QueryStr(),
strTemp.QueryStr(), strTemp.QueryStr(),
(USHORT) strTemp.QueryCCH(), (USHORT)strTemp.QueryCCH(),
TRUE))) TRUE)))
{ {
return hr; return hr;
@ -816,8 +830,9 @@ FORWARDING_HANDLER::GetHeaders(
} }
else else
{ {
// Resize the buffer large enough to hold the encoded certificate info
if (FAILED(hr = strTemp.Resize( if (FAILED(hr = strTemp.Resize(
1 + (pRequest->GetRawHttpRequest()->pSslInfo->pClientCertInfo->CertEncodedSize + 2)/3 * 4))) 1 + (pRequest->GetRawHttpRequest()->pSslInfo->pClientCertInfo->CertEncodedSize + 2) / 3 * 4)))
{ {
return hr; return hr;
} }
@ -869,7 +884,6 @@ FORWARDING_HANDLER::CreateWinHttpRequest(
__in const PROTOCOL_CONFIG * pProtocol, __in const PROTOCOL_CONFIG * pProtocol,
__in HINTERNET hConnect, __in HINTERNET hConnect,
__inout STRU * pstrUrl, __inout STRU * pstrUrl,
const STRU& strDestination,
ASPNETCORE_CONFIG* pAspNetCoreConfig, ASPNETCORE_CONFIG* pAspNetCoreConfig,
SERVER_PROCESS* pServerProcess SERVER_PROCESS* pServerProcess
) )
@ -877,7 +891,7 @@ FORWARDING_HANDLER::CreateWinHttpRequest(
HRESULT hr = S_OK; HRESULT hr = S_OK;
PCWSTR pszVersion = NULL; PCWSTR pszVersion = NULL;
PCSTR pszVerb; PCSTR pszVerb;
STACK_STRU( strVerb, 32 ); STACK_STRU(strVerb, 32);
// //
// Create the request handle for this request (leave some fields blank, // Create the request handle for this request (leave some fields blank,
@ -910,7 +924,7 @@ FORWARDING_HANDLER::CreateWinHttpRequest(
WINHTTP_NO_REFERER, WINHTTP_NO_REFERER,
WINHTTP_DEFAULT_ACCEPT_TYPES, WINHTTP_DEFAULT_ACCEPT_TYPES,
WINHTTP_FLAG_ESCAPE_DISABLE_QUERY WINHTTP_FLAG_ESCAPE_DISABLE_QUERY
| g_OptionalWinHttpFlags ); | g_OptionalWinHttpFlags);
if (m_hRequest == NULL) if (m_hRequest == NULL)
{ {
hr = HRESULT_FROM_WIN32(GetLastError()); hr = HRESULT_FROM_WIN32(GetLastError());
@ -964,8 +978,18 @@ FORWARDING_HANDLER::CreateWinHttpRequest(
goto Finished; goto Finished;
} }
if (WinHttpSetStatusCallback(m_hRequest,
FORWARDING_HANDLER::OnWinHttpCompletion,
(WINHTTP_CALLBACK_FLAG_ALL_COMPLETIONS |
WINHTTP_CALLBACK_FLAG_HANDLES |
WINHTTP_CALLBACK_STATUS_SENDING_REQUEST),
NULL) == WINHTTP_INVALID_STATUS_CALLBACK)
{
hr = HRESULT_FROM_WIN32(GetLastError());
goto Finished;
}
hr = GetHeaders(pProtocol, hr = GetHeaders(pProtocol,
strDestination.QueryStr(),
&m_pszHeaders, &m_pszHeaders,
&m_cchHeaders, &m_cchHeaders,
pAspNetCoreConfig, pAspNetCoreConfig,
@ -982,7 +1006,7 @@ Finished:
REQUEST_NOTIFICATION_STATUS REQUEST_NOTIFICATION_STATUS
FORWARDING_HANDLER::OnExecuteRequestHandler( FORWARDING_HANDLER::OnExecuteRequestHandler(
VOID VOID
) )
{ {
REQUEST_NOTIFICATION_STATUS retVal = RQ_NOTIFICATION_CONTINUE; REQUEST_NOTIFICATION_STATUS retVal = RQ_NOTIFICATION_CONTINUE;
@ -990,10 +1014,10 @@ VOID
bool fRequestLocked = FALSE; bool fRequestLocked = FALSE;
ASPNETCORE_CONFIG *pAspNetCoreConfig = NULL; ASPNETCORE_CONFIG *pAspNetCoreConfig = NULL;
FORWARDER_CONNECTION *pConnection = NULL; FORWARDER_CONNECTION *pConnection = NULL;
STACK_STRU( strDestination, 32); STACK_STRU(strDestination, 32);
STACK_STRU( strUrl, 2048); STACK_STRU(strUrl, 2048);
STACK_STRU( struEscapedUrl, 2048); STACK_STRU(struEscapedUrl, 2048);
STACK_STRU( strDescription, 128); STACK_STRU(strDescription, 128);
HINTERNET hConnect = NULL; HINTERNET hConnect = NULL;
IHttpRequest *pRequest = m_pW3Context->GetRequest(); IHttpRequest *pRequest = m_pW3Context->GetRequest();
IHttpResponse *pResponse = m_pW3Context->GetResponse(); IHttpResponse *pResponse = m_pW3Context->GetResponse();
@ -1065,8 +1089,8 @@ VOID
goto Failure; goto Failure;
} }
hr = pApplicationManager->GetApplication( m_pW3Context, hr = pApplicationManager->GetApplication(m_pW3Context,
&m_pApplication ); &m_pApplication);
if (FAILED(hr)) if (FAILED(hr))
{ {
goto Failure; goto Failure;
@ -1136,7 +1160,7 @@ VOID
goto Finished; goto Finished;
} }
hr = m_pApplication->GetProcess( m_pW3Context, hr = m_pApplication->GetProcess(m_pW3Context,
pAspNetCoreConfig, pAspNetCoreConfig,
&pServerProcess); &pServerProcess);
if (FAILED(hr)) if (FAILED(hr))
@ -1178,7 +1202,6 @@ VOID
pProtocol, pProtocol,
hConnect, hConnect,
&struEscapedUrl, &struEscapedUrl,
strDestination,
pAspNetCoreConfig, pAspNetCoreConfig,
pServerProcess); pServerProcess);
@ -1443,7 +1466,7 @@ Finished:
pConnection = NULL; pConnection = NULL;
} }
if( pServerProcess != NULL ) if (pServerProcess != NULL)
{ {
pServerProcess->DereferenceServerProcess(); pServerProcess->DereferenceServerProcess();
pServerProcess = NULL; pServerProcess = NULL;
@ -1494,17 +1517,17 @@ FORWARDING_HANDLER::OnAsyncCompletion(
Routine Description: Routine Description:
Handle the completion from IIS and continue the execution Handle the completion from IIS and continue the execution
of this request based on the current state. of this request based on the current state.
Arguments: Arguments:
cbCompletion - Number of bytes associated with this completion cbCompletion - Number of bytes associated with this completion
dwCompletionStatus - the win32 status associated with this completion dwCompletionStatus - the win32 status associated with this completion
Return Value: Return Value:
REQUEST_NOTIFICATION_STATUS REQUEST_NOTIFICATION_STATUS
--*/ --*/
{ {
@ -1512,17 +1535,16 @@ Return Value:
REQUEST_NOTIFICATION_STATUS retVal = RQ_NOTIFICATION_CONTINUE; REQUEST_NOTIFICATION_STATUS retVal = RQ_NOTIFICATION_CONTINUE;
BOOL fLocked = FALSE; BOOL fLocked = FALSE;
bool fClientError = FALSE; bool fClientError = FALSE;
DBG_ASSERT(m_pW3Context != NULL); BOOL fClosed = FALSE;
__analysis_assume(m_pW3Context != NULL);
if ( sm_pTraceLog != NULL ) if (sm_pTraceLog != NULL)
{ {
WriteRefTraceLogEx( sm_pTraceLog, WriteRefTraceLogEx(sm_pTraceLog,
m_cRefs, m_cRefs,
this, this,
"FORWARDING_HANDLER::OnAsyncCompletion Enter", "FORWARDING_HANDLER::OnAsyncCompletion Enter",
reinterpret_cast<PVOID>(static_cast<DWORD_PTR>(cbCompletion)), reinterpret_cast<PVOID>(static_cast<DWORD_PTR>(cbCompletion)),
reinterpret_cast<PVOID>(static_cast<DWORD_PTR>(hrCompletionStatus)) ); reinterpret_cast<PVOID>(static_cast<DWORD_PTR>(hrCompletionStatus)));
} }
// //
@ -1534,6 +1556,9 @@ Return Value:
// //
ReferenceForwardingHandler(); ReferenceForwardingHandler();
DBG_ASSERT(m_pW3Context != NULL);
__analysis_assume(m_pW3Context != NULL);
// //
// OnAsyncCompletion can be called on a Winhttp io completion thread. // OnAsyncCompletion can be called on a Winhttp io completion thread.
// Hence we need to check the TLS before we acquire the shared lock. // Hence we need to check the TLS before we acquire the shared lock.
@ -1551,7 +1576,7 @@ Return Value:
if (m_hRequest == NULL) if (m_hRequest == NULL)
{ {
if (m_RequestStatus == FORWARDER_DONE) if (m_RequestStatus == FORWARDER_DONE && m_fFinishRequest)
{ {
retVal = RQ_NOTIFICATION_FINISH_REQUEST; retVal = RQ_NOTIFICATION_FINISH_REQUEST;
goto Finished; goto Finished;
@ -1584,10 +1609,22 @@ Return Value:
// //
// WebSocket upgrade is successful. Close the WinHttpRequest Handle // WebSocket upgrade is successful. Close the WinHttpRequest Handle
// //
WinHttpSetStatusCallback(m_hRequest,
WinHttpCloseHandle(m_hRequest); FORWARDING_HANDLER::OnWinHttpCompletion,
WINHTTP_CALLBACK_FLAG_HANDLES,
NULL);
fClosed = WinHttpCloseHandle(m_hRequest);
DBG_ASSERT(fClosed);
if (fClosed)
{
m_fWebSocketUpgrade = TRUE;
m_hRequest = NULL; m_hRequest = NULL;
}
else
{
hr = HRESULT_FROM_WIN32(GetLastError());
goto Failure;
}
retVal = RQ_NOTIFICATION_PENDING; retVal = RQ_NOTIFICATION_PENDING;
goto Finished; goto Finished;
} }
@ -1662,6 +1699,13 @@ Failure:
IHttpResponse *pResponse = m_pW3Context->GetResponse(); IHttpResponse *pResponse = m_pW3Context->GetResponse();
pResponse->DisableKernelCache(); pResponse->DisableKernelCache();
pResponse->GetRawHttpResponse()->EntityChunkCount = 0; pResponse->GetRawHttpResponse()->EntityChunkCount = 0;
// double check to set right status code
if (!m_pW3Context->GetConnection()->IsConnected())
{
fClientError = TRUE;
}
if (fClientError) if (fClientError)
{ {
if (!m_fResponseHeadersReceivedAndSet) if (!m_fResponseHeadersReceivedAndSet)
@ -1679,14 +1723,14 @@ Failure:
} }
else else
{ {
STACK_STRU( strDescription, 128); STACK_STRU(strDescription, 128);
pResponse->SetStatus(502, "Bad Gateway", 3, hr); pResponse->SetStatus(502, "Bad Gateway", 3, hr);
if (hr > HRESULT_FROM_WIN32(WINHTTP_ERROR_BASE) && if (hr > HRESULT_FROM_WIN32(WINHTTP_ERROR_BASE) &&
hr <= HRESULT_FROM_WIN32(WINHTTP_ERROR_LAST)) hr <= HRESULT_FROM_WIN32(WINHTTP_ERROR_LAST))
{ {
#pragma prefast (suppress : __WARNING_FUNCTION_NEEDS_REVIEW, "Function and parameters reviewed.") #pragma prefast (suppress : __WARNING_FUNCTION_NEEDS_REVIEW, "Function and parameters reviewed.")
FormatMessage( FormatMessage(
FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_HMODULE, FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_HMODULE,
g_hWinHttpModule, g_hWinHttpModule,
@ -1703,7 +1747,7 @@ Failure:
strDescription.QueryStr(), strDescription.QueryStr(),
strDescription.QuerySizeCCH()); strDescription.QuerySizeCCH());
} }
(VOID) strDescription.SyncWithBuffer(); (VOID)strDescription.SyncWithBuffer();
if (strDescription.QueryCCH() != 0) if (strDescription.QueryCCH() != 0)
{ {
pResponse->SetErrorDescription( pResponse->SetErrorDescription(
@ -1712,7 +1756,7 @@ Failure:
FALSE); FALSE);
} }
if( hr == HRESULT_FROM_WIN32(ERROR_WINHTTP_INVALID_SERVER_RESPONSE)) if (hr == HRESULT_FROM_WIN32(ERROR_WINHTTP_INVALID_SERVER_RESPONSE))
{ {
pResponse->ResetConnection(); pResponse->ResetConnection();
goto Finished; goto Finished;
@ -1832,8 +1876,8 @@ FORWARDING_HANDLER::OnSendingRequest(
m_pEntityBuffer[4] = '\r'; m_pEntityBuffer[4] = '\r';
m_pEntityBuffer[5] = '\n'; m_pEntityBuffer[5] = '\n';
m_pEntityBuffer[cbCompletion+6] = '\r'; m_pEntityBuffer[cbCompletion + 6] = '\r';
m_pEntityBuffer[cbCompletion+7] = '\n'; m_pEntityBuffer[cbCompletion + 7] = '\n';
if (cbCompletion < 0x10) if (cbCompletion < 0x10)
{ {
@ -1918,7 +1962,7 @@ FORWARDING_HANDLER::OnReceivingResponse(
// buffering // buffering
// //
m_BytesToSend = min(m_cMinBufferLimit, BUFFER_SIZE); m_BytesToSend = min(m_cMinBufferLimit, BUFFER_SIZE);
if (m_BytesToSend < BUFFER_SIZE/2) if (m_BytesToSend < BUFFER_SIZE / 2)
{ {
// //
// Disable buffering. // Disable buffering.
@ -1986,10 +2030,10 @@ Failure:
VOID VOID
FORWARDING_HANDLER::OnWinHttpCompletionInternal( FORWARDING_HANDLER::OnWinHttpCompletionInternal(
HINTERNET hRequest, HINTERNET hRequest,
DWORD dwInternetStatus, DWORD dwInternetStatus,
LPVOID lpvStatusInformation, LPVOID lpvStatusInformation,
DWORD dwStatusInformationLength DWORD dwStatusInformationLength
) )
/*++ /*++
@ -2018,6 +2062,7 @@ None
__analysis_assume(m_pW3Context != NULL); __analysis_assume(m_pW3Context != NULL);
IHttpResponse * pResponse = m_pW3Context->GetResponse(); IHttpResponse * pResponse = m_pW3Context->GetResponse();
BOOL fDerefForwardingHandler = TRUE; BOOL fDerefForwardingHandler = TRUE;
BOOL fEndRequest = FALSE;
UNREFERENCED_PARAMETER(dwStatusInformationLength); UNREFERENCED_PARAMETER(dwStatusInformationLength);
@ -2032,14 +2077,69 @@ None
} }
// //
// If the request is upgraded to websocket, route the completion // ReadLock on the winhttp handle to protect from a client disconnect/
// to the websocket handler. We don't need to take the request lock, // server stop closing the handle while we are using it.
// since for websocket request, the parent request handle is already
// closed.
// //
// WinHttp can call async completion on the same thread/stack, so
// we have to account for that and not try to take the lock again,
// otherwise, we could end up in a deadlock.
//
// Take a reference so that object does not go away as a result of
// async completion - release one reference when async operation is
// initiated, two references if async operation is not initiated
//
if (TlsGetValue(g_dwTlsIndex) != this)
{
DBG_ASSERT(TlsGetValue(g_dwTlsIndex) == NULL);
AcquireSRWLockShared(&m_RequestLock);
TlsSetValue(g_dwTlsIndex, this);
fIsCompletionThread = TRUE;
DBG_ASSERT(TlsGetValue(g_dwTlsIndex) == this);
}
fEndRequest = (dwInternetStatus == WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING);
if (!fEndRequest)
{
if (!m_pW3Context->GetConnection()->IsConnected())
{
m_fClientDisconnected = TRUE;
if (m_hRequest != NULL)
{
WinHttpSetStatusCallback(m_hRequest,
FORWARDING_HANDLER::OnWinHttpCompletion,
WINHTTP_CALLBACK_FLAG_HANDLES,
NULL);
if (WinHttpCloseHandle(m_hRequest))
{
m_hRequest = NULL;
}
else
{
// if WinHttpCloseHandle failed, we are already in failure path
// nothing can can be done here
}
}
hr = ERROR_CONNECTION_ABORTED;
fClientError = m_fHandleClosedDueToClient = TRUE;
fDerefForwardingHandler = FALSE;
// wait for HANDLE_CLOSING callback to clean up
fAnotherCompletionExpected = !fEndRequest;
goto Failure;
}
}
if (m_RequestStatus == FORWARDER_RECEIVED_WEBSOCKET_RESPONSE) if (m_RequestStatus == FORWARDER_RECEIVED_WEBSOCKET_RESPONSE)
{ {
fDerefForwardingHandler = FALSE;
fAnotherCompletionExpected = TRUE;
if(m_pWebSocket == NULL)
{
goto Finished;
}
switch (dwInternetStatus) switch (dwInternetStatus)
{ {
case WINHTTP_CALLBACK_STATUS_SHUTDOWN_COMPLETE: case WINHTTP_CALLBACK_STATUS_SHUTDOWN_COMPLETE:
@ -2064,46 +2164,10 @@ None
); );
break; break;
} }
fDerefForwardingHandler = FALSE;
fAnotherCompletionExpected = TRUE;
goto Finished; goto Finished;
} }
//
// ReadLock on the winhttp handle to protect from a client disconnect/
// server stop closing the handle while we are using it.
//
// WinHttp can call async completion on the same thread/stack, so
// we have to account for that and not try to take the lock again,
// otherwise, we could end up in a deadlock.
//
// Take a reference so that object does not go away as a result of
// async completion - release one reference when async operation is
// initiated, two references if async operation is not initiated
//
if (TlsGetValue(g_dwTlsIndex) != this)
{
DBG_ASSERT(TlsGetValue(g_dwTlsIndex) == NULL);
AcquireSRWLockShared(&m_RequestLock);
TlsSetValue(g_dwTlsIndex, this);
fIsCompletionThread = TRUE;
DBG_ASSERT(TlsGetValue(g_dwTlsIndex) == this);
}
if (m_hRequest == NULL)
{
fClientError = m_fHandleClosedDueToClient;
goto Failure;
}
if (!m_pWebSocket)
{
DBG_ASSERT(hRequest == m_hRequest);
}
switch (dwInternetStatus) switch (dwInternetStatus)
{ {
@ -2154,6 +2218,21 @@ None
fDerefForwardingHandler = FALSE; fDerefForwardingHandler = FALSE;
fAnotherCompletionExpected = TRUE; fAnotherCompletionExpected = TRUE;
break; break;
case WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING:
if (m_RequestStatus != FORWARDER_DONE)
{
hr = ERROR_CONNECTION_ABORTED;
fClientError = m_fHandleClosedDueToClient;
}
else
{
fDerefForwardingHandler = m_fClientDisconnected && !m_fWebSocketUpgrade;
}
m_hRequest = NULL;
m_pWebSocket = NULL;
fAnotherCompletionExpected = FALSE;
break;
case WINHTTP_CALLBACK_STATUS_CONNECTION_CLOSED: case WINHTTP_CALLBACK_STATUS_CONNECTION_CLOSED:
hr = ERROR_CONNECTION_ABORTED; hr = ERROR_CONNECTION_ABORTED;
break; break;
@ -2190,17 +2269,20 @@ None
goto Finished; goto Finished;
Failure: Failure:
m_RequestStatus = FORWARDER_DONE;
if (!m_fErrorHandled)
{
m_fErrorHandled = TRUE;
if (hr == HRESULT_FROM_WIN32(ERROR_WINHTTP_INVALID_SERVER_RESPONSE)) if (hr == HRESULT_FROM_WIN32(ERROR_WINHTTP_INVALID_SERVER_RESPONSE))
{ {
m_RequestStatus = FORWARDER_RESET_CONNECTION; m_RequestStatus = FORWARDER_RESET_CONNECTION;
goto Finished; goto Finished;
} }
m_RequestStatus = FORWARDER_DONE;
pResponse->DisableKernelCache(); pResponse->DisableKernelCache();
pResponse->GetRawHttpResponse()->EntityChunkCount = 0; pResponse->GetRawHttpResponse()->EntityChunkCount = 0;
fClientError = !m_pW3Context->GetConnection()->IsConnected();
if (fClientError) if (fClientError)
{ {
if (!m_fResponseHeadersReceivedAndSet) if (!m_fResponseHeadersReceivedAndSet)
@ -2251,8 +2333,10 @@ Failure:
FALSE); FALSE);
} }
} }
}
Finished: Finished:
if (fIsCompletionThread) if (fIsCompletionThread)
{ {
DBG_ASSERT(TlsGetValue(g_dwTlsIndex) == this); DBG_ASSERT(TlsGetValue(g_dwTlsIndex) == this);
@ -2275,14 +2359,45 @@ Finished:
// If fAnotherCompletionExpected is false, this method must post the completion. // If fAnotherCompletionExpected is false, this method must post the completion.
// //
if (m_RequestStatus == FORWARDER_DONE)
{
if (m_hRequest != NULL)
{
WinHttpSetStatusCallback(m_hRequest,
FORWARDING_HANDLER::OnWinHttpCompletion,
WINHTTP_CALLBACK_FLAG_HANDLES,
NULL);
if(WinHttpCloseHandle(m_hRequest))
{
m_hRequest = NULL;
}
}
if (m_pWebSocket != NULL)
{
m_pWebSocket->TerminateRequest();
m_pWebSocket = NULL;
}
if (!fAnotherCompletionExpected ) if(fEndRequest)
{
// only postCompletion after WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING
// so that no further WinHttp callback will be called
// in case of websocket, m_hRequest has already been closed after upgrade
// websocket will handle completion
m_fFinishRequest = TRUE;
m_pW3Context->PostCompletion(0);
}
}
else if (!fAnotherCompletionExpected)
{ {
// //
// Since we use TLS to guard WinHttp operation, call PostCompletion instead of // Since we use TLS to guard WinHttp operation, call PostCompletion instead of
// IndicateCompletion to allow cleaning up the TLS before thread reuse. // IndicateCompletion to allow cleaning up the TLS before thread reuse.
// //
m_pW3Context->PostCompletion(0); m_pW3Context->PostCompletion(0);
// //
// No code executed after posting the completion. // No code executed after posting the completion.
// //
@ -2292,7 +2407,7 @@ Finished:
HRESULT HRESULT
FORWARDING_HANDLER::OnWinHttpCompletionSendRequestOrWriteComplete( FORWARDING_HANDLER::OnWinHttpCompletionSendRequestOrWriteComplete(
HINTERNET hRequest, HINTERNET hRequest,
DWORD , DWORD,
__out bool * pfClientError, __out bool * pfClientError,
__out bool * pfAnotherCompletionExpected __out bool * pfAnotherCompletionExpected
) )
@ -2414,8 +2529,8 @@ FORWARDING_HANDLER::OnWinHttpCompletionStatusHeadersAvailable(
) )
{ {
HRESULT hr = S_OK; HRESULT hr = S_OK;
STACK_BUFFER( bufHeaderBuffer, 2048); STACK_BUFFER(bufHeaderBuffer, 2048);
STACK_STRA( strHeaders, 2048); STACK_STRA(strHeaders, 2048);
DWORD dwHeaderSize = bufHeaderBuffer.QuerySize(); DWORD dwHeaderSize = bufHeaderBuffer.QuerySize();
UNREFERENCED_PARAMETER(pfAnotherCompletionExpected); UNREFERENCED_PARAMETER(pfAnotherCompletionExpected);
@ -2471,10 +2586,10 @@ FORWARDING_HANDLER::OnWinHttpCompletionStatusHeadersAvailable(
// HTTP/1.1 302 Moved Permanently\r\n....\r\nLocation:http://site\0 // HTTP/1.1 302 Moved Permanently\r\n....\r\nLocation:http://site\0
// //
if ( !strHeaders.IsEmpty() && strHeaders.QueryStr()[strHeaders.QueryCCH() - 1] != '\n' ) if (!strHeaders.IsEmpty() && strHeaders.QueryStr()[strHeaders.QueryCCH() - 1] != '\n')
{ {
hr = strHeaders.Append( "\r\n" ); hr = strHeaders.Append("\r\n");
if ( FAILED( hr ) ) if (FAILED(hr))
{ {
goto Finished; goto Finished;
} }
@ -2596,7 +2711,7 @@ FORWARDING_HANDLER::OnWinHttpCompletionStatusReadComplete(
// //
m_BytesToSend -= dwStatusInformationLength; m_BytesToSend -= dwStatusInformationLength;
if (m_cMinBufferLimit >= BUFFER_SIZE/2) if (m_cMinBufferLimit >= BUFFER_SIZE / 2)
{ {
if (m_cContentLength != 0) if (m_cContentLength != 0)
{ {
@ -2676,15 +2791,15 @@ FORWARDING_HANDLER::StaticInitialize(
Routine Description: Routine Description:
Global initialization routine for FORWARDING_HANDLERs Global initialization routine for FORWARDING_HANDLERs
Arguments: Arguments:
fEnableReferenceCountTracing - True if ref count tracing should be use. fEnableReferenceCountTracing - True if ref count tracing should be use.
Return Value: Return Value:
HRESULT HRESULT
--*/ --*/
{ {
@ -2730,8 +2845,8 @@ Return Value:
// //
if (WinHttpSetStatusCallback(sm_hSession, if (WinHttpSetStatusCallback(sm_hSession,
FORWARDING_HANDLER::OnWinHttpCompletion, FORWARDING_HANDLER::OnWinHttpCompletion,
( WINHTTP_CALLBACK_FLAG_ALL_COMPLETIONS | (WINHTTP_CALLBACK_FLAG_ALL_COMPLETIONS |
WINHTTP_CALLBACK_STATUS_SENDING_REQUEST ), WINHTTP_CALLBACK_STATUS_SENDING_REQUEST),
NULL) == WINHTTP_INVALID_STATUS_CALLBACK) NULL) == WINHTTP_INVALID_STATUS_CALLBACK)
{ {
hr = HRESULT_FROM_WIN32(GetLastError()); hr = HRESULT_FROM_WIN32(GetLastError());
@ -2754,14 +2869,14 @@ Return Value:
// Initialize Application Manager // Initialize Application Manager
APPLICATION_MANAGER *pApplicationManager = APPLICATION_MANAGER::GetInstance(); APPLICATION_MANAGER *pApplicationManager = APPLICATION_MANAGER::GetInstance();
if(pApplicationManager == NULL) if (pApplicationManager == NULL)
{ {
hr = E_OUTOFMEMORY; hr = E_OUTOFMEMORY;
goto Failure; goto Failure;
} }
hr = pApplicationManager->Initialize(); hr = pApplicationManager->Initialize();
if(FAILED(hr)) if (FAILED(hr))
{ {
goto Failure; goto Failure;
} }
@ -2803,9 +2918,9 @@ Return Value:
goto Failure; goto Failure;
} }
if ( fEnableReferenceCountTracing ) if (fEnableReferenceCountTracing)
{ {
sm_pTraceLog = CreateRefTraceLog( 10000, 0 ); sm_pTraceLog = CreateRefTraceLog(10000, 0);
} }
return S_OK; return S_OK;
@ -2826,15 +2941,15 @@ FORWARDING_HANDLER::StaticTerminate(
Routine Description: Routine Description:
Global termination routine for FORWARDING_HANDLERs Global termination routine for FORWARDING_HANDLERs
Arguments: Arguments:
None None
Return Value: Return Value:
None None
--*/ --*/
{ {
@ -2851,9 +2966,9 @@ Return Value:
DWORD tickCount = GetTickCount(); DWORD tickCount = GetTickCount();
while( g_dwActiveServerProcesses > 0 ) while (g_dwActiveServerProcesses > 0)
{ {
if( (GetTickCount() - tickCount) > 10000 ) if ((GetTickCount() - tickCount) > 10000)
{ {
break; break;
} }
@ -2905,7 +3020,7 @@ CopyMultiSzToOutput(
PCWSTR pszListCopy = pszList; PCWSTR pszListCopy = pszList;
while (*pszList != L'\0') while (*pszList != L'\0')
{ {
cbData += (static_cast<DWORD>(wcslen(pszList)) + 1)*sizeof(WCHAR); cbData += (static_cast<DWORD>(wcslen(pszList)) + 1) * sizeof(WCHAR);
pszList += wcslen(pszList) + 1; pszList += wcslen(pszList) + 1;
} }
cbData += sizeof(WCHAR); cbData += sizeof(WCHAR);
@ -2943,13 +3058,27 @@ FORWARDING_HANDLER::TerminateRequest(
bool fClientInitiated bool fClientInitiated
) )
{ {
AcquireSRWLockExclusive(&m_RequestLock); bool fAcquiredLock = FALSE;
if (TlsGetValue(g_dwTlsIndex) != this)
{
DBG_ASSERT(TlsGetValue(g_dwTlsIndex) == NULL);
AcquireSRWLockShared(&m_RequestLock);
TlsSetValue(g_dwTlsIndex, this);
DBG_ASSERT(TlsGetValue(g_dwTlsIndex) == this);
fAcquiredLock = TRUE;
}
if (m_hRequest != NULL) if (m_hRequest != NULL)
{ {
WinHttpCloseHandle(m_hRequest); WinHttpSetStatusCallback(m_hRequest,
FORWARDING_HANDLER::OnWinHttpCompletion,
WINHTTP_CALLBACK_FLAG_HANDLES,
NULL);
if (WinHttpCloseHandle(m_hRequest))
{
m_hRequest = NULL; m_hRequest = NULL;
}
m_fHandleClosedDueToClient = fClientInitiated; m_fHandleClosedDueToClient = fClientInitiated;
} }
@ -2962,7 +3091,13 @@ FORWARDING_HANDLER::TerminateRequest(
m_pWebSocket->TerminateRequest(); m_pWebSocket->TerminateRequest();
} }
ReleaseSRWLockExclusive(&m_RequestLock); if (fAcquiredLock)
{
DBG_ASSERT(TlsGetValue(g_dwTlsIndex) == this);
TlsSetValue(g_dwTlsIndex, NULL);
ReleaseSRWLockShared(&m_RequestLock);
DBG_ASSERT(TlsGetValue(g_dwTlsIndex) == NULL);
}
} }
BYTE * BYTE *
@ -2970,10 +3105,10 @@ FORWARDING_HANDLER::GetNewResponseBuffer(
DWORD dwBufferSize DWORD dwBufferSize
) )
{ {
DWORD dwNeededSize = (m_cEntityBuffers+1)*sizeof(BYTE *); DWORD dwNeededSize = (m_cEntityBuffers + 1) * sizeof(BYTE *);
if (dwNeededSize > m_buffEntityBuffers.QuerySize() && if (dwNeededSize > m_buffEntityBuffers.QuerySize() &&
!m_buffEntityBuffers.Resize( !m_buffEntityBuffers.Resize(
max(dwNeededSize, m_buffEntityBuffers.QuerySize()*2))) max(dwNeededSize, m_buffEntityBuffers.QuerySize() * 2)))
{ {
return NULL; return NULL;
} }
@ -2996,7 +3131,7 @@ VOID
FORWARDING_HANDLER::FreeResponseBuffers() FORWARDING_HANDLER::FreeResponseBuffers()
{ {
BYTE **pBuffers = m_buffEntityBuffers.QueryPtr(); BYTE **pBuffers = m_buffEntityBuffers.QueryPtr();
for (DWORD i=0; i<m_cEntityBuffers; i++) for (DWORD i = 0; i<m_cEntityBuffers; i++)
{ {
HeapFree(GetProcessHeap(), HeapFree(GetProcessHeap(),
0, // dwFlags 0, // dwFlags

View File

@ -86,7 +86,7 @@ inline bool IsSpace(char ch)
#include <acache.h> #include <acache.h>
#include <time.h> #include <time.h>
#include "aspnetcoreutils.h" #include "environmentvariablehash.h"
#include "..\aspnetcore_msg.h" #include "..\aspnetcore_msg.h"
#include "aspnetcoreconfig.h" #include "aspnetcoreconfig.h"
#include "serverprocess.h" #include "serverprocess.h"

View File

@ -238,6 +238,9 @@ PROCESS_MANAGER::GetProcess(
pConfig->QueryArguments(), pConfig->QueryArguments(),
pConfig->QueryStartupTimeLimitInMS(), pConfig->QueryStartupTimeLimitInMS(),
pConfig->QueryShutdownTimeLimitInMS(), pConfig->QueryShutdownTimeLimitInMS(),
pConfig->QueryWindowsAuthEnabled(),
pConfig->QueryBasicAuthEnabled(),
pConfig->QueryAnonymousAuthEnabled(),
pConfig->QueryEnvironmentVariables(), pConfig->QueryEnvironmentVariables(),
pConfig->QueryStdoutLogEnabled(), pConfig->QueryStdoutLogEnabled(),
pConfig->QueryStdoutLogFile() pConfig->QueryStdoutLogFile()

View File

@ -11,7 +11,6 @@ PROTOCOL_CONFIG::Initialize()
m_fKeepAlive = TRUE; m_fKeepAlive = TRUE;
m_msTimeout = 120000; m_msTimeout = 120000;
m_fPreserveHostHeader = TRUE;
m_fReverseRewriteHeaders = FALSE; m_fReverseRewriteHeaders = FALSE;
if (FAILED(hr = m_strXForwardedForName.CopyW(L"X-Forwarded-For"))) if (FAILED(hr = m_strXForwardedForName.CopyW(L"X-Forwarded-For")))

File diff suppressed because it is too large Load Diff

View File

@ -212,7 +212,10 @@ WEBSOCKET_HANDLER::IndicateCompletionToIIS(
_pHandler->SetStatus(FORWARDER_DONE); _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 HRESULT
@ -744,18 +747,25 @@ Routine Description:
++*/ ++*/
{ {
HRESULT hr = S_OK; HRESULT hr = S_OK;
BOOL fLocked = FALSE;
CleanupReason cleanupReason = CleanupReasonUnknown; CleanupReason cleanupReason = CleanupReasonUnknown;
DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO, DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO,
"WEBSOCKET_HANDLER::OnWinHttpSendComplete"); "WEBSOCKET_HANDLER::OnWinHttpSendComplete");
EnterCriticalSection (&_RequestLock);
if (_fCleanupInProgress) if (_fCleanupInProgress)
{ {
goto Finished; goto Finished;
} }
EnterCriticalSection (&_RequestLock);
fLocked = TRUE;
if (_fCleanupInProgress)
{
goto Finished;
}
// //
// Data was successfully sent to backend. // Data was successfully sent to backend.
// Initiate next receive from IIS. // Initiate next receive from IIS.
@ -768,8 +778,10 @@ Routine Description:
} }
Finished: Finished:
if (fLocked)
{
LeaveCriticalSection(&_RequestLock); LeaveCriticalSection(&_RequestLock);
}
if (FAILED (hr)) if (FAILED (hr))
{ {
@ -840,18 +852,24 @@ Routine Description:
--*/ --*/
{ {
HRESULT hr = S_OK; HRESULT hr = S_OK;
BOOL fLocked = FALSE;
CleanupReason cleanupReason = CleanupReasonUnknown; CleanupReason cleanupReason = CleanupReasonUnknown;
DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO, DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO,
"WEBSOCKET_HANDLER::OnWinHttpReceiveComplete"); "WEBSOCKET_HANDLER::OnWinHttpReceiveComplete");
EnterCriticalSection(&_RequestLock);
if (_fCleanupInProgress) if (_fCleanupInProgress)
{ {
goto Finished; goto Finished;
} }
EnterCriticalSection(&_RequestLock);
fLocked = TRUE;
if (_fCleanupInProgress)
{
goto Finished;
}
hr = DoIisWebSocketSend( hr = DoIisWebSocketSend(
pCompletionStatus->dwBytesTransferred, pCompletionStatus->dwBytesTransferred,
pCompletionStatus->eBufferType pCompletionStatus->eBufferType
@ -864,9 +882,10 @@ Routine Description:
} }
Finished: Finished:
if (fLocked)
{
LeaveCriticalSection(&_RequestLock); LeaveCriticalSection(&_RequestLock);
}
if (FAILED (hr)) if (FAILED (hr))
{ {
Cleanup (cleanupReason); Cleanup (cleanupReason);
@ -902,21 +921,26 @@ Routine Description:
--*/ --*/
{ {
HRESULT hr = S_OK; HRESULT hr = S_OK;
BOOL fLocked = FALSE;
CleanupReason cleanupReason = CleanupReasonUnknown; CleanupReason cleanupReason = CleanupReasonUnknown;
UNREFERENCED_PARAMETER(cbIo); UNREFERENCED_PARAMETER(cbIo);
DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO, "WEBSOCKET_HANDLER::OnIisSendComplete"); DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO, "WEBSOCKET_HANDLER::OnIisSendComplete");
EnterCriticalSection(&_RequestLock); if (FAILED(hrCompletion))
if (FAILED (hrCompletion))
{ {
hr = hrCompletion; hr = hrCompletion;
cleanupReason = ClientDisconnect; cleanupReason = ClientDisconnect;
goto Finished; goto Finished;
} }
if (_fCleanupInProgress)
{
goto Finished;
}
EnterCriticalSection(&_RequestLock);
fLocked = TRUE;
if (_fCleanupInProgress) if (_fCleanupInProgress)
{ {
goto Finished; goto Finished;
@ -934,9 +958,10 @@ Routine Description:
} }
Finished: Finished:
if (fLocked)
{
LeaveCriticalSection(&_RequestLock); LeaveCriticalSection(&_RequestLock);
}
if (FAILED (hr)) if (FAILED (hr))
{ {
Cleanup (cleanupReason); Cleanup (cleanupReason);
@ -977,15 +1002,14 @@ Routine Description:
--*/ --*/
{ {
HRESULT hr = S_OK; HRESULT hr = S_OK;
BOOL fLocked = FALSE;
CleanupReason cleanupReason = CleanupReasonUnknown; CleanupReason cleanupReason = CleanupReasonUnknown;
WINHTTP_WEB_SOCKET_BUFFER_TYPE BufferType; WINHTTP_WEB_SOCKET_BUFFER_TYPE BufferType;
DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO, DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO,
"WEBSOCKET_HANDLER::OnIisReceiveComplete"); "WEBSOCKET_HANDLER::OnIisReceiveComplete");
EnterCriticalSection(&_RequestLock); if (FAILED(hrCompletion))
if (FAILED (hrCompletion))
{ {
cleanupReason = ClientDisconnect; cleanupReason = ClientDisconnect;
hr = hrCompletion; hr = hrCompletion;
@ -997,6 +1021,13 @@ Routine Description:
goto Finished; goto Finished;
} }
EnterCriticalSection(&_RequestLock);
fLocked = TRUE;
if (_fCleanupInProgress)
{
goto Finished;
}
// //
// Get Buffer Type from flags. // Get Buffer Type from flags.
// //
@ -1018,9 +1049,10 @@ Routine Description:
} }
Finished: Finished:
if (fLocked)
{
LeaveCriticalSection(&_RequestLock); LeaveCriticalSection(&_RequestLock);
}
if (FAILED (hr)) if (FAILED (hr))
{ {
Cleanup (cleanupReason); Cleanup (cleanupReason);
@ -1042,7 +1074,7 @@ Finished:
VOID VOID
WEBSOCKET_HANDLER::Cleanup( WEBSOCKET_HANDLER::Cleanup(
CleanupReason reason CleanupReason reason
) )
/*++ /*++
Routine Description: Routine Description:
@ -1056,11 +1088,18 @@ Arguments:
CleanupReason CleanupReason
--*/ --*/
{ {
DebugPrintf (ASPNETCORE_DEBUG_FLAG_INFO, BOOL fLocked = FALSE;
DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO,
"WEBSOCKET_HANDLER::Cleanup Initiated with reason %d", reason); "WEBSOCKET_HANDLER::Cleanup Initiated with reason %d", reason);
if (_fCleanupInProgress)
{
goto Finished;
}
EnterCriticalSection(&_RequestLock); EnterCriticalSection(&_RequestLock);
fLocked = TRUE;
if (_fCleanupInProgress) if (_fCleanupInProgress)
{ {
goto Finished; goto Finished;
@ -1080,5 +1119,8 @@ Arguments:
_pHttpContext->CancelIo(); _pHttpContext->CancelIo();
Finished: Finished:
if (fLocked)
{
LeaveCriticalSection(&_RequestLock); LeaveCriticalSection(&_RequestLock);
}
} }