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\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" />

View File

@ -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 )

View File

@ -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:
@ -55,12 +58,12 @@ public:
_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()
{
@ -156,9 +177,9 @@ private:
//
// private constructor
//
ASPNETCORE_CONFIG():
m_fStdoutLogEnabled( FALSE )
m_fStdoutLogEnabled( FALSE ),
m_pEnvironmentVariables( NULL )
{
}
@ -170,15 +191,17 @@ private:
DWORD m_dwRequestTimeoutInMS;
DWORD m_dwStartupTimeLimitInMS;
DWORD m_dwShutdownTimeLimitInMS;
MULTISZ m_mszEnvironment;
DWORD m_dwRapidFailsPerMinute;
DWORD m_dwProcessesPerApplication;
STRU m_struApplication;
STRU m_struArguments;
STRU m_struProcessPath;
BOOL m_fStdoutLogEnabled;
STRU m_struStdoutLogFile;
DWORD m_dwProcessesPerApplication;
BOOL m_fStdoutLogEnabled;
BOOL m_fForwardWindowsAuthToken;
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
/*++
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;

View File

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

View File

@ -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;
@ -30,7 +37,10 @@ public:
_In_ STRU *pszArguments,
_In_ DWORD dwStartupTimeLimitInMS,
_In_ DWORD dwShtudownTimeLimitInMS,
_In_ MULTISZ *pszEnvironment,
_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 ;
};

View File

@ -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);
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)
{
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)
{
pOldAppOfflineHtm->DereferenceAppOfflineHtm();
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());
}
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;
@ -36,7 +42,7 @@ ASPNETCORE_CONFIG::GetConfig(
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->
pAspNetCoreConfig = (ASPNETCORE_CONFIG*)pHttpApplication->
GetModuleContextContainer()->
GetModuleContext( g_pModuleId );
GetModuleContext(g_pModuleId);
_ASSERT( pAspNetCoreConfig != NULL );
_ASSERT(pAspNetCoreConfig != NULL);
hr = S_OK;
}
@ -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,
hr = pAdminManager->GetAdminSection(CS_WINDOWS_AUTHENTICATION_SECTION,
strSiteConfigPath.QueryStr(),
&pAspNetCoreElement );
if( FAILED( hr ) )
&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,
hr = GetElementStringProperty(pAspNetCoreElement,
CS_ASPNETCORE_PROCESS_EXE_PATH,
&m_struProcessPath );
if( FAILED( hr ) )
&m_struProcessPath);
if (FAILED(hr))
{
goto Finished;
}
hr = GetElementStringProperty( pAspNetCoreElement,
hr = GetElementStringProperty(pAspNetCoreElement,
CS_ASPNETCORE_PROCESS_ARGUMENTS,
&m_struArguments );
if( FAILED( hr ) )
&m_struArguments);
if (FAILED(hr))
{
goto Finished;
}
hr = GetElementDWORDProperty( pAspNetCoreElement,
hr = GetElementDWORDProperty(pAspNetCoreElement,
CS_ASPNETCORE_RAPID_FAILS_PER_MINUTE,
&m_dwRapidFailsPerMinute );
if( FAILED( hr ) )
&m_dwRapidFailsPerMinute);
if (FAILED(hr))
{
goto Finished;
}
@ -185,16 +243,15 @@ 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,
hr = GetElementDWORDProperty(pAspNetCoreElement,
CS_ASPNETCORE_PROCESSES_PER_APPLICATION,
&m_dwProcessesPerApplication );
if( FAILED( hr ) )
&m_dwProcessesPerApplication);
if (FAILED(hr))
{
goto Finished;
}
@ -204,7 +261,7 @@ ASPNETCORE_CONFIG::Populate(
CS_ASPNETCORE_PROCESS_STARTUP_TIME_LIMIT,
&m_dwStartupTimeLimitInMS
);
if( FAILED( hr ) )
if (FAILED(hr))
{
goto Finished;
}
@ -222,10 +279,10 @@ ASPNETCORE_CONFIG::Populate(
}
m_dwShutdownTimeLimitInMS *= MILLISECONDS_IN_ONE_SECOND;
hr = GetElementBoolProperty( pAspNetCoreElement,
hr = GetElementBoolProperty(pAspNetCoreElement,
CS_ASPNETCORE_FORWARD_WINDOWS_AUTH_TOKEN,
&m_fForwardWindowsAuthToken );
if( FAILED( hr ) )
&m_fForwardWindowsAuthToken);
if (FAILED(hr))
{
goto Finished;
}
@ -243,240 +300,116 @@ ASPNETCORE_CONFIG::Populate(
CS_ASPNETCORE_WINHTTP_REQUEST_TIMEOUT,
&ullRawTimeSpan
);
if( FAILED( hr ) )
if (FAILED(hr))
{
goto Finished;
}
m_dwRequestTimeoutInMS = (DWORD)TIMESPAN_IN_MILLISECONDS(ullRawTimeSpan);
hr = GetElementBoolProperty( pAspNetCoreElement,
hr = GetElementBoolProperty(pAspNetCoreElement,
CS_ASPNETCORE_STDOUT_LOG_ENABLED,
&m_fStdoutLogEnabled );
if( FAILED( hr ) )
&m_fStdoutLogEnabled);
if (FAILED(hr))
{
goto Finished;
}
hr = GetElementStringProperty( pAspNetCoreElement,
hr = GetElementStringProperty(pAspNetCoreElement,
CS_ASPNETCORE_STDOUT_LOG_FILE,
&m_struStdoutLogFile );
if( FAILED( hr ) )
&m_struStdoutLogFile);
if (FAILED(hr))
{
goto Finished;
}
hr = GetElementChildByName( pAspNetCoreElement,
hr = GetElementChildByName(pAspNetCoreElement,
CS_ASPNETCORE_ENVIRONMENT_VARIABLES,
&pEnvVarList );
if( FAILED( hr ) )
&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,
if (FAILED(hr = GetElementStringProperty(pEnvVar,
CS_ASPNETCORE_ENVIRONMENT_VARIABLE_NAME,
&strEnvName);
if( FAILED( hr ) )
{
goto Finished;
}
hr = GetElementStringProperty( pEnvVar,
&strEnvName)) ||
FAILED(hr = GetElementStringProperty(pEnvVar,
CS_ASPNETCORE_ENVIRONMENT_VARIABLE_VALUE,
&strEnvValue);
if( FAILED( hr ) )
&strEnvValue)) ||
FAILED(hr = strEnvName.Append(L"=")) ||
FAILED(hr = STRU::ExpandEnvironmentVariables(strEnvValue.QueryStr(), &strExpandedEnvValue)))
{
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;
}

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.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))

View File

@ -22,32 +22,36 @@ PROTOCOL_CONFIG FORWARDING_HANDLER::sm_ProtocolConfig;
FORWARDING_HANDLER::FORWARDING_HANDLER(
__in IHttpContext * pW3Context
) : m_Signature ( FORWARDING_HANDLER_SIGNATURE ),
m_cRefs ( 1 ),
m_pW3Context ( pW3Context ),
m_pChildRequestContext ( NULL ),
m_hRequest ( NULL ),
m_fHandleClosedDueToClient( FALSE ),
m_fResponseHeadersReceivedAndSet( FALSE ),
m_fDoReverseRewriteHeaders ( FALSE ),
m_msStartTime ( 0 ),
m_BytesToReceive ( 0 ),
m_BytesToSend ( 0 ),
m_pEntityBuffer ( NULL ),
m_cchLastSend ( 0 ),
m_cEntityBuffers ( 0 ),
m_cBytesBuffered ( 0 ),
m_cMinBufferLimit ( 0 ),
m_pszOriginalHostHeader ( NULL ),
m_RequestStatus ( FORWARDER_START ),
m_pDisconnect ( NULL ),
m_pszHeaders ( NULL ),
m_cchHeaders ( 0 ),
m_fWebSocketEnabled ( FALSE ),
m_cContentLength ( 0 ),
m_pWebSocket ( NULL ),
m_pApplication( NULL ),
m_pAppOfflineHtm( NULL )
) : m_Signature(FORWARDING_HANDLER_SIGNATURE),
m_cRefs(1),
m_pW3Context(pW3Context),
m_pChildRequestContext(NULL),
m_hRequest(NULL),
m_fHandleClosedDueToClient(FALSE),
m_fResponseHeadersReceivedAndSet(FALSE),
m_fDoReverseRewriteHeaders(FALSE),
m_msStartTime(0),
m_BytesToReceive(0),
m_BytesToSend(0),
m_pEntityBuffer(NULL),
m_cchLastSend(0),
m_cEntityBuffers(0),
m_cBytesBuffered(0),
m_cMinBufferLimit(0),
m_pszOriginalHostHeader(NULL),
m_RequestStatus(FORWARDER_START),
m_pDisconnect(NULL),
m_pszHeaders(NULL),
m_cchHeaders(0),
m_fWebSocketEnabled(FALSE),
m_cContentLength(0),
m_pWebSocket(NULL),
m_pApplication(NULL),
m_pAppOfflineHtm(NULL),
m_fErrorHandled(FALSE),
m_fWebSocketUpgrade(FALSE),
m_fFinishRequest(FALSE),
m_fClientDisconnected(FALSE)
{
InitializeSRWLock(&m_RequestLock);
}
@ -95,6 +99,10 @@ FORWARDING_HANDLER::~FORWARDING_HANDLER(
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);
m_hRequest = NULL;
}
@ -105,7 +113,7 @@ FORWARDING_HANDLER::~FORWARDING_HANDLER(
m_pApplication = NULL;
}
if( m_pAppOfflineHtm != NULL )
if(m_pAppOfflineHtm != NULL)
{
m_pAppOfflineHtm->DereferenceAppOfflineHtm();
m_pAppOfflineHtm = NULL;
@ -154,10 +162,10 @@ FORWARDING_HANDLER::DereferenceForwardingHandler(
VOID
) const
{
DBG_ASSERT(m_cRefs != 0 );
DBG_ASSERT(m_cRefs != 0);
LONG cRefs = 0;
if ( (cRefs = InterlockedDecrement(&m_cRefs) ) == 0)
if ((cRefs = InterlockedDecrement(&m_cRefs)) == 0)
{
delete this;
}
@ -179,8 +187,8 @@ FORWARDING_HANDLER::SetStatusAndHeaders(
HRESULT hr;
IHttpResponse * pResponse = m_pW3Context->GetResponse();
IHttpRequest * pRequest = m_pW3Context->GetRequest();
STACK_STRA ( strHeaderName, 128);
STACK_STRA ( strHeaderValue, 2048);
STACK_STRA(strHeaderName, 128);
STACK_STRA(strHeaderValue, 2048);
DWORD index = 0;
PSTR pchNewline;
PCSTR pchEndofHeaderValue;
@ -341,7 +349,7 @@ FORWARDING_HANDLER::SetStatusAndHeaders(
//
// Copy the header value
//
if (pchEndofHeaderValue == pszHeaders+index)
if (pchEndofHeaderValue == pszHeaders + index)
{
strHeaderValue.Reset();
}
@ -405,7 +413,7 @@ FORWARDING_HANDLER::SetStatusAndHeaders(
// Explicitly remove the Server header if the back-end didn't set one.
//
if ( !fServerHeaderPresent )
if (!fServerHeaderPresent)
{
pResponse->DeleteHeader("Server");
}
@ -525,7 +533,7 @@ SetCookie:
// syntax name=value ; ... ; Domain=.host ; ...
//
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)
{
@ -567,7 +575,7 @@ SetCookie:
pszStartHost++;
}
pszEndHost = pszStartHost;
while(!IsSpace(*pszEndHost) &&
while (!IsSpace(*pszEndHost) &&
*pszEndHost != ';' &&
*pszEndHost != '\0')
{
@ -600,39 +608,45 @@ SetCookie:
HRESULT
FORWARDING_HANDLER::GetHeaders(
const PROTOCOL_CONFIG * pProtocol,
PCWSTR pszDestination,
PCWSTR * ppszHeaders,
DWORD * pcchHeaders,
ASPNETCORE_CONFIG* pAspNetCoreConfig,
SERVER_PROCESS* pServerProcess
)
{
IHttpRequest *pRequest = m_pW3Context->GetRequest();
HRESULT hr = S_OK;
PCSTR pszCurrentHeader;
USHORT cchCurrentHeader;
PCSTR pszFinalHeader;
DWORD cchFinalHeader;
STACK_STRA( strTemp, 64);
HTTP_REQUEST_HEADERS *pHeaders;
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;
//
// 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())
{
STACK_STRA( straTemp, 256 );
if (FAILED(hr = straTemp.CopyW(pszDestination)) ||
if (FAILED(hr = PATH::SplitUrl(pRequest->GetRawHttpRequest()->CookedUrl.pFullUrl,
&fSecure,
&struDestination,
&struUrl)) ||
FAILED(hr = strTemp.CopyW(struDestination.QueryStr())) ||
FAILED(hr = pRequest->SetHeader(HttpHeaderHost,
straTemp.QueryStr(),
static_cast<USHORT>(straTemp.QueryCCH()),
strTemp.QueryStr(),
static_cast<USHORT>(strTemp.QueryCCH()),
TRUE))) // fReplace
{
return hr;
}
}
//
// Strip all headers starting with MS-ASPNETCORE.
@ -641,11 +655,11 @@ FORWARDING_HANDLER::GetHeaders(
//
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)
{
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.
//
while(ppHeadersToBeRemoved != NULL)
while (ppHeadersToBeRemoved != NULL)
{
m_pW3Context->GetRequest()->DeleteHeader( ppHeadersToBeRemoved );
ppHeadersToBeRemoved = mszMsAspNetCoreHeaders.Next( ppHeadersToBeRemoved );
m_pW3Context->GetRequest()->DeleteHeader(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(),
(USHORT)strlen(pServerProcess->QueryGuid()),
TRUE );
if(FAILED(hr))
TRUE);
if (FAILED(hr))
{
return hr;
}
}
if( pAspNetCoreConfig->QueryForwardWindowsAuthToken() &&
if (pAspNetCoreConfig->QueryForwardWindowsAuthToken() &&
(_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 &&
m_pW3Context->GetUser()->GetPrimaryToken() != INVALID_HANDLE_VALUE )
if (m_pW3Context->GetUser()->GetPrimaryToken() != NULL &&
m_pW3Context->GetUser()->GetPrimaryToken() != INVALID_HANDLE_VALUE)
{
HANDLE hTargetTokenHandle = NULL;
hr = pServerProcess->SetWindowsAuthToken( m_pW3Context->GetUser()->GetPrimaryToken(),
&hTargetTokenHandle );
if(FAILED(hr))
hr = pServerProcess->SetWindowsAuthToken(m_pW3Context->GetUser()->GetPrimaryToken(),
&hTargetTokenHandle);
if (FAILED(hr))
{
return hr;
}
@ -691,18 +705,18 @@ FORWARDING_HANDLER::GetHeaders(
//
// set request header with target token value
//
CHAR pszHandleStr[16] = {0};
if(_ui64toa_s( (UINT64) hTargetTokenHandle, pszHandleStr, 16, 16 ) != 0)
CHAR pszHandleStr[16] = { 0 };
if (_ui64toa_s((UINT64)hTargetTokenHandle, pszHandleStr, 16, 16) != 0)
{
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
return hr;
}
hr = m_pW3Context->GetRequest()->SetHeader( "MS-ASPNETCORE-WINAUTHTOKEN",
hr = m_pW3Context->GetRequest()->SetHeader("MS-ASPNETCORE-WINAUTHTOKEN",
pszHandleStr,
(USHORT)strlen(pszHandleStr),
TRUE );
if(FAILED(hr))
TRUE);
if (FAILED(hr))
{
return hr;
}
@ -793,14 +807,14 @@ FORWARDING_HANDLER::GetHeaders(
}
}
if(FAILED(hr = strTemp.Append(pszScheme)))
if (FAILED(hr = strTemp.Append(pszScheme)))
{
return hr;
}
if(FAILED(pRequest->SetHeader(pProtocol->QuerySslHeaderName()->QueryStr(),
if (FAILED(pRequest->SetHeader(pProtocol->QuerySslHeaderName()->QueryStr(),
strTemp.QueryStr(),
(USHORT) strTemp.QueryCCH(),
(USHORT)strTemp.QueryCCH(),
TRUE)))
{
return hr;
@ -816,8 +830,9 @@ FORWARDING_HANDLER::GetHeaders(
}
else
{
// Resize the buffer large enough to hold the encoded certificate info
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;
}
@ -869,7 +884,6 @@ FORWARDING_HANDLER::CreateWinHttpRequest(
__in const PROTOCOL_CONFIG * pProtocol,
__in HINTERNET hConnect,
__inout STRU * pstrUrl,
const STRU& strDestination,
ASPNETCORE_CONFIG* pAspNetCoreConfig,
SERVER_PROCESS* pServerProcess
)
@ -877,7 +891,7 @@ FORWARDING_HANDLER::CreateWinHttpRequest(
HRESULT hr = S_OK;
PCWSTR pszVersion = NULL;
PCSTR pszVerb;
STACK_STRU( strVerb, 32 );
STACK_STRU(strVerb, 32);
//
// Create the request handle for this request (leave some fields blank,
@ -910,7 +924,7 @@ FORWARDING_HANDLER::CreateWinHttpRequest(
WINHTTP_NO_REFERER,
WINHTTP_DEFAULT_ACCEPT_TYPES,
WINHTTP_FLAG_ESCAPE_DISABLE_QUERY
| g_OptionalWinHttpFlags );
| g_OptionalWinHttpFlags);
if (m_hRequest == NULL)
{
hr = HRESULT_FROM_WIN32(GetLastError());
@ -964,8 +978,18 @@ FORWARDING_HANDLER::CreateWinHttpRequest(
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,
strDestination.QueryStr(),
&m_pszHeaders,
&m_cchHeaders,
pAspNetCoreConfig,
@ -982,7 +1006,7 @@ Finished:
REQUEST_NOTIFICATION_STATUS
FORWARDING_HANDLER::OnExecuteRequestHandler(
VOID
VOID
)
{
REQUEST_NOTIFICATION_STATUS retVal = RQ_NOTIFICATION_CONTINUE;
@ -990,10 +1014,10 @@ VOID
bool fRequestLocked = FALSE;
ASPNETCORE_CONFIG *pAspNetCoreConfig = NULL;
FORWARDER_CONNECTION *pConnection = NULL;
STACK_STRU( strDestination, 32);
STACK_STRU( strUrl, 2048);
STACK_STRU( struEscapedUrl, 2048);
STACK_STRU( strDescription, 128);
STACK_STRU(strDestination, 32);
STACK_STRU(strUrl, 2048);
STACK_STRU(struEscapedUrl, 2048);
STACK_STRU(strDescription, 128);
HINTERNET hConnect = NULL;
IHttpRequest *pRequest = m_pW3Context->GetRequest();
IHttpResponse *pResponse = m_pW3Context->GetResponse();
@ -1065,8 +1089,8 @@ VOID
goto Failure;
}
hr = pApplicationManager->GetApplication( m_pW3Context,
&m_pApplication );
hr = pApplicationManager->GetApplication(m_pW3Context,
&m_pApplication);
if (FAILED(hr))
{
goto Failure;
@ -1136,7 +1160,7 @@ VOID
goto Finished;
}
hr = m_pApplication->GetProcess( m_pW3Context,
hr = m_pApplication->GetProcess(m_pW3Context,
pAspNetCoreConfig,
&pServerProcess);
if (FAILED(hr))
@ -1178,7 +1202,6 @@ VOID
pProtocol,
hConnect,
&struEscapedUrl,
strDestination,
pAspNetCoreConfig,
pServerProcess);
@ -1443,7 +1466,7 @@ Finished:
pConnection = NULL;
}
if( pServerProcess != NULL )
if (pServerProcess != NULL)
{
pServerProcess->DereferenceServerProcess();
pServerProcess = NULL;
@ -1494,17 +1517,17 @@ FORWARDING_HANDLER::OnAsyncCompletion(
Routine Description:
Handle the completion from IIS and continue the execution
of this request based on the current state.
Handle the completion from IIS and continue the execution
of this request based on the current state.
Arguments:
cbCompletion - Number of bytes associated with this completion
dwCompletionStatus - the win32 status associated with this completion
cbCompletion - Number of bytes associated with this completion
dwCompletionStatus - the win32 status associated with this completion
Return Value:
REQUEST_NOTIFICATION_STATUS
REQUEST_NOTIFICATION_STATUS
--*/
{
@ -1512,17 +1535,16 @@ Return Value:
REQUEST_NOTIFICATION_STATUS retVal = RQ_NOTIFICATION_CONTINUE;
BOOL fLocked = FALSE;
bool fClientError = FALSE;
DBG_ASSERT(m_pW3Context != NULL);
__analysis_assume(m_pW3Context != NULL);
BOOL fClosed = FALSE;
if ( sm_pTraceLog != NULL )
if (sm_pTraceLog != NULL)
{
WriteRefTraceLogEx( sm_pTraceLog,
WriteRefTraceLogEx(sm_pTraceLog,
m_cRefs,
this,
"FORWARDING_HANDLER::OnAsyncCompletion Enter",
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();
DBG_ASSERT(m_pW3Context != NULL);
__analysis_assume(m_pW3Context != NULL);
//
// OnAsyncCompletion can be called on a Winhttp io completion thread.
// 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_RequestStatus == FORWARDER_DONE)
if (m_RequestStatus == FORWARDER_DONE && m_fFinishRequest)
{
retVal = RQ_NOTIFICATION_FINISH_REQUEST;
goto Finished;
@ -1584,10 +1609,22 @@ Return Value:
//
// WebSocket upgrade is successful. Close the WinHttpRequest Handle
//
WinHttpCloseHandle(m_hRequest);
WinHttpSetStatusCallback(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;
}
else
{
hr = HRESULT_FROM_WIN32(GetLastError());
goto Failure;
}
retVal = RQ_NOTIFICATION_PENDING;
goto Finished;
}
@ -1662,6 +1699,13 @@ Failure:
IHttpResponse *pResponse = m_pW3Context->GetResponse();
pResponse->DisableKernelCache();
pResponse->GetRawHttpResponse()->EntityChunkCount = 0;
// double check to set right status code
if (!m_pW3Context->GetConnection()->IsConnected())
{
fClientError = TRUE;
}
if (fClientError)
{
if (!m_fResponseHeadersReceivedAndSet)
@ -1679,14 +1723,14 @@ Failure:
}
else
{
STACK_STRU( strDescription, 128);
STACK_STRU(strDescription, 128);
pResponse->SetStatus(502, "Bad Gateway", 3, hr);
if (hr > HRESULT_FROM_WIN32(WINHTTP_ERROR_BASE) &&
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(
FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_HMODULE,
g_hWinHttpModule,
@ -1703,7 +1747,7 @@ Failure:
strDescription.QueryStr(),
strDescription.QuerySizeCCH());
}
(VOID) strDescription.SyncWithBuffer();
(VOID)strDescription.SyncWithBuffer();
if (strDescription.QueryCCH() != 0)
{
pResponse->SetErrorDescription(
@ -1712,7 +1756,7 @@ Failure:
FALSE);
}
if( hr == HRESULT_FROM_WIN32(ERROR_WINHTTP_INVALID_SERVER_RESPONSE))
if (hr == HRESULT_FROM_WIN32(ERROR_WINHTTP_INVALID_SERVER_RESPONSE))
{
pResponse->ResetConnection();
goto Finished;
@ -1832,8 +1876,8 @@ FORWARDING_HANDLER::OnSendingRequest(
m_pEntityBuffer[4] = '\r';
m_pEntityBuffer[5] = '\n';
m_pEntityBuffer[cbCompletion+6] = '\r';
m_pEntityBuffer[cbCompletion+7] = '\n';
m_pEntityBuffer[cbCompletion + 6] = '\r';
m_pEntityBuffer[cbCompletion + 7] = '\n';
if (cbCompletion < 0x10)
{
@ -1918,7 +1962,7 @@ FORWARDING_HANDLER::OnReceivingResponse(
// buffering
//
m_BytesToSend = min(m_cMinBufferLimit, BUFFER_SIZE);
if (m_BytesToSend < BUFFER_SIZE/2)
if (m_BytesToSend < BUFFER_SIZE / 2)
{
//
// Disable buffering.
@ -1986,10 +2030,10 @@ Failure:
VOID
FORWARDING_HANDLER::OnWinHttpCompletionInternal(
HINTERNET hRequest,
DWORD dwInternetStatus,
LPVOID lpvStatusInformation,
DWORD dwStatusInformationLength
HINTERNET hRequest,
DWORD dwInternetStatus,
LPVOID lpvStatusInformation,
DWORD dwStatusInformationLength
)
/*++
@ -2018,6 +2062,7 @@ None
__analysis_assume(m_pW3Context != NULL);
IHttpResponse * pResponse = m_pW3Context->GetResponse();
BOOL fDerefForwardingHandler = TRUE;
BOOL fEndRequest = FALSE;
UNREFERENCED_PARAMETER(dwStatusInformationLength);
@ -2032,14 +2077,69 @@ None
}
//
// If the request is upgraded to websocket, route the completion
// to the websocket handler. We don't need to take the request lock,
// since for websocket request, the parent request handle is already
// closed.
// 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);
}
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)
{
fDerefForwardingHandler = FALSE;
fAnotherCompletionExpected = TRUE;
if(m_pWebSocket == NULL)
{
goto Finished;
}
switch (dwInternetStatus)
{
case WINHTTP_CALLBACK_STATUS_SHUTDOWN_COMPLETE:
@ -2064,46 +2164,10 @@ None
);
break;
}
fDerefForwardingHandler = FALSE;
fAnotherCompletionExpected = TRUE;
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)
{
@ -2154,6 +2218,21 @@ None
fDerefForwardingHandler = FALSE;
fAnotherCompletionExpected = TRUE;
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:
hr = ERROR_CONNECTION_ABORTED;
break;
@ -2190,17 +2269,20 @@ None
goto Finished;
Failure:
m_RequestStatus = FORWARDER_DONE;
if (!m_fErrorHandled)
{
m_fErrorHandled = TRUE;
if (hr == HRESULT_FROM_WIN32(ERROR_WINHTTP_INVALID_SERVER_RESPONSE))
{
m_RequestStatus = FORWARDER_RESET_CONNECTION;
goto Finished;
}
m_RequestStatus = FORWARDER_DONE;
pResponse->DisableKernelCache();
pResponse->GetRawHttpResponse()->EntityChunkCount = 0;
fClientError = !m_pW3Context->GetConnection()->IsConnected();
if (fClientError)
{
if (!m_fResponseHeadersReceivedAndSet)
@ -2251,8 +2333,10 @@ Failure:
FALSE);
}
}
}
Finished:
if (fIsCompletionThread)
{
DBG_ASSERT(TlsGetValue(g_dwTlsIndex) == this);
@ -2275,14 +2359,45 @@ Finished:
// 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
// IndicateCompletion to allow cleaning up the TLS before thread reuse.
//
m_pW3Context->PostCompletion(0);
//
// No code executed after posting the completion.
//
@ -2292,7 +2407,7 @@ Finished:
HRESULT
FORWARDING_HANDLER::OnWinHttpCompletionSendRequestOrWriteComplete(
HINTERNET hRequest,
DWORD ,
DWORD,
__out bool * pfClientError,
__out bool * pfAnotherCompletionExpected
)
@ -2414,8 +2529,8 @@ FORWARDING_HANDLER::OnWinHttpCompletionStatusHeadersAvailable(
)
{
HRESULT hr = S_OK;
STACK_BUFFER( bufHeaderBuffer, 2048);
STACK_STRA( strHeaders, 2048);
STACK_BUFFER(bufHeaderBuffer, 2048);
STACK_STRA(strHeaders, 2048);
DWORD dwHeaderSize = bufHeaderBuffer.QuerySize();
UNREFERENCED_PARAMETER(pfAnotherCompletionExpected);
@ -2471,10 +2586,10 @@ FORWARDING_HANDLER::OnWinHttpCompletionStatusHeadersAvailable(
// 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" );
if ( FAILED( hr ) )
hr = strHeaders.Append("\r\n");
if (FAILED(hr))
{
goto Finished;
}
@ -2596,7 +2711,7 @@ FORWARDING_HANDLER::OnWinHttpCompletionStatusReadComplete(
//
m_BytesToSend -= dwStatusInformationLength;
if (m_cMinBufferLimit >= BUFFER_SIZE/2)
if (m_cMinBufferLimit >= BUFFER_SIZE / 2)
{
if (m_cContentLength != 0)
{
@ -2676,15 +2791,15 @@ FORWARDING_HANDLER::StaticInitialize(
Routine Description:
Global initialization routine for FORWARDING_HANDLERs
Global initialization routine for FORWARDING_HANDLERs
Arguments:
fEnableReferenceCountTracing - True if ref count tracing should be use.
fEnableReferenceCountTracing - True if ref count tracing should be use.
Return Value:
HRESULT
HRESULT
--*/
{
@ -2730,8 +2845,8 @@ Return Value:
//
if (WinHttpSetStatusCallback(sm_hSession,
FORWARDING_HANDLER::OnWinHttpCompletion,
( WINHTTP_CALLBACK_FLAG_ALL_COMPLETIONS |
WINHTTP_CALLBACK_STATUS_SENDING_REQUEST ),
(WINHTTP_CALLBACK_FLAG_ALL_COMPLETIONS |
WINHTTP_CALLBACK_STATUS_SENDING_REQUEST),
NULL) == WINHTTP_INVALID_STATUS_CALLBACK)
{
hr = HRESULT_FROM_WIN32(GetLastError());
@ -2754,14 +2869,14 @@ Return Value:
// Initialize Application Manager
APPLICATION_MANAGER *pApplicationManager = APPLICATION_MANAGER::GetInstance();
if(pApplicationManager == NULL)
if (pApplicationManager == NULL)
{
hr = E_OUTOFMEMORY;
goto Failure;
}
hr = pApplicationManager->Initialize();
if(FAILED(hr))
if (FAILED(hr))
{
goto Failure;
}
@ -2803,9 +2918,9 @@ Return Value:
goto Failure;
}
if ( fEnableReferenceCountTracing )
if (fEnableReferenceCountTracing)
{
sm_pTraceLog = CreateRefTraceLog( 10000, 0 );
sm_pTraceLog = CreateRefTraceLog(10000, 0);
}
return S_OK;
@ -2826,15 +2941,15 @@ FORWARDING_HANDLER::StaticTerminate(
Routine Description:
Global termination routine for FORWARDING_HANDLERs
Global termination routine for FORWARDING_HANDLERs
Arguments:
None
None
Return Value:
None
None
--*/
{
@ -2851,9 +2966,9 @@ Return Value:
DWORD tickCount = GetTickCount();
while( g_dwActiveServerProcesses > 0 )
while (g_dwActiveServerProcesses > 0)
{
if( (GetTickCount() - tickCount) > 10000 )
if ((GetTickCount() - tickCount) > 10000)
{
break;
}
@ -2905,7 +3020,7 @@ CopyMultiSzToOutput(
PCWSTR pszListCopy = pszList;
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;
}
cbData += sizeof(WCHAR);
@ -2943,13 +3058,27 @@ FORWARDING_HANDLER::TerminateRequest(
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)
{
WinHttpCloseHandle(m_hRequest);
WinHttpSetStatusCallback(m_hRequest,
FORWARDING_HANDLER::OnWinHttpCompletion,
WINHTTP_CALLBACK_FLAG_HANDLES,
NULL);
if (WinHttpCloseHandle(m_hRequest))
{
m_hRequest = NULL;
}
m_fHandleClosedDueToClient = fClientInitiated;
}
@ -2962,7 +3091,13 @@ FORWARDING_HANDLER::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 *
@ -2970,10 +3105,10 @@ FORWARDING_HANDLER::GetNewResponseBuffer(
DWORD dwBufferSize
)
{
DWORD dwNeededSize = (m_cEntityBuffers+1)*sizeof(BYTE *);
DWORD dwNeededSize = (m_cEntityBuffers + 1) * sizeof(BYTE *);
if (dwNeededSize > m_buffEntityBuffers.QuerySize() &&
!m_buffEntityBuffers.Resize(
max(dwNeededSize, m_buffEntityBuffers.QuerySize()*2)))
max(dwNeededSize, m_buffEntityBuffers.QuerySize() * 2)))
{
return NULL;
}
@ -2996,7 +3131,7 @@ VOID
FORWARDING_HANDLER::FreeResponseBuffers()
{
BYTE **pBuffers = m_buffEntityBuffers.QueryPtr();
for (DWORD i=0; i<m_cEntityBuffers; i++)
for (DWORD i = 0; i<m_cEntityBuffers; i++)
{
HeapFree(GetProcessHeap(),
0, // dwFlags

View File

@ -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"

View File

@ -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()

View File

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

View File

@ -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:
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:
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:
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:
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,
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:
if (fLocked)
{
LeaveCriticalSection(&_RequestLock);
}
}