зеркало из https://github.com/Azure/iisnode.git
iisnode events in FREB
This commit is contained in:
Родитель
959005cc67
Коммит
66d9afdf87
|
@ -375,7 +375,7 @@ Error:
|
|||
|
||||
if (ERROR_MORE_DATA != hr)
|
||||
{
|
||||
context->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
|
||||
context->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log( context->GetHttpContext(),
|
||||
L"iisnode failed to parse response status line", WINEVENT_LEVEL_ERROR, context->GetActivityId());
|
||||
}
|
||||
|
||||
|
@ -470,7 +470,7 @@ Error:
|
|||
|
||||
if (ERROR_MORE_DATA != hr)
|
||||
{
|
||||
context->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
|
||||
context->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log( context->GetHttpContext(),
|
||||
L"iisnode failed to parse response body chunk header", WINEVENT_LEVEL_ERROR, context->GetActivityId());
|
||||
|
||||
return hr;
|
||||
|
|
|
@ -57,12 +57,12 @@ HRESULT CNodeApplication::Initialize(PCWSTR scriptName, IHttpContext* context)
|
|||
this->GetApplicationManager(),
|
||||
this));
|
||||
|
||||
this->GetApplicationManager()->GetEventProvider()->Log(L"iisnode initialized a new node.js application", WINEVENT_LEVEL_INFO);
|
||||
this->GetApplicationManager()->GetEventProvider()->Log(context, L"iisnode initialized a new node.js application", WINEVENT_LEVEL_INFO);
|
||||
|
||||
return S_OK;
|
||||
Error:
|
||||
|
||||
this->GetApplicationManager()->GetEventProvider()->Log(L"iisnode failed to initialize a new node.js application", WINEVENT_LEVEL_ERROR);
|
||||
this->GetApplicationManager()->GetEventProvider()->Log(context, L"iisnode failed to initialize a new node.js application", WINEVENT_LEVEL_ERROR);
|
||||
|
||||
this->Cleanup();
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ CNodeApplicationManager::CNodeApplicationManager(IHttpServer* server, HTTP_MODUL
|
|||
: server(server), moduleId(moduleId), applications(NULL), asyncManager(NULL), jobObject(NULL),
|
||||
breakAwayFromJobObject(FALSE), fileWatcher(NULL), initialized(FALSE), eventProvider(NULL),
|
||||
currentDebugPort(0), inspector(NULL), totalRequests(0), controlSignalHandlerThread(NULL),
|
||||
signalPipe(NULL), signalPipeName(NULL), pPipeSecAttr(NULL)
|
||||
signalPipe(NULL), signalPipeName(NULL), pPipeSecAttr(NULL), _fSignalPipeInitialized( FALSE )
|
||||
{
|
||||
InitializeSRWLock(&this->srwlock);
|
||||
}
|
||||
|
@ -90,13 +90,95 @@ CNodeApplicationManager::GetPipeSecurityAttributes(
|
|||
return this->pPipeSecAttr;
|
||||
}
|
||||
|
||||
HRESULT CNodeApplicationManager::InitializeControlPipe()
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
UUID uuid;
|
||||
RPC_WSTR suuid = NULL;
|
||||
|
||||
if( _fSignalPipeInitialized )
|
||||
{
|
||||
return hr;
|
||||
}
|
||||
|
||||
//
|
||||
// generate unique pipe name
|
||||
//
|
||||
|
||||
ErrorIf(RPC_S_OK != UuidCreate(&uuid), ERROR_CAN_NOT_COMPLETE);
|
||||
ErrorIf(RPC_S_OK != UuidToStringW(&uuid, &suuid), ERROR_NOT_ENOUGH_MEMORY);
|
||||
ErrorIf((this->signalPipeName = new WCHAR[1024]) == NULL, ERROR_NOT_ENOUGH_MEMORY);
|
||||
wcscpy(this->signalPipeName, L"\\\\.\\pipe\\");
|
||||
wcscpy(this->signalPipeName + 9, (WCHAR*)suuid);
|
||||
RpcStringFreeW(&suuid);
|
||||
suuid = NULL;
|
||||
|
||||
this->signalPipe = CreateNamedPipeW( this->signalPipeName,
|
||||
PIPE_ACCESS_INBOUND,
|
||||
PIPE_TYPE_MESSAGE | PIPE_WAIT,
|
||||
1,
|
||||
MAX_BUFFER_SIZE,
|
||||
MAX_BUFFER_SIZE,
|
||||
0,
|
||||
GetPipeSecurityAttributes() );
|
||||
|
||||
ErrorIf( this->signalPipe == INVALID_HANDLE_VALUE,
|
||||
HRESULT_FROM_WIN32(ERROR_INVALID_HANDLE) );
|
||||
|
||||
//
|
||||
// start pipe reader thread.
|
||||
//
|
||||
|
||||
this->controlSignalHandlerThread = (HANDLE) _beginthreadex( NULL,
|
||||
0,
|
||||
CNodeApplicationManager::ControlSignalHandler,
|
||||
this,
|
||||
0,
|
||||
NULL);
|
||||
|
||||
ErrorIf((HANDLE)-1L == this->controlSignalHandlerThread, ERROR_NOT_ENOUGH_MEMORY);
|
||||
|
||||
this->GetEventProvider()->Log(L"iisnode initialized control pipe", WINEVENT_LEVEL_INFO);
|
||||
|
||||
_fSignalPipeInitialized = TRUE;
|
||||
|
||||
Error:
|
||||
|
||||
if(suuid != NULL)
|
||||
{
|
||||
RpcStringFreeW(&suuid);
|
||||
suuid = NULL;
|
||||
}
|
||||
|
||||
if( FAILED( hr ) )
|
||||
{
|
||||
if(NULL != this->controlSignalHandlerThread)
|
||||
{
|
||||
CloseHandle(this->controlSignalHandlerThread);
|
||||
this->controlSignalHandlerThread = NULL;
|
||||
}
|
||||
|
||||
if(NULL != this->signalPipe)
|
||||
{
|
||||
CloseHandle(this->signalPipe);
|
||||
this->signalPipe = NULL;
|
||||
}
|
||||
|
||||
if(NULL != this->signalPipeName)
|
||||
{
|
||||
delete[] this->signalPipeName;
|
||||
this->signalPipeName = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
HRESULT CNodeApplicationManager::InitializeCore(IHttpContext* context)
|
||||
{
|
||||
HRESULT hr;
|
||||
BOOL isInJob, createJob;
|
||||
JOBOBJECT_EXTENDED_LIMIT_INFORMATION jobInfo;
|
||||
UUID uuid;
|
||||
RPC_WSTR suuid = NULL;
|
||||
|
||||
ErrorIf(NULL == (this->eventProvider = new CNodeEventProvider()), ERROR_NOT_ENOUGH_MEMORY);
|
||||
CheckError(this->eventProvider->Initialize());
|
||||
|
@ -150,62 +232,19 @@ HRESULT CNodeApplicationManager::InitializeCore(IHttpContext* context)
|
|||
HRESULT_FROM_WIN32(GetLastError()));
|
||||
}
|
||||
|
||||
if(CModuleConfiguration::GetRecycleSignalEnabled(context))
|
||||
if(CModuleConfiguration::GetRecycleSignalEnabled(context) && !_fSignalPipeInitialized)
|
||||
{
|
||||
//
|
||||
// generate unique pipe name
|
||||
//
|
||||
|
||||
ErrorIf(RPC_S_OK != UuidCreate(&uuid), ERROR_CAN_NOT_COMPLETE);
|
||||
ErrorIf(RPC_S_OK != UuidToStringW(&uuid, &suuid), ERROR_NOT_ENOUGH_MEMORY);
|
||||
ErrorIf((this->signalPipeName = new WCHAR[1024]) == NULL, ERROR_NOT_ENOUGH_MEMORY);
|
||||
wcscpy(this->signalPipeName, L"\\\\.\\pipe\\");
|
||||
wcscpy(this->signalPipeName + 9, (WCHAR*)suuid);
|
||||
RpcStringFreeW(&suuid);
|
||||
suuid = NULL;
|
||||
|
||||
this->signalPipe = CreateNamedPipeW( this->signalPipeName,
|
||||
PIPE_ACCESS_INBOUND,
|
||||
PIPE_TYPE_MESSAGE | PIPE_WAIT,
|
||||
1,
|
||||
MAX_BUFFER_SIZE,
|
||||
MAX_BUFFER_SIZE,
|
||||
0,
|
||||
GetPipeSecurityAttributes() );
|
||||
|
||||
ErrorIf( this->signalPipe == INVALID_HANDLE_VALUE,
|
||||
HRESULT_FROM_WIN32(ERROR_INVALID_HANDLE) );
|
||||
|
||||
//
|
||||
// start pipe reader thread.
|
||||
//
|
||||
|
||||
this->controlSignalHandlerThread = (HANDLE) _beginthreadex( NULL,
|
||||
0,
|
||||
CNodeApplicationManager::ControlSignalHandler,
|
||||
this,
|
||||
0,
|
||||
NULL);
|
||||
|
||||
ErrorIf((HANDLE)-1L == this->controlSignalHandlerThread, ERROR_NOT_ENOUGH_MEMORY);
|
||||
|
||||
this->GetEventProvider()->Log(L"iisnode initialized control pipe", WINEVENT_LEVEL_INFO);
|
||||
CheckError(InitializeControlPipe());
|
||||
}
|
||||
|
||||
this->initialized = TRUE;
|
||||
|
||||
this->GetEventProvider()->Log(L"iisnode initialized the application manager", WINEVENT_LEVEL_INFO);
|
||||
this->GetEventProvider()->Log(context, L"iisnode initialized the application manager", WINEVENT_LEVEL_INFO);
|
||||
|
||||
return S_OK;
|
||||
Error:
|
||||
|
||||
this->GetEventProvider()->Log(L"iisnode failed to initialize the application manager", WINEVENT_LEVEL_ERROR);
|
||||
|
||||
if(suuid != NULL)
|
||||
{
|
||||
RpcStringFreeW(&suuid);
|
||||
suuid = NULL;
|
||||
}
|
||||
this->GetEventProvider()->Log(context, L"iisnode failed to initialize the application manager", WINEVENT_LEVEL_ERROR);
|
||||
|
||||
if (NULL != this->asyncManager)
|
||||
{
|
||||
|
@ -230,6 +269,8 @@ Error:
|
|||
|
||||
CNodeApplicationManager::~CNodeApplicationManager()
|
||||
{
|
||||
HANDLE hPipe = NULL;
|
||||
|
||||
while (NULL != this->applications)
|
||||
{
|
||||
delete this->applications->nodeApplication;
|
||||
|
@ -238,6 +279,30 @@ CNodeApplicationManager::~CNodeApplicationManager()
|
|||
delete current;
|
||||
}
|
||||
|
||||
if( _fSignalPipeInitialized )
|
||||
{
|
||||
//
|
||||
// try to connect to the pipe to unblock the thread
|
||||
// waiting on ConnectNamedPipe
|
||||
// We dont need to check any errors on whether the connect
|
||||
// succeeded because we dont care.
|
||||
//
|
||||
|
||||
hPipe = CreateFileW( this->GetSignalPipeName(),
|
||||
GENERIC_WRITE,
|
||||
0,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
0,
|
||||
NULL );
|
||||
|
||||
if(hPipe != NULL)
|
||||
{
|
||||
CloseHandle(hPipe);
|
||||
hPipe = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if(NULL != this->controlSignalHandlerThread)
|
||||
{
|
||||
CloseHandle(this->controlSignalHandlerThread);
|
||||
|
@ -304,7 +369,7 @@ CAsyncManager* CNodeApplicationManager::GetAsyncManager()
|
|||
|
||||
HRESULT CNodeApplicationManager::Dispatch(IHttpContext* context, IHttpEventProvider* pProvider, CNodeHttpStoredContext** ctx)
|
||||
{
|
||||
HRESULT hr;
|
||||
HRESULT hr = S_OK;
|
||||
CNodeApplication* application;
|
||||
NodeDebugCommand debugCommand;
|
||||
|
||||
|
@ -319,6 +384,18 @@ HRESULT CNodeApplicationManager::Dispatch(IHttpContext* context, IHttpEventProvi
|
|||
{
|
||||
default:
|
||||
|
||||
if(CModuleConfiguration::GetRecycleSignalEnabled(context) && !_fSignalPipeInitialized)
|
||||
{
|
||||
ENTER_SRW_EXCLUSIVE(this->srwlock)
|
||||
|
||||
if(CModuleConfiguration::GetRecycleSignalEnabled(context) && !_fSignalPipeInitialized)
|
||||
{
|
||||
CheckError(InitializeControlPipe());
|
||||
}
|
||||
|
||||
LEAVE_SRW_EXCLUSIVE(this->srwlock)
|
||||
}
|
||||
|
||||
ENTER_SRW_SHARED(this->srwlock)
|
||||
|
||||
CheckError(this->GetOrCreateNodeApplication(context, debugCommand, FALSE, &application));
|
||||
|
@ -554,7 +631,7 @@ HRESULT CNodeApplicationManager::GetOrCreateNodeApplicationCore(PCWSTR physicalP
|
|||
}
|
||||
else
|
||||
{
|
||||
this->GetEventProvider()->Log(L"iisnode found an existing node.js application to dispatch the http request to", WINEVENT_LEVEL_VERBOSE);
|
||||
this->GetEventProvider()->Log(context, L"iisnode found an existing node.js application to dispatch the http request to", WINEVENT_LEVEL_VERBOSE);
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
|
@ -569,7 +646,7 @@ Error:
|
|||
delete applicationEntry;
|
||||
}
|
||||
|
||||
this->GetEventProvider()->Log(L"iisnode failed to create a new node.js application", WINEVENT_LEVEL_ERROR);
|
||||
this->GetEventProvider()->Log(context, L"iisnode failed to create a new node.js application", WINEVENT_LEVEL_ERROR);
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
@ -860,7 +937,7 @@ HRESULT CNodeApplicationManager::GetOrCreateDebuggedNodeApplicationCore(PCWSTR p
|
|||
}
|
||||
else
|
||||
{
|
||||
this->GetEventProvider()->Log(L"iisnode found an existing node.js debugger to dispatch the http request to", WINEVENT_LEVEL_VERBOSE);
|
||||
this->GetEventProvider()->Log(context, L"iisnode found an existing node.js debugger to dispatch the http request to", WINEVENT_LEVEL_VERBOSE);
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
|
@ -884,7 +961,7 @@ Error:
|
|||
delete debuggerEntry;
|
||||
}
|
||||
|
||||
this->GetEventProvider()->Log(L"iisnode failed to create a new node.js application to debug or the debugger for that application", WINEVENT_LEVEL_ERROR);
|
||||
this->GetEventProvider()->Log(context, L"iisnode failed to create a new node.js application to debug or the debugger for that application", WINEVENT_LEVEL_ERROR);
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
|
|
@ -40,6 +40,7 @@ private:
|
|||
HMODULE inspector;
|
||||
LONG totalRequests;
|
||||
|
||||
BOOL _fSignalPipeInitialized;
|
||||
HANDLE signalPipe;
|
||||
HANDLE controlSignalHandlerThread;
|
||||
LPWSTR signalPipeName;
|
||||
|
@ -65,7 +66,7 @@ private:
|
|||
HRESULT FindNextDebugPort(IHttpContext* context, DWORD* port);
|
||||
HRESULT EnsureDebugeeReady(IHttpContext* context, DWORD debugPort);
|
||||
HRESULT InitializeCore(IHttpContext* context);
|
||||
|
||||
HRESULT InitializeControlPipe();
|
||||
static unsigned int WINAPI ControlSignalHandler(void* arg);
|
||||
|
||||
public:
|
||||
|
|
|
@ -4,80 +4,115 @@
|
|||
const GUID CNodeEventProvider::providerId = { 0x1040dfc4, 0x61db, 0x484a, { 0x95, 0x30, 0x58, 0x4b, 0x27, 0x35, 0xf7, 0xf7 } };
|
||||
|
||||
CNodeEventProvider::CNodeEventProvider()
|
||||
: handle(0), advapi(NULL), eventRegister(NULL), eventUnregister(NULL), eventWriteString(NULL), eventProviderEnabled(NULL)
|
||||
: handle(0), advapi(NULL), eventRegister(NULL), eventUnregister(NULL), eventWriteString(NULL), eventProviderEnabled(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
CNodeEventProvider::~CNodeEventProvider()
|
||||
{
|
||||
if (this->advapi && this->eventUnregister && this->handle)
|
||||
{
|
||||
this->eventUnregister(this->handle);
|
||||
this->handle = 0;
|
||||
}
|
||||
if (this->advapi && this->eventUnregister && this->handle)
|
||||
{
|
||||
this->eventUnregister(this->handle);
|
||||
this->handle = 0;
|
||||
}
|
||||
|
||||
if (this->advapi)
|
||||
{
|
||||
FreeLibrary(this->advapi);
|
||||
this->advapi = NULL;
|
||||
}
|
||||
if (this->advapi)
|
||||
{
|
||||
FreeLibrary(this->advapi);
|
||||
this->advapi = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT CNodeEventProvider::Initialize()
|
||||
{
|
||||
HRESULT hr;
|
||||
HRESULT hr;
|
||||
|
||||
this->advapi = LoadLibrary("advapi32.dll");
|
||||
this->eventRegister = (EventRegisterFunc)GetProcAddress(this->advapi, "EventRegister");
|
||||
this->eventUnregister = (EventUnregisterFunc)GetProcAddress(this->advapi, "EventUnregister");
|
||||
this->eventWriteString = (EventWriteStringFunc)GetProcAddress(this->advapi, "EventWriteString");
|
||||
this->eventProviderEnabled = (EventProviderEnabledFunc)GetProcAddress(this->advapi, "EventProviderEnabled");
|
||||
this->advapi = LoadLibrary("advapi32.dll");
|
||||
this->eventRegister = (EventRegisterFunc)GetProcAddress(this->advapi, "EventRegister");
|
||||
this->eventUnregister = (EventUnregisterFunc)GetProcAddress(this->advapi, "EventUnregister");
|
||||
this->eventWriteString = (EventWriteStringFunc)GetProcAddress(this->advapi, "EventWriteString");
|
||||
this->eventProviderEnabled = (EventProviderEnabledFunc)GetProcAddress(this->advapi, "EventProviderEnabled");
|
||||
|
||||
if (this->eventRegister)
|
||||
{
|
||||
CheckError(this->eventRegister(&providerId, NULL, NULL, &this->handle));
|
||||
}
|
||||
if (this->eventRegister)
|
||||
{
|
||||
CheckError(this->eventRegister(&providerId, NULL, NULL, &this->handle));
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
return S_OK;
|
||||
Error:
|
||||
|
||||
if (this->advapi)
|
||||
{
|
||||
FreeLibrary(this->advapi);
|
||||
this->advapi = NULL;
|
||||
}
|
||||
if (this->advapi)
|
||||
{
|
||||
FreeLibrary(this->advapi);
|
||||
this->advapi = NULL;
|
||||
}
|
||||
|
||||
return hr;
|
||||
return hr;
|
||||
}
|
||||
|
||||
bool CNodeEventProvider::IsEnabled(UCHAR level)
|
||||
{
|
||||
bool result = this->eventProviderEnabled ? this->eventProviderEnabled(this->handle, level, 0) : false;
|
||||
return result;
|
||||
bool result = this->eventProviderEnabled ? this->eventProviderEnabled(this->handle, level, 0) : false;
|
||||
return result;
|
||||
}
|
||||
|
||||
HRESULT CNodeEventProvider::Log(PCWSTR message, UCHAR level, GUID* activityId)
|
||||
{
|
||||
HRESULT hr;
|
||||
HRESULT hr;
|
||||
|
||||
if (this->eventWriteString && this->IsEnabled(level))
|
||||
{
|
||||
// TODO, tjanczuk, use activityId through EventWrite instead
|
||||
if (activityId)
|
||||
{
|
||||
WCHAR m[256];
|
||||
StringFromGUID2(*activityId, m, 256);
|
||||
wcscat(m, L": ");
|
||||
wcscat(m, message);
|
||||
CheckError(this->eventWriteString(this->handle, level, 0, m));
|
||||
}
|
||||
else
|
||||
{
|
||||
CheckError(this->eventWriteString(this->handle, level, 0, message));
|
||||
}
|
||||
}
|
||||
if (this->eventWriteString && this->IsEnabled(level))
|
||||
{
|
||||
// TODO, tjanczuk, use activityId through EventWrite instead
|
||||
if (activityId)
|
||||
{
|
||||
WCHAR m[256];
|
||||
StringFromGUID2(*activityId, m, 256);
|
||||
wcscat(m, L": ");
|
||||
wcscat(m, message);
|
||||
CheckError(this->eventWriteString(this->handle, level, 0, m));
|
||||
}
|
||||
else
|
||||
{
|
||||
CheckError(this->eventWriteString(this->handle, level, 0, message));
|
||||
}
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
return S_OK;
|
||||
Error:
|
||||
return hr;
|
||||
return hr;
|
||||
}
|
||||
|
||||
HRESULT CNodeEventProvider::Log(IHttpContext *context, PCWSTR message, UCHAR level, GUID* activityId)
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
//
|
||||
// Log to iisnode event provider for backwards compatibility in addition to
|
||||
// logging to the IHttpContext->GetTraceContext()
|
||||
//
|
||||
|
||||
if (this->eventWriteString && this->IsEnabled(level))
|
||||
{
|
||||
if (activityId)
|
||||
{
|
||||
WCHAR m[256];
|
||||
StringFromGUID2(*activityId, m, 256);
|
||||
wcscat(m, L": ");
|
||||
wcscat(m, message);
|
||||
CheckError(this->eventWriteString(this->handle, level, 0, m));
|
||||
}
|
||||
else
|
||||
{
|
||||
CheckError(this->eventWriteString(this->handle, level, 0, message));
|
||||
}
|
||||
}
|
||||
|
||||
if( IsEnabled( context->GetTraceContext(), level ) )
|
||||
{
|
||||
CheckError( RaiseEvent( context->GetTraceContext(), message, level, activityId ) );
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
Error:
|
||||
return hr;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
#ifndef __CNODEEVENTPROVIDER_H__
|
||||
#define __CNODEEVENTPROVIDER_H__
|
||||
|
||||
#include <httpserv.h>
|
||||
#include <httptrace.h>
|
||||
|
||||
typedef ULONG (__stdcall *EventRegisterFunc)(
|
||||
_In_ LPCGUID ProviderId,
|
||||
_In_opt_ PENABLECALLBACK EnableCallback,
|
||||
|
@ -25,27 +28,153 @@ typedef ULONG (__stdcall *EventWriteStringFunc)(
|
|||
__in PCWSTR String
|
||||
);
|
||||
|
||||
//
|
||||
// Start of the new provider class WWWServerTraceProvider,
|
||||
// GUID: {3a2a4e84-4c21-4981-ae10-3fda0d9b0f83}
|
||||
// Description: IIS: WWW Server
|
||||
//
|
||||
|
||||
class WWWServerTraceProvider
|
||||
{
|
||||
public:
|
||||
static
|
||||
LPCGUID
|
||||
GetProviderGuid( VOID )
|
||||
// return GUID for the current event class
|
||||
{
|
||||
static const GUID ProviderGuid =
|
||||
{0x3a2a4e84,0x4c21,0x4981,{0xae,0x10,0x3f,0xda,0x0d,0x9b,0x0f,0x83}};
|
||||
return &ProviderGuid;
|
||||
};
|
||||
enum enumAreaFlags
|
||||
{
|
||||
// IISNODE Events
|
||||
IISNODE = 0x8000
|
||||
};
|
||||
static
|
||||
LPCWSTR
|
||||
TranslateEnumAreaFlagsToString( enum enumAreaFlags EnumValue)
|
||||
{
|
||||
switch( (DWORD) EnumValue )
|
||||
{
|
||||
case 0x8000: return L"IISNODE";
|
||||
}
|
||||
return NULL;
|
||||
};
|
||||
|
||||
static
|
||||
BOOL
|
||||
CheckTracingEnabled(
|
||||
IHttpTraceContext * pHttpTraceContext,
|
||||
enumAreaFlags AreaFlags,
|
||||
DWORD dwVerbosity )
|
||||
{
|
||||
HRESULT hr;
|
||||
HTTP_TRACE_CONFIGURATION TraceConfig;
|
||||
TraceConfig.pProviderGuid = GetProviderGuid();
|
||||
hr = pHttpTraceContext->GetTraceConfiguration( &TraceConfig );
|
||||
if ( FAILED( hr ) || !TraceConfig.fProviderEnabled )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
if ( TraceConfig.dwVerbosity >= dwVerbosity &&
|
||||
( TraceConfig.dwAreas == (DWORD) AreaFlags ||
|
||||
( TraceConfig.dwAreas & (DWORD)AreaFlags ) == (DWORD)AreaFlags ) )
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
};
|
||||
};
|
||||
|
||||
class CNodeEventProvider
|
||||
{
|
||||
private:
|
||||
// {1040DFC4-61DB-484A-9530-584B2735F7F7}
|
||||
static const GUID providerId;
|
||||
// {1040DFC4-61DB-484A-9530-584B2735F7F7}
|
||||
static const GUID providerId;
|
||||
|
||||
REGHANDLE handle;
|
||||
HMODULE advapi;
|
||||
EventRegisterFunc eventRegister;
|
||||
EventUnregisterFunc eventUnregister;
|
||||
EventProviderEnabledFunc eventProviderEnabled;
|
||||
EventWriteStringFunc eventWriteString;
|
||||
REGHANDLE handle;
|
||||
HMODULE advapi;
|
||||
EventRegisterFunc eventRegister;
|
||||
EventUnregisterFunc eventUnregister;
|
||||
EventProviderEnabledFunc eventProviderEnabled;
|
||||
EventWriteStringFunc eventWriteString;
|
||||
|
||||
static
|
||||
HRESULT
|
||||
RaiseEvent(
|
||||
IHttpTraceContext * pHttpTraceContext,
|
||||
PCWSTR message,
|
||||
UCHAR level,
|
||||
GUID* activityId = NULL
|
||||
)
|
||||
//
|
||||
// Raise IISNODE Event
|
||||
//
|
||||
{
|
||||
HTTP_TRACE_EVENT Event;
|
||||
Event.pProviderGuid = WWWServerTraceProvider::GetProviderGuid();
|
||||
Event.dwArea = WWWServerTraceProvider::IISNODE;
|
||||
Event.pAreaGuid = GetAreaGuid();
|
||||
Event.dwEvent = 100;
|
||||
Event.pszEventName = L"IISNODE";
|
||||
Event.dwEventVersion = 1;
|
||||
Event.dwVerbosity = level;
|
||||
Event.cEventItems = 2;
|
||||
Event.pActivityGuid = NULL;
|
||||
Event.pRelatedActivityGuid = NULL;
|
||||
Event.dwTimeStamp = 0;
|
||||
Event.dwFlags = HTTP_TRACE_EVENT_FLAG_STATIC_DESCRIPTIVE_FIELDS;
|
||||
|
||||
// pActivityGuid, pRelatedActivityGuid, Timestamp to be filled in by IIS
|
||||
|
||||
HTTP_TRACE_EVENT_ITEM Items[ 2 ];
|
||||
Items[ 0 ].pszName = L"ActivityId";
|
||||
Items[ 0 ].dwDataType = HTTP_TRACE_TYPE_LPCGUID; // mof type (guid)
|
||||
Items[ 0 ].pbData = (PBYTE) activityId;
|
||||
Items[ 0 ].cbData = 16;
|
||||
Items[ 0 ].pszDataDescription = NULL;
|
||||
Items[ 1 ].pszName = L"Message";
|
||||
Items[ 1 ].dwDataType = HTTP_TRACE_TYPE_LPCWSTR; // mof type (string)
|
||||
Items[ 1 ].pbData = (PBYTE) message;
|
||||
Items[ 1 ].cbData =
|
||||
( Items[ 1 ].pbData == NULL )? 0 : ( sizeof(WCHAR) * (1 + (DWORD) wcslen( (PWSTR) Items[ 1 ].pbData ) ) );
|
||||
Items[ 1 ].pszDataDescription = NULL;
|
||||
Event.pEventItems = Items;
|
||||
pHttpTraceContext->RaiseTraceEvent( &Event );
|
||||
return S_OK;
|
||||
};
|
||||
|
||||
static
|
||||
LPCGUID
|
||||
GetAreaGuid( VOID )
|
||||
// return GUID for the current event class
|
||||
{
|
||||
// {c85d1b99-a120-417d-8ae7-e02a30300dea}
|
||||
static const GUID AreaGuid =
|
||||
{0xc85d1b99,0xa120,0x417d,{0x8a,0xe7,0xe0,0x2a,0x30,0x30,0x0d,0xea}};
|
||||
return &AreaGuid;
|
||||
};
|
||||
|
||||
bool IsEnabled(UCHAR level);
|
||||
|
||||
bool IsEnabled(IHttpTraceContext * pHttpTraceContext, UCHAR level)
|
||||
{
|
||||
return WWWServerTraceProvider::CheckTracingEnabled(
|
||||
pHttpTraceContext,
|
||||
WWWServerTraceProvider::IISNODE,
|
||||
level ); //Verbosity
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
CNodeEventProvider();
|
||||
~CNodeEventProvider();
|
||||
CNodeEventProvider();
|
||||
~CNodeEventProvider();
|
||||
|
||||
HRESULT Initialize();
|
||||
bool IsEnabled(UCHAR level);
|
||||
HRESULT Log(PCWSTR message, UCHAR level, GUID* activityId = NULL);
|
||||
HRESULT Initialize();
|
||||
|
||||
HRESULT Log(PCWSTR message, UCHAR level, GUID* activityId = NULL);
|
||||
HRESULT Log(IHttpContext *context, PCWSTR message, UCHAR level, GUID* activityId = NULL);
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -33,10 +33,10 @@ REQUEST_NOTIFICATION_STATUS CNodeHttpModule::OnExecuteRequestHandler(
|
|||
|
||||
CheckError(this->applicationManager->Initialize(pHttpContext));
|
||||
|
||||
this->applicationManager->GetEventProvider()->Log(L"iisnode received a new http request", WINEVENT_LEVEL_INFO);
|
||||
this->applicationManager->GetEventProvider()->Log(pHttpContext, L"iisnode received a new http request", WINEVENT_LEVEL_INFO);
|
||||
|
||||
CheckError(this->applicationManager->Dispatch(pHttpContext, pProvider, &ctx));
|
||||
this->applicationManager->GetEventProvider()->Log(L"iisnode dispatched new http request", WINEVENT_LEVEL_INFO, ctx->GetActivityId());
|
||||
this->applicationManager->GetEventProvider()->Log(pHttpContext, L"iisnode dispatched new http request", WINEVENT_LEVEL_INFO, ctx->GetActivityId());
|
||||
ASYNC_CONTEXT* async = ctx->GetAsyncContext();
|
||||
async->RunSynchronousContinuations();
|
||||
|
||||
|
@ -53,25 +53,25 @@ REQUEST_NOTIFICATION_STATUS CNodeHttpModule::OnExecuteRequestHandler(
|
|||
switch (result)
|
||||
{
|
||||
default:
|
||||
this->applicationManager->GetEventProvider()->Log(
|
||||
this->applicationManager->GetEventProvider()->Log(pHttpContext,
|
||||
L"iisnode leaves CNodeHttpModule::OnExecuteRequestHandler",
|
||||
WINEVENT_LEVEL_VERBOSE,
|
||||
ctx->GetActivityId());
|
||||
break;
|
||||
case RQ_NOTIFICATION_CONTINUE:
|
||||
this->applicationManager->GetEventProvider()->Log(
|
||||
this->applicationManager->GetEventProvider()->Log(pHttpContext,
|
||||
L"iisnode leaves CNodeHttpModule::OnExecuteRequestHandler with RQ_NOTIFICATION_CONTINUE",
|
||||
WINEVENT_LEVEL_VERBOSE,
|
||||
ctx->GetActivityId());
|
||||
break;
|
||||
case RQ_NOTIFICATION_FINISH_REQUEST:
|
||||
this->applicationManager->GetEventProvider()->Log(
|
||||
this->applicationManager->GetEventProvider()->Log(pHttpContext,
|
||||
L"iisnode leaves CNodeHttpModule::OnExecuteRequestHandler with RQ_NOTIFICATION_FINISH_REQUEST",
|
||||
WINEVENT_LEVEL_VERBOSE,
|
||||
ctx->GetActivityId());
|
||||
break;
|
||||
case RQ_NOTIFICATION_PENDING:
|
||||
this->applicationManager->GetEventProvider()->Log(
|
||||
this->applicationManager->GetEventProvider()->Log(pHttpContext,
|
||||
L"iisnode leaves CNodeHttpModule::OnExecuteRequestHandler with RQ_NOTIFICATION_PENDING",
|
||||
WINEVENT_LEVEL_VERBOSE,
|
||||
ctx->GetActivityId());
|
||||
|
@ -88,11 +88,11 @@ Error:
|
|||
{
|
||||
if (ctx)
|
||||
{
|
||||
log->Log(L"iisnode failed to process a new http request", WINEVENT_LEVEL_INFO, ctx->GetActivityId());
|
||||
log->Log(pHttpContext,L"iisnode failed to process a new http request", WINEVENT_LEVEL_INFO, ctx->GetActivityId());
|
||||
}
|
||||
else
|
||||
{
|
||||
log->Log(L"iisnode failed to process a new http request", WINEVENT_LEVEL_INFO);
|
||||
log->Log(pHttpContext,L"iisnode failed to process a new http request", WINEVENT_LEVEL_INFO);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -108,7 +108,7 @@ Error:
|
|||
{
|
||||
if (log)
|
||||
{
|
||||
log->Log(L"iisnode rejected websocket connection request", WINEVENT_LEVEL_INFO);
|
||||
log->Log(pHttpContext, L"iisnode rejected websocket connection request", WINEVENT_LEVEL_INFO);
|
||||
}
|
||||
CProtocolBridge::SendEmptyResponse(pHttpContext, 501, 0, _T("Not Implemented"), hr);
|
||||
}
|
||||
|
@ -205,7 +205,7 @@ REQUEST_NOTIFICATION_STATUS CNodeHttpModule::OnAsyncCompletion(
|
|||
|
||||
ctx->IncreasePendingAsyncOperationCount();
|
||||
|
||||
this->applicationManager->GetEventProvider()->Log(
|
||||
this->applicationManager->GetEventProvider()->Log(pHttpContext,
|
||||
L"iisnode enters CNodeHttpModule::OnAsyncCompletion callback",
|
||||
WINEVENT_LEVEL_VERBOSE,
|
||||
ctx->GetActivityId());
|
||||
|
@ -240,25 +240,25 @@ REQUEST_NOTIFICATION_STATUS CNodeHttpModule::OnAsyncCompletion(
|
|||
switch (result)
|
||||
{
|
||||
default:
|
||||
this->applicationManager->GetEventProvider()->Log(
|
||||
this->applicationManager->GetEventProvider()->Log(pHttpContext,
|
||||
L"iisnode leaves CNodeHttpModule::OnAsyncCompletion",
|
||||
WINEVENT_LEVEL_VERBOSE,
|
||||
ctx->GetActivityId());
|
||||
break;
|
||||
case RQ_NOTIFICATION_CONTINUE:
|
||||
this->applicationManager->GetEventProvider()->Log(
|
||||
this->applicationManager->GetEventProvider()->Log(pHttpContext,
|
||||
L"iisnode leaves CNodeHttpModule::OnAsyncCompletion with RQ_NOTIFICATION_CONTINUE",
|
||||
WINEVENT_LEVEL_VERBOSE,
|
||||
ctx->GetActivityId());
|
||||
break;
|
||||
case RQ_NOTIFICATION_FINISH_REQUEST:
|
||||
this->applicationManager->GetEventProvider()->Log(
|
||||
this->applicationManager->GetEventProvider()->Log(pHttpContext,
|
||||
L"iisnode leaves CNodeHttpModule::OnAsyncCompletion with RQ_NOTIFICATION_FINISH_REQUEST",
|
||||
WINEVENT_LEVEL_VERBOSE,
|
||||
ctx->GetActivityId());
|
||||
break;
|
||||
case RQ_NOTIFICATION_PENDING:
|
||||
this->applicationManager->GetEventProvider()->Log(
|
||||
this->applicationManager->GetEventProvider()->Log(pHttpContext,
|
||||
L"iisnode leaves CNodeHttpModule::OnAsyncCompletion with RQ_NOTIFICATION_PENDING",
|
||||
WINEVENT_LEVEL_VERBOSE,
|
||||
ctx->GetActivityId());
|
||||
|
|
|
@ -1,461 +1,461 @@
|
|||
#include "precomp.h"
|
||||
|
||||
CNodeHttpStoredContext::CNodeHttpStoredContext(CNodeApplication* nodeApplication, CNodeEventProvider* eventProvider, IHttpContext* context)
|
||||
: nodeApplication(nodeApplication), context(context), process(NULL), buffer(NULL), bufferSize(0), dataSize(0), parsingOffset(0),
|
||||
chunkLength(0), chunkTransmitted(0), isChunked(FALSE), pipe(INVALID_HANDLE_VALUE), result(S_OK), isLastChunk(FALSE),
|
||||
requestNotificationStatus(RQ_NOTIFICATION_PENDING), connectionRetryCount(0), pendingAsyncOperationCount(1),
|
||||
targetUrl(NULL), targetUrlLength(0), childContext(NULL), isConnectionFromPool(FALSE), expectResponseBody(TRUE),
|
||||
closeConnection(FALSE), isUpgrade(FALSE), upgradeContext(NULL), opaqueFlagSet(FALSE), requestPumpStarted(FALSE),
|
||||
responseChunkBufferSize(0)
|
||||
: nodeApplication(nodeApplication), context(context), process(NULL), buffer(NULL), bufferSize(0), dataSize(0), parsingOffset(0),
|
||||
chunkLength(0), chunkTransmitted(0), isChunked(FALSE), pipe(INVALID_HANDLE_VALUE), result(S_OK), isLastChunk(FALSE),
|
||||
requestNotificationStatus(RQ_NOTIFICATION_PENDING), connectionRetryCount(0), pendingAsyncOperationCount(1),
|
||||
targetUrl(NULL), targetUrlLength(0), childContext(NULL), isConnectionFromPool(FALSE), expectResponseBody(TRUE),
|
||||
closeConnection(FALSE), isUpgrade(FALSE), upgradeContext(NULL), opaqueFlagSet(FALSE), requestPumpStarted(FALSE),
|
||||
responseChunkBufferSize(0)
|
||||
{
|
||||
IHttpTraceContext* tctx;
|
||||
LPCGUID pguid;
|
||||
IHttpTraceContext* tctx;
|
||||
LPCGUID pguid;
|
||||
|
||||
this->responseChunk.DataChunkType = HttpDataChunkFromMemory;
|
||||
this->responseChunk.FromMemory.pBuffer = NULL;
|
||||
this->responseChunk.DataChunkType = HttpDataChunkFromMemory;
|
||||
this->responseChunk.FromMemory.pBuffer = NULL;
|
||||
|
||||
RtlZeroMemory(&this->asyncContext, sizeof(ASYNC_CONTEXT));
|
||||
CoCreateGuid(&this->activityId);
|
||||
|
||||
this->asyncContext.data = this;
|
||||
this->eventProvider = eventProvider;
|
||||
RtlZeroMemory(&this->asyncContext, sizeof(ASYNC_CONTEXT));
|
||||
CoCreateGuid(&this->activityId);
|
||||
|
||||
this->asyncContext.data = this;
|
||||
this->eventProvider = eventProvider;
|
||||
}
|
||||
|
||||
CNodeHttpStoredContext::~CNodeHttpStoredContext()
|
||||
{
|
||||
if (NULL != this->upgradeContext)
|
||||
{
|
||||
delete this->upgradeContext;
|
||||
this->upgradeContext = NULL;
|
||||
}
|
||||
else if (INVALID_HANDLE_VALUE != this->pipe)
|
||||
{
|
||||
CloseHandle(this->pipe);
|
||||
this->pipe = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
if (NULL != this->upgradeContext)
|
||||
{
|
||||
delete this->upgradeContext;
|
||||
this->upgradeContext = NULL;
|
||||
}
|
||||
else if (INVALID_HANDLE_VALUE != this->pipe)
|
||||
{
|
||||
CloseHandle(this->pipe);
|
||||
this->pipe = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
if (this->responseChunk.FromMemory.pBuffer) {
|
||||
free(this->responseChunk.FromMemory.pBuffer);
|
||||
this->responseChunk.FromMemory.pBuffer = NULL;
|
||||
responseChunkBufferSize = 0;
|
||||
}
|
||||
if (this->responseChunk.FromMemory.pBuffer) {
|
||||
free(this->responseChunk.FromMemory.pBuffer);
|
||||
this->responseChunk.FromMemory.pBuffer = NULL;
|
||||
responseChunkBufferSize = 0;
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT CNodeHttpStoredContext::EnsureResponseChunk(DWORD size, HTTP_DATA_CHUNK** chunk)
|
||||
{
|
||||
HRESULT hr;
|
||||
HRESULT hr;
|
||||
|
||||
if (size > this->responseChunkBufferSize)
|
||||
{
|
||||
if (this->responseChunk.FromMemory.pBuffer)
|
||||
{
|
||||
free(this->responseChunk.FromMemory.pBuffer);
|
||||
this->responseChunk.FromMemory.pBuffer = NULL;
|
||||
this->responseChunkBufferSize = 0;
|
||||
}
|
||||
if (size > this->responseChunkBufferSize)
|
||||
{
|
||||
if (this->responseChunk.FromMemory.pBuffer)
|
||||
{
|
||||
free(this->responseChunk.FromMemory.pBuffer);
|
||||
this->responseChunk.FromMemory.pBuffer = NULL;
|
||||
this->responseChunkBufferSize = 0;
|
||||
}
|
||||
|
||||
ErrorIf(NULL == (this->responseChunk.FromMemory.pBuffer = malloc(size)), ERROR_NOT_ENOUGH_MEMORY);
|
||||
this->responseChunkBufferSize = size;
|
||||
}
|
||||
ErrorIf(NULL == (this->responseChunk.FromMemory.pBuffer = malloc(size)), ERROR_NOT_ENOUGH_MEMORY);
|
||||
this->responseChunkBufferSize = size;
|
||||
}
|
||||
|
||||
*chunk = &this->responseChunk;
|
||||
*chunk = &this->responseChunk;
|
||||
|
||||
return S_OK;
|
||||
return S_OK;
|
||||
Error:
|
||||
return hr;
|
||||
return hr;
|
||||
}
|
||||
|
||||
IHttpContext* CNodeHttpStoredContext::GetHttpContext()
|
||||
{
|
||||
return this->context;
|
||||
return this->context;
|
||||
}
|
||||
|
||||
CNodeApplication* CNodeHttpStoredContext::GetNodeApplication()
|
||||
{
|
||||
return this->nodeApplication;
|
||||
return this->nodeApplication;
|
||||
}
|
||||
|
||||
void CNodeHttpStoredContext::SetNextProcessor(LPOVERLAPPED_COMPLETION_ROUTINE processor)
|
||||
{
|
||||
this->asyncContext.completionProcessor = processor;
|
||||
this->SetContinueSynchronously(FALSE);
|
||||
this->asyncContext.completionProcessor = processor;
|
||||
this->SetContinueSynchronously(FALSE);
|
||||
}
|
||||
|
||||
LPOVERLAPPED CNodeHttpStoredContext::GetOverlapped()
|
||||
{
|
||||
return &this->asyncContext.overlapped;
|
||||
return &this->asyncContext.overlapped;
|
||||
}
|
||||
|
||||
LPOVERLAPPED CNodeHttpStoredContext::InitializeOverlapped()
|
||||
{
|
||||
RtlZeroMemory(&this->asyncContext.overlapped, sizeof(OVERLAPPED));
|
||||
RtlZeroMemory(&this->asyncContext.overlapped, sizeof(OVERLAPPED));
|
||||
|
||||
return &this->asyncContext.overlapped;
|
||||
return &this->asyncContext.overlapped;
|
||||
}
|
||||
|
||||
void CNodeHttpStoredContext::CleanupStoredContext()
|
||||
{
|
||||
delete this;
|
||||
delete this;
|
||||
}
|
||||
|
||||
CNodeProcess* CNodeHttpStoredContext::GetNodeProcess()
|
||||
{
|
||||
return this->process;
|
||||
return this->process;
|
||||
}
|
||||
|
||||
void CNodeHttpStoredContext::SetNodeProcess(CNodeProcess* process)
|
||||
{
|
||||
this->process = process;
|
||||
this->process = process;
|
||||
}
|
||||
|
||||
ASYNC_CONTEXT* CNodeHttpStoredContext::GetAsyncContext()
|
||||
{
|
||||
return &this->asyncContext;
|
||||
return &this->asyncContext;
|
||||
}
|
||||
|
||||
CNodeHttpStoredContext* CNodeHttpStoredContext::Get(LPOVERLAPPED overlapped)
|
||||
{
|
||||
return overlapped == NULL ? NULL : (CNodeHttpStoredContext*)((ASYNC_CONTEXT*)overlapped)->data;
|
||||
return overlapped == NULL ? NULL : (CNodeHttpStoredContext*)((ASYNC_CONTEXT*)overlapped)->data;
|
||||
}
|
||||
|
||||
HANDLE CNodeHttpStoredContext::GetPipe()
|
||||
{
|
||||
return this->pipe;
|
||||
return this->pipe;
|
||||
}
|
||||
|
||||
void CNodeHttpStoredContext::SetPipe(HANDLE pipe)
|
||||
{
|
||||
this->pipe = pipe;
|
||||
if (NULL != this->upgradeContext)
|
||||
{
|
||||
this->upgradeContext->SetPipe(pipe);
|
||||
}
|
||||
this->pipe = pipe;
|
||||
if (NULL != this->upgradeContext)
|
||||
{
|
||||
this->upgradeContext->SetPipe(pipe);
|
||||
}
|
||||
}
|
||||
|
||||
DWORD CNodeHttpStoredContext::GetConnectionRetryCount()
|
||||
{
|
||||
return this->connectionRetryCount;
|
||||
return this->connectionRetryCount;
|
||||
}
|
||||
|
||||
void CNodeHttpStoredContext::SetConnectionRetryCount(DWORD count)
|
||||
{
|
||||
this->connectionRetryCount = count;
|
||||
this->connectionRetryCount = count;
|
||||
}
|
||||
|
||||
void* CNodeHttpStoredContext::GetBuffer()
|
||||
{
|
||||
return this->buffer;
|
||||
return this->buffer;
|
||||
}
|
||||
|
||||
DWORD CNodeHttpStoredContext::GetBufferSize()
|
||||
{
|
||||
return this->bufferSize;
|
||||
return this->bufferSize;
|
||||
}
|
||||
|
||||
void* CNodeHttpStoredContext::GetChunkBuffer()
|
||||
{
|
||||
// leave room in the allocated memory buffer for a chunk transfer encoding header that
|
||||
// will be calculated only after the entity body chunk had been read
|
||||
// leave room in the allocated memory buffer for a chunk transfer encoding header that
|
||||
// will be calculated only after the entity body chunk had been read
|
||||
|
||||
return (void*)((char*)this->GetBuffer() + this->GetChunkHeaderMaxSize());
|
||||
return (void*)((char*)this->GetBuffer() + this->GetChunkHeaderMaxSize());
|
||||
}
|
||||
|
||||
DWORD CNodeHttpStoredContext::GetChunkBufferSize()
|
||||
{
|
||||
// leave room in the buffer for the chunk header and the CRLF following a chunk
|
||||
// leave room in the buffer for the chunk header and the CRLF following a chunk
|
||||
|
||||
return this->GetBufferSize() - this->GetChunkHeaderMaxSize() - 2;
|
||||
return this->GetBufferSize() - this->GetChunkHeaderMaxSize() - 2;
|
||||
}
|
||||
|
||||
DWORD CNodeHttpStoredContext::GetChunkHeaderMaxSize()
|
||||
{
|
||||
// the maximum size of the chunk header
|
||||
// the maximum size of the chunk header
|
||||
|
||||
return 64;
|
||||
return 64;
|
||||
}
|
||||
|
||||
void** CNodeHttpStoredContext::GetBufferRef()
|
||||
{
|
||||
return &this->buffer;
|
||||
return &this->buffer;
|
||||
}
|
||||
|
||||
DWORD* CNodeHttpStoredContext::GetBufferSizeRef()
|
||||
{
|
||||
return &this->bufferSize;
|
||||
return &this->bufferSize;
|
||||
}
|
||||
|
||||
void CNodeHttpStoredContext::SetBuffer(void* buffer)
|
||||
{
|
||||
this->buffer = buffer;
|
||||
this->buffer = buffer;
|
||||
}
|
||||
|
||||
void CNodeHttpStoredContext::SetBufferSize(DWORD bufferSize)
|
||||
{
|
||||
this->bufferSize = bufferSize;
|
||||
this->bufferSize = bufferSize;
|
||||
}
|
||||
|
||||
DWORD CNodeHttpStoredContext::GetDataSize()
|
||||
{
|
||||
return this->dataSize;
|
||||
return this->dataSize;
|
||||
}
|
||||
|
||||
DWORD CNodeHttpStoredContext::GetParsingOffset()
|
||||
{
|
||||
return this->parsingOffset;
|
||||
return this->parsingOffset;
|
||||
}
|
||||
|
||||
void CNodeHttpStoredContext::SetDataSize(DWORD dataSize)
|
||||
{
|
||||
this->dataSize = dataSize;
|
||||
this->dataSize = dataSize;
|
||||
}
|
||||
|
||||
void CNodeHttpStoredContext::SetParsingOffset(DWORD parsingOffset)
|
||||
{
|
||||
this->parsingOffset = parsingOffset;
|
||||
this->parsingOffset = parsingOffset;
|
||||
}
|
||||
|
||||
LONGLONG CNodeHttpStoredContext::GetChunkTransmitted()
|
||||
{
|
||||
return this->chunkTransmitted;
|
||||
return this->chunkTransmitted;
|
||||
}
|
||||
|
||||
LONGLONG CNodeHttpStoredContext::GetChunkLength()
|
||||
{
|
||||
return this->chunkLength;
|
||||
return this->chunkLength;
|
||||
}
|
||||
|
||||
void CNodeHttpStoredContext::SetChunkTransmitted(LONGLONG length)
|
||||
{
|
||||
this->chunkTransmitted = length;
|
||||
this->chunkTransmitted = length;
|
||||
}
|
||||
|
||||
void CNodeHttpStoredContext::SetChunkLength(LONGLONG length)
|
||||
{
|
||||
this->chunkLength = length;
|
||||
this->chunkLength = length;
|
||||
}
|
||||
|
||||
BOOL CNodeHttpStoredContext::GetIsChunked()
|
||||
{
|
||||
return this->isChunked;
|
||||
return this->isChunked;
|
||||
}
|
||||
|
||||
void CNodeHttpStoredContext::SetIsChunked(BOOL chunked)
|
||||
{
|
||||
this->isChunked = chunked;
|
||||
this->isChunked = chunked;
|
||||
}
|
||||
|
||||
void CNodeHttpStoredContext::SetIsLastChunk(BOOL lastChunk)
|
||||
{
|
||||
this->isLastChunk = lastChunk;
|
||||
this->isLastChunk = lastChunk;
|
||||
}
|
||||
|
||||
BOOL CNodeHttpStoredContext::GetIsLastChunk()
|
||||
{
|
||||
return this->isLastChunk;
|
||||
return this->isLastChunk;
|
||||
}
|
||||
|
||||
HRESULT CNodeHttpStoredContext::GetHresult()
|
||||
{
|
||||
return this->result;
|
||||
return this->result;
|
||||
}
|
||||
|
||||
void CNodeHttpStoredContext::SetHresult(HRESULT result)
|
||||
{
|
||||
this->result = result;
|
||||
this->result = result;
|
||||
}
|
||||
|
||||
REQUEST_NOTIFICATION_STATUS CNodeHttpStoredContext::GetRequestNotificationStatus()
|
||||
{
|
||||
return this->requestNotificationStatus;
|
||||
return this->requestNotificationStatus;
|
||||
}
|
||||
|
||||
void CNodeHttpStoredContext::SetRequestNotificationStatus(REQUEST_NOTIFICATION_STATUS status)
|
||||
{
|
||||
this->requestNotificationStatus = status;
|
||||
this->requestNotificationStatus = status;
|
||||
}
|
||||
|
||||
GUID* CNodeHttpStoredContext::GetActivityId()
|
||||
{
|
||||
return &this->activityId;
|
||||
return &this->activityId;
|
||||
}
|
||||
|
||||
long CNodeHttpStoredContext::IncreasePendingAsyncOperationCount()
|
||||
{
|
||||
this->eventProvider->Log(
|
||||
L"iisnode increases pending async operation count",
|
||||
WINEVENT_LEVEL_VERBOSE,
|
||||
this->GetActivityId());
|
||||
if (this->requestPumpStarted)
|
||||
{
|
||||
return InterlockedIncrement(&this->upgradeContext->pendingAsyncOperationCount);
|
||||
}
|
||||
else
|
||||
{
|
||||
return InterlockedIncrement(&this->pendingAsyncOperationCount);
|
||||
}
|
||||
this->eventProvider->Log(this->context,
|
||||
L"iisnode increases pending async operation count",
|
||||
WINEVENT_LEVEL_VERBOSE,
|
||||
this->GetActivityId());
|
||||
if (this->requestPumpStarted)
|
||||
{
|
||||
return InterlockedIncrement(&this->upgradeContext->pendingAsyncOperationCount);
|
||||
}
|
||||
else
|
||||
{
|
||||
return InterlockedIncrement(&this->pendingAsyncOperationCount);
|
||||
}
|
||||
}
|
||||
|
||||
long CNodeHttpStoredContext::DecreasePendingAsyncOperationCount()
|
||||
{
|
||||
this->eventProvider->Log(
|
||||
L"iisnode decreases pending async operation count",
|
||||
WINEVENT_LEVEL_VERBOSE,
|
||||
this->GetActivityId());
|
||||
if (this->requestPumpStarted)
|
||||
{
|
||||
return InterlockedDecrement(&this->upgradeContext->pendingAsyncOperationCount);
|
||||
}
|
||||
else
|
||||
{
|
||||
return InterlockedDecrement(&this->pendingAsyncOperationCount);
|
||||
}
|
||||
this->eventProvider->Log(this->context,
|
||||
L"iisnode decreases pending async operation count",
|
||||
WINEVENT_LEVEL_VERBOSE,
|
||||
this->GetActivityId());
|
||||
if (this->requestPumpStarted)
|
||||
{
|
||||
return InterlockedDecrement(&this->upgradeContext->pendingAsyncOperationCount);
|
||||
}
|
||||
else
|
||||
{
|
||||
return InterlockedDecrement(&this->pendingAsyncOperationCount);
|
||||
}
|
||||
}
|
||||
|
||||
PCSTR CNodeHttpStoredContext::GetTargetUrl()
|
||||
{
|
||||
return this->targetUrl;
|
||||
return this->targetUrl;
|
||||
}
|
||||
|
||||
DWORD CNodeHttpStoredContext::GetTargetUrlLength()
|
||||
{
|
||||
return this->targetUrlLength;
|
||||
return this->targetUrlLength;
|
||||
}
|
||||
|
||||
void CNodeHttpStoredContext::SetTargetUrl(PCSTR targetUrl, DWORD targetUrlLength)
|
||||
{
|
||||
this->targetUrl = targetUrl;
|
||||
this->targetUrlLength = targetUrlLength;
|
||||
this->targetUrl = targetUrl;
|
||||
this->targetUrlLength = targetUrlLength;
|
||||
}
|
||||
|
||||
void CNodeHttpStoredContext::SetChildContext(IHttpContext* context)
|
||||
{
|
||||
this->childContext = context;
|
||||
this->childContext = context;
|
||||
}
|
||||
|
||||
IHttpContext* CNodeHttpStoredContext::GetChildContext()
|
||||
{
|
||||
return this->childContext;
|
||||
return this->childContext;
|
||||
}
|
||||
|
||||
BOOL CNodeHttpStoredContext::GetIsConnectionFromPool()
|
||||
{
|
||||
return this->isConnectionFromPool;
|
||||
return this->isConnectionFromPool;
|
||||
}
|
||||
|
||||
void CNodeHttpStoredContext::SetIsConnectionFromPool(BOOL fromPool)
|
||||
{
|
||||
this->isConnectionFromPool = fromPool;
|
||||
this->isConnectionFromPool = fromPool;
|
||||
}
|
||||
|
||||
void CNodeHttpStoredContext::SetExpectResponseBody(BOOL expect)
|
||||
{
|
||||
this->expectResponseBody = expect;
|
||||
this->expectResponseBody = expect;
|
||||
}
|
||||
|
||||
BOOL CNodeHttpStoredContext::GetExpectResponseBody()
|
||||
{
|
||||
return this->expectResponseBody;
|
||||
return this->expectResponseBody;
|
||||
}
|
||||
|
||||
void CNodeHttpStoredContext::SetCloseConnection(BOOL close)
|
||||
{
|
||||
this->closeConnection = close;
|
||||
this->closeConnection = close;
|
||||
}
|
||||
|
||||
BOOL CNodeHttpStoredContext::GetCloseConnection()
|
||||
{
|
||||
return this->closeConnection;
|
||||
return this->closeConnection;
|
||||
}
|
||||
|
||||
HRESULT CNodeHttpStoredContext::SetupUpgrade()
|
||||
{
|
||||
HRESULT hr;
|
||||
HRESULT hr;
|
||||
|
||||
ErrorIf(this->isUpgrade, E_FAIL);
|
||||
ErrorIf(this->isUpgrade, E_FAIL);
|
||||
|
||||
// The upgradeContext is used to pump incoming bytes to the node.js application.
|
||||
// The 'this' context is used to pump outgoing bytes to IIS. Once the response headers are flushed,
|
||||
// both contexts are used concurrently in a full duplex, asynchronous fashion.
|
||||
// The last context to complete pumping closes the IIS request.
|
||||
// The upgradeContext is used to pump incoming bytes to the node.js application.
|
||||
// The 'this' context is used to pump outgoing bytes to IIS. Once the response headers are flushed,
|
||||
// both contexts are used concurrently in a full duplex, asynchronous fashion.
|
||||
// The last context to complete pumping closes the IIS request.
|
||||
|
||||
ErrorIf(NULL == (this->upgradeContext = new CNodeHttpStoredContext(this->GetNodeApplication(), this->eventProvider, this->GetHttpContext())),
|
||||
ERROR_NOT_ENOUGH_MEMORY);
|
||||
this->upgradeContext->bufferSize = CModuleConfiguration::GetInitialRequestBufferSize(this->context);
|
||||
ErrorIf(NULL == (this->upgradeContext->buffer = this->context->AllocateRequestMemory(this->upgradeContext->bufferSize)),
|
||||
ERROR_NOT_ENOUGH_MEMORY);
|
||||
ErrorIf(NULL == (this->upgradeContext = new CNodeHttpStoredContext(this->GetNodeApplication(), this->eventProvider, this->GetHttpContext())),
|
||||
ERROR_NOT_ENOUGH_MEMORY);
|
||||
this->upgradeContext->bufferSize = CModuleConfiguration::GetInitialRequestBufferSize(this->context);
|
||||
ErrorIf(NULL == (this->upgradeContext->buffer = this->context->AllocateRequestMemory(this->upgradeContext->bufferSize)),
|
||||
ERROR_NOT_ENOUGH_MEMORY);
|
||||
|
||||
// Enable duplex read/write of data
|
||||
// Enable duplex read/write of data
|
||||
|
||||
IHttpContext3* ctx3 = (IHttpContext3*)this->GetHttpContext();
|
||||
ctx3->EnableFullDuplex();
|
||||
IHttpContext3* ctx3 = (IHttpContext3*)this->GetHttpContext();
|
||||
ctx3->EnableFullDuplex();
|
||||
|
||||
// Disable caching and buffering
|
||||
// Disable caching and buffering
|
||||
|
||||
ctx3->GetResponse()->DisableBuffering();
|
||||
ctx3->GetResponse()->DisableKernelCache();
|
||||
ctx3->GetResponse()->DisableBuffering();
|
||||
ctx3->GetResponse()->DisableKernelCache();
|
||||
|
||||
this->upgradeContext->SetPipe(this->GetPipe());
|
||||
this->upgradeContext->SetNodeProcess(this->GetNodeProcess());
|
||||
this->upgradeContext->isUpgrade = TRUE;
|
||||
this->isUpgrade = TRUE;
|
||||
this->upgradeContext->SetPipe(this->GetPipe());
|
||||
this->upgradeContext->SetNodeProcess(this->GetNodeProcess());
|
||||
this->upgradeContext->isUpgrade = TRUE;
|
||||
this->isUpgrade = TRUE;
|
||||
|
||||
return S_OK;
|
||||
return S_OK;
|
||||
|
||||
Error:
|
||||
|
||||
return hr;
|
||||
return hr;
|
||||
}
|
||||
|
||||
BOOL CNodeHttpStoredContext::GetIsUpgrade()
|
||||
{
|
||||
return this->isUpgrade;
|
||||
return this->isUpgrade;
|
||||
}
|
||||
|
||||
CNodeHttpStoredContext* CNodeHttpStoredContext::GetUpgradeContext()
|
||||
{
|
||||
return this->upgradeContext;
|
||||
return this->upgradeContext;
|
||||
}
|
||||
|
||||
void CNodeHttpStoredContext::SetOpaqueFlag()
|
||||
{
|
||||
this->opaqueFlagSet = TRUE;
|
||||
this->opaqueFlagSet = TRUE;
|
||||
}
|
||||
|
||||
BOOL CNodeHttpStoredContext::GetOpaqueFlagSet()
|
||||
{
|
||||
return this->opaqueFlagSet;
|
||||
return this->opaqueFlagSet;
|
||||
}
|
||||
|
||||
void CNodeHttpStoredContext::SetRequestPumpStarted()
|
||||
{
|
||||
// The pending async operation count for the pair of CNodeHttpStoredContexts will be maintained in the upgradeContext instance from now on.
|
||||
// The +1 represents the creation of the upgradeContext and the corresponding decrease happens when the pumping of incoming bytes completes.
|
||||
this->upgradeContext->pendingAsyncOperationCount = this->pendingAsyncOperationCount + 1;
|
||||
this->pendingAsyncOperationCount = 0;
|
||||
this->requestPumpStarted = TRUE;
|
||||
// The pending async operation count for the pair of CNodeHttpStoredContexts will be maintained in the upgradeContext instance from now on.
|
||||
// The +1 represents the creation of the upgradeContext and the corresponding decrease happens when the pumping of incoming bytes completes.
|
||||
this->upgradeContext->pendingAsyncOperationCount = this->pendingAsyncOperationCount + 1;
|
||||
this->pendingAsyncOperationCount = 0;
|
||||
this->requestPumpStarted = TRUE;
|
||||
}
|
||||
|
||||
BOOL CNodeHttpStoredContext::GetRequestPumpStarted()
|
||||
{
|
||||
return this->requestPumpStarted;
|
||||
return this->requestPumpStarted;
|
||||
}
|
||||
|
||||
FILETIME* CNodeHttpStoredContext::GetStartTime()
|
||||
{
|
||||
return &this->startTime;
|
||||
return &this->startTime;
|
||||
}
|
||||
|
||||
DWORD CNodeHttpStoredContext::GetBytesCompleted()
|
||||
{
|
||||
return this->asyncContext.bytesCompleteted;
|
||||
return this->asyncContext.bytesCompleteted;
|
||||
}
|
||||
|
||||
void CNodeHttpStoredContext::SetBytesCompleted(DWORD bytesCompleted)
|
||||
{
|
||||
this->asyncContext.bytesCompleteted = bytesCompleted;
|
||||
this->asyncContext.bytesCompleteted = bytesCompleted;
|
||||
}
|
||||
|
||||
void CNodeHttpStoredContext::SetContinueSynchronously(BOOL continueSynchronously)
|
||||
{
|
||||
this->asyncContext.continueSynchronously = continueSynchronously;
|
||||
this->asyncContext.continueSynchronously = continueSynchronously;
|
||||
}
|
||||
|
|
|
@ -1,122 +1,122 @@
|
|||
#include "precomp.h"
|
||||
|
||||
CNodeProcess::CNodeProcess(CNodeProcessManager* processManager, IHttpContext* context)
|
||||
: processManager(processManager), process(NULL), processWatcher(NULL), isClosing(FALSE),
|
||||
hasProcessExited(FALSE)
|
||||
: processManager(processManager), process(NULL), processWatcher(NULL), isClosing(FALSE),
|
||||
hasProcessExited(FALSE)
|
||||
{
|
||||
RtlZeroMemory(this->namedPipe, sizeof this->namedPipe);
|
||||
RtlZeroMemory(&this->startupInfo, sizeof this->startupInfo);
|
||||
this->maxConcurrentRequestsPerProcess = CModuleConfiguration::GetMaxConcurrentRequestsPerProcess(context);
|
||||
RtlZeroMemory(this->namedPipe, sizeof this->namedPipe);
|
||||
RtlZeroMemory(&this->startupInfo, sizeof this->startupInfo);
|
||||
this->maxConcurrentRequestsPerProcess = CModuleConfiguration::GetMaxConcurrentRequestsPerProcess(context);
|
||||
}
|
||||
|
||||
CNodeProcess::~CNodeProcess()
|
||||
{
|
||||
this->isClosing = TRUE;
|
||||
this->isClosing = TRUE;
|
||||
|
||||
if (NULL != this->process)
|
||||
{
|
||||
TerminateProcess(this->process, 2);
|
||||
CloseHandle(this->process);
|
||||
this->process = NULL;
|
||||
}
|
||||
if (NULL != this->process)
|
||||
{
|
||||
TerminateProcess(this->process, 2);
|
||||
CloseHandle(this->process);
|
||||
this->process = NULL;
|
||||
}
|
||||
|
||||
if (NULL != this->processWatcher)
|
||||
{
|
||||
// The following check prevents a dead-lock between process watcher thread calling OnProcessExited
|
||||
// which results in CNodeProcess::~ctor being called,
|
||||
// and the wait for process watcher thread to exit in CNodeProcess::~ctor itself.
|
||||
if (NULL != this->processWatcher)
|
||||
{
|
||||
// The following check prevents a dead-lock between process watcher thread calling OnProcessExited
|
||||
// which results in CNodeProcess::~ctor being called,
|
||||
// and the wait for process watcher thread to exit in CNodeProcess::~ctor itself.
|
||||
|
||||
if (!this->hasProcessExited)
|
||||
{
|
||||
WaitForSingleObject(this->processWatcher, INFINITE);
|
||||
}
|
||||
CloseHandle(this->processWatcher);
|
||||
this->processWatcher = NULL;
|
||||
}
|
||||
if (!this->hasProcessExited)
|
||||
{
|
||||
WaitForSingleObject(this->processWatcher, INFINITE);
|
||||
}
|
||||
CloseHandle(this->processWatcher);
|
||||
this->processWatcher = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
BOOL CNodeProcess::HasProcessExited()
|
||||
{
|
||||
return this->hasProcessExited;
|
||||
return this->hasProcessExited;
|
||||
}
|
||||
|
||||
HRESULT CNodeProcess::Initialize(IHttpContext* context)
|
||||
{
|
||||
HRESULT hr;
|
||||
UUID uuid;
|
||||
RPC_CSTR suuid = NULL;
|
||||
LPWSTR fullCommandLine = NULL;
|
||||
LPCWSTR coreCommandLine;
|
||||
LPCWSTR interceptor;
|
||||
PCWSTR scriptName;
|
||||
PROCESS_INFORMATION processInformation;
|
||||
DWORD exitCode = S_OK;
|
||||
LPCH newEnvironment = NULL;
|
||||
DWORD flags;
|
||||
HANDLE job;
|
||||
PWSTR currentDirectory = NULL;
|
||||
PWSTR scriptTranslated = NULL;
|
||||
DWORD currentDirectorySize = 0;
|
||||
CNodeApplication* app = this->GetProcessManager()->GetApplication();
|
||||
HRESULT hr;
|
||||
UUID uuid;
|
||||
RPC_CSTR suuid = NULL;
|
||||
LPWSTR fullCommandLine = NULL;
|
||||
LPCWSTR coreCommandLine;
|
||||
LPCWSTR interceptor;
|
||||
PCWSTR scriptName;
|
||||
PROCESS_INFORMATION processInformation;
|
||||
DWORD exitCode = S_OK;
|
||||
LPCH newEnvironment = NULL;
|
||||
DWORD flags;
|
||||
HANDLE job;
|
||||
PWSTR currentDirectory = NULL;
|
||||
PWSTR scriptTranslated = NULL;
|
||||
DWORD currentDirectorySize = 0;
|
||||
CNodeApplication* app = this->GetProcessManager()->GetApplication();
|
||||
PCH pSignalPipeName = NULL;
|
||||
|
||||
RtlZeroMemory(&processInformation, sizeof processInformation);
|
||||
RtlZeroMemory(&startupInfo, sizeof startupInfo);
|
||||
RtlZeroMemory(&processInformation, sizeof processInformation);
|
||||
RtlZeroMemory(&startupInfo, sizeof startupInfo);
|
||||
|
||||
// initialize connection pool
|
||||
// initialize connection pool
|
||||
|
||||
CheckError(this->connectionPool.Initialize(context));
|
||||
CheckError(this->connectionPool.Initialize(context));
|
||||
|
||||
// generate the name for the named pipe to communicate with the node.js process
|
||||
|
||||
ErrorIf(RPC_S_OK != UuidCreate(&uuid), ERROR_CAN_NOT_COMPLETE);
|
||||
ErrorIf(RPC_S_OK != UuidToString(&uuid, &suuid), ERROR_NOT_ENOUGH_MEMORY);
|
||||
_tcscpy(this->namedPipe, _T("\\\\.\\pipe\\"));
|
||||
_tcscpy(this->namedPipe + 9, (char*)suuid);
|
||||
RpcStringFree(&suuid);
|
||||
suuid = NULL;
|
||||
// generate the name for the named pipe to communicate with the node.js process
|
||||
|
||||
ErrorIf(RPC_S_OK != UuidCreate(&uuid), ERROR_CAN_NOT_COMPLETE);
|
||||
ErrorIf(RPC_S_OK != UuidToString(&uuid, &suuid), ERROR_NOT_ENOUGH_MEMORY);
|
||||
_tcscpy(this->namedPipe, _T("\\\\.\\pipe\\"));
|
||||
_tcscpy(this->namedPipe + 9, (char*)suuid);
|
||||
RpcStringFree(&suuid);
|
||||
suuid = NULL;
|
||||
|
||||
// build the full command line for the node.js process
|
||||
// build the full command line for the node.js process
|
||||
|
||||
interceptor = CModuleConfiguration::GetInterceptor(context);
|
||||
coreCommandLine = CModuleConfiguration::GetNodeProcessCommandLine(context);
|
||||
scriptName = this->GetProcessManager()->GetApplication()->GetScriptName();
|
||||
// allocate memory for command line to allow for debugging options plus interceptor plus spaces and enclosing the script name in quotes
|
||||
ErrorIf(NULL == (fullCommandLine = new WCHAR[wcslen(coreCommandLine) + wcslen(interceptor) + wcslen(scriptName) + 256]), ERROR_NOT_ENOUGH_MEMORY);
|
||||
wcscpy(fullCommandLine, coreCommandLine);
|
||||
interceptor = CModuleConfiguration::GetInterceptor(context);
|
||||
coreCommandLine = CModuleConfiguration::GetNodeProcessCommandLine(context);
|
||||
scriptName = this->GetProcessManager()->GetApplication()->GetScriptName();
|
||||
// allocate memory for command line to allow for debugging options plus interceptor plus spaces and enclosing the script name in quotes
|
||||
ErrorIf(NULL == (fullCommandLine = new WCHAR[wcslen(coreCommandLine) + wcslen(interceptor) + wcslen(scriptName) + 256]), ERROR_NOT_ENOUGH_MEMORY);
|
||||
wcscpy(fullCommandLine, coreCommandLine);
|
||||
|
||||
// add debug options
|
||||
if (app->IsDebuggee())
|
||||
{
|
||||
WCHAR buffer[64];
|
||||
// add debug options
|
||||
if (app->IsDebuggee())
|
||||
{
|
||||
WCHAR buffer[64];
|
||||
|
||||
if (ND_DEBUG_BRK == app->GetDebugCommand())
|
||||
{
|
||||
swprintf(buffer, L" --debug-brk=%d ", app->GetDebugPort());
|
||||
}
|
||||
else if (ND_DEBUG == app->GetDebugCommand())
|
||||
{
|
||||
swprintf(buffer, L" --debug=%d ", app->GetDebugPort());
|
||||
}
|
||||
else
|
||||
{
|
||||
CheckError(ERROR_INVALID_PARAMETER);
|
||||
}
|
||||
if (ND_DEBUG_BRK == app->GetDebugCommand())
|
||||
{
|
||||
swprintf(buffer, L" --debug-brk=%d ", app->GetDebugPort());
|
||||
}
|
||||
else if (ND_DEBUG == app->GetDebugCommand())
|
||||
{
|
||||
swprintf(buffer, L" --debug=%d ", app->GetDebugPort());
|
||||
}
|
||||
else
|
||||
{
|
||||
CheckError(ERROR_INVALID_PARAMETER);
|
||||
}
|
||||
|
||||
wcscat(fullCommandLine, buffer);
|
||||
}
|
||||
|
||||
if (!app->IsDebugger())
|
||||
{
|
||||
// add interceptor
|
||||
wcscat(fullCommandLine, L" ");
|
||||
wcscat(fullCommandLine, interceptor);
|
||||
}
|
||||
wcscat(fullCommandLine, buffer);
|
||||
}
|
||||
|
||||
if (!app->IsDebugger())
|
||||
{
|
||||
// add interceptor
|
||||
wcscat(fullCommandLine, L" ");
|
||||
wcscat(fullCommandLine, interceptor);
|
||||
}
|
||||
|
||||
// add application entry point
|
||||
wcscat(fullCommandLine, L" \"");
|
||||
wcscat(fullCommandLine, scriptName);
|
||||
wcscat(fullCommandLine, L"\"");
|
||||
// add application entry point
|
||||
wcscat(fullCommandLine, L" \"");
|
||||
wcscat(fullCommandLine, scriptName);
|
||||
wcscat(fullCommandLine, L"\"");
|
||||
|
||||
if(CModuleConfiguration::GetRecycleSignalEnabled(context))
|
||||
{
|
||||
|
@ -128,133 +128,133 @@ HRESULT CNodeProcess::Initialize(IHttpContext* context)
|
|||
pSignalPipeName[dwSignalPipeNameLen] = '\0';
|
||||
}
|
||||
|
||||
// create the environment block for the node.js process
|
||||
// create the environment block for the node.js process
|
||||
|
||||
CheckError(CModuleConfiguration::CreateNodeEnvironment(
|
||||
context,
|
||||
app->IsDebugger() ? app->GetDebugPort() : 0,
|
||||
this->namedPipe,
|
||||
CheckError(CModuleConfiguration::CreateNodeEnvironment(
|
||||
context,
|
||||
app->IsDebugger() ? app->GetDebugPort() : 0,
|
||||
this->namedPipe,
|
||||
CModuleConfiguration::GetRecycleSignalEnabled(context) ? pSignalPipeName : NULL,
|
||||
&newEnvironment));
|
||||
&newEnvironment));
|
||||
|
||||
// establish the current directory for node.exe process to be the same as the location of the application *.js file
|
||||
// (in case of the debugger process, it is still the debuggee application file)
|
||||
// establish the current directory for node.exe process to be the same as the location of the application *.js file
|
||||
// (in case of the debugger process, it is still the debuggee application file)
|
||||
|
||||
scriptTranslated = (PWSTR)context->GetScriptTranslated(¤tDirectorySize);
|
||||
while (currentDirectorySize && scriptTranslated[currentDirectorySize] != L'\\' && scriptTranslated[currentDirectorySize] != L'/')
|
||||
currentDirectorySize--;
|
||||
ErrorIf(NULL == (currentDirectory = new WCHAR[wcslen(scriptTranslated) + 1]), ERROR_NOT_ENOUGH_MEMORY);
|
||||
wcscpy(currentDirectory, scriptTranslated);
|
||||
currentDirectory[currentDirectorySize] = L'\0';
|
||||
scriptTranslated = (PWSTR)context->GetScriptTranslated(¤tDirectorySize);
|
||||
while (currentDirectorySize && scriptTranslated[currentDirectorySize] != L'\\' && scriptTranslated[currentDirectorySize] != L'/')
|
||||
currentDirectorySize--;
|
||||
ErrorIf(NULL == (currentDirectory = new WCHAR[wcslen(scriptTranslated) + 1]), ERROR_NOT_ENOUGH_MEMORY);
|
||||
wcscpy(currentDirectory, scriptTranslated);
|
||||
currentDirectory[currentDirectorySize] = L'\0';
|
||||
|
||||
// create startup info for the node.js process
|
||||
// create startup info for the node.js process
|
||||
|
||||
RtlZeroMemory(&this->startupInfo, sizeof this->startupInfo);
|
||||
GetStartupInfoW(&startupInfo);
|
||||
CheckError(this->CreateStdHandles(context));
|
||||
RtlZeroMemory(&this->startupInfo, sizeof this->startupInfo);
|
||||
GetStartupInfoW(&startupInfo);
|
||||
CheckError(this->CreateStdHandles(context));
|
||||
|
||||
// create process watcher thread in a suspended state
|
||||
// create process watcher thread in a suspended state
|
||||
|
||||
ErrorIf(NULL == (this->processWatcher = (HANDLE)_beginthreadex(
|
||||
NULL,
|
||||
4096,
|
||||
CNodeProcess::ProcessWatcher,
|
||||
this,
|
||||
CREATE_SUSPENDED,
|
||||
NULL)),
|
||||
ERROR_NOT_ENOUGH_MEMORY);
|
||||
ErrorIf(NULL == (this->processWatcher = (HANDLE)_beginthreadex(
|
||||
NULL,
|
||||
4096,
|
||||
CNodeProcess::ProcessWatcher,
|
||||
this,
|
||||
CREATE_SUSPENDED,
|
||||
NULL)),
|
||||
ERROR_NOT_ENOUGH_MEMORY);
|
||||
|
||||
// create the node.exe process
|
||||
// create the node.exe process
|
||||
|
||||
flags = DETACHED_PROCESS | CREATE_SUSPENDED;
|
||||
if (this->GetProcessManager()->GetApplication()->GetApplicationManager()->GetBreakAwayFromJobObject())
|
||||
{
|
||||
flags |= CREATE_BREAKAWAY_FROM_JOB;
|
||||
}
|
||||
|
||||
if(!CreateProcessW(
|
||||
NULL,
|
||||
fullCommandLine,
|
||||
NULL,
|
||||
NULL,
|
||||
TRUE,
|
||||
flags,
|
||||
newEnvironment,
|
||||
currentDirectory,
|
||||
&this->startupInfo,
|
||||
&processInformation))
|
||||
{
|
||||
if (ERROR_FILE_NOT_FOUND == (hr = GetLastError()))
|
||||
{
|
||||
hr = IISNODE_ERROR_UNABLE_TO_START_NODE_EXE;
|
||||
}
|
||||
flags = DETACHED_PROCESS | CREATE_SUSPENDED;
|
||||
if (this->GetProcessManager()->GetApplication()->GetApplicationManager()->GetBreakAwayFromJobObject())
|
||||
{
|
||||
flags |= CREATE_BREAKAWAY_FROM_JOB;
|
||||
}
|
||||
|
||||
if(!CreateProcessW(
|
||||
NULL,
|
||||
fullCommandLine,
|
||||
NULL,
|
||||
NULL,
|
||||
TRUE,
|
||||
flags,
|
||||
newEnvironment,
|
||||
currentDirectory,
|
||||
&this->startupInfo,
|
||||
&processInformation))
|
||||
{
|
||||
if (ERROR_FILE_NOT_FOUND == (hr = GetLastError()))
|
||||
{
|
||||
hr = IISNODE_ERROR_UNABLE_TO_START_NODE_EXE;
|
||||
}
|
||||
|
||||
CheckError(hr);
|
||||
}
|
||||
|
||||
// join a job object if needed, then resume the process
|
||||
CheckError(hr);
|
||||
}
|
||||
|
||||
// join a job object if needed, then resume the process
|
||||
|
||||
job = this->GetProcessManager()->GetApplication()->GetApplicationManager()->GetJobObject();
|
||||
if (NULL != job)
|
||||
{
|
||||
ErrorIf(!AssignProcessToJobObject(job, processInformation.hProcess), HRESULT_FROM_WIN32(GetLastError()));
|
||||
}
|
||||
job = this->GetProcessManager()->GetApplication()->GetApplicationManager()->GetJobObject();
|
||||
if (NULL != job)
|
||||
{
|
||||
ErrorIf(!AssignProcessToJobObject(job, processInformation.hProcess), HRESULT_FROM_WIN32(GetLastError()));
|
||||
}
|
||||
|
||||
ErrorIf((DWORD) -1 == ResumeThread(processInformation.hThread), GetLastError());
|
||||
ErrorIf(GetExitCodeProcess(processInformation.hProcess, &exitCode) && STILL_ACTIVE != exitCode, exitCode);
|
||||
this->process = processInformation.hProcess;
|
||||
this->pid = processInformation.dwProcessId;
|
||||
|
||||
// start process watcher thread to get notified of premature node process termination in CNodeProcess::OnProcessExited
|
||||
ErrorIf((DWORD) -1 == ResumeThread(processInformation.hThread), GetLastError());
|
||||
ErrorIf(GetExitCodeProcess(processInformation.hProcess, &exitCode) && STILL_ACTIVE != exitCode, exitCode);
|
||||
this->process = processInformation.hProcess;
|
||||
this->pid = processInformation.dwProcessId;
|
||||
|
||||
// start process watcher thread to get notified of premature node process termination in CNodeProcess::OnProcessExited
|
||||
|
||||
ResumeThread(this->processWatcher);
|
||||
ResumeThread(this->processWatcher);
|
||||
|
||||
// clean up
|
||||
// clean up
|
||||
|
||||
delete [] currentDirectory;
|
||||
currentDirectory = NULL;
|
||||
delete [] newEnvironment;
|
||||
newEnvironment = NULL;
|
||||
delete [] fullCommandLine;
|
||||
fullCommandLine = NULL;
|
||||
CloseHandle(processInformation.hThread);
|
||||
processInformation.hThread = NULL;
|
||||
delete [] currentDirectory;
|
||||
currentDirectory = NULL;
|
||||
delete [] newEnvironment;
|
||||
newEnvironment = NULL;
|
||||
delete [] fullCommandLine;
|
||||
fullCommandLine = NULL;
|
||||
CloseHandle(processInformation.hThread);
|
||||
processInformation.hThread = NULL;
|
||||
if(pSignalPipeName != NULL)
|
||||
{
|
||||
delete[] pSignalPipeName;
|
||||
pSignalPipeName = NULL;
|
||||
}
|
||||
|
||||
if (this->GetProcessManager()->GetApplication()->IsDebugger())
|
||||
{
|
||||
this->GetProcessManager()->GetEventProvider()->Log(
|
||||
L"iisnode initialized a new node.exe debugger process", WINEVENT_LEVEL_INFO);
|
||||
}
|
||||
else
|
||||
{
|
||||
this->GetProcessManager()->GetEventProvider()->Log(
|
||||
L"iisnode initialized a new node.exe process", WINEVENT_LEVEL_INFO);
|
||||
}
|
||||
if (this->GetProcessManager()->GetApplication()->IsDebugger())
|
||||
{
|
||||
this->GetProcessManager()->GetEventProvider()->Log(context,
|
||||
L"iisnode initialized a new node.exe debugger process", WINEVENT_LEVEL_INFO);
|
||||
}
|
||||
else
|
||||
{
|
||||
this->GetProcessManager()->GetEventProvider()->Log(context,
|
||||
L"iisnode initialized a new node.exe process", WINEVENT_LEVEL_INFO);
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
return S_OK;
|
||||
Error:
|
||||
|
||||
if (this->GetProcessManager()->GetApplication()->IsDebugger())
|
||||
{
|
||||
this->GetProcessManager()->GetEventProvider()->Log(
|
||||
L"iisnode failed to initialize a new node.exe debugger process", WINEVENT_LEVEL_ERROR);
|
||||
}
|
||||
else
|
||||
{
|
||||
this->GetProcessManager()->GetEventProvider()->Log(
|
||||
L"iisnode failed to initialize a new node.exe process", WINEVENT_LEVEL_ERROR);
|
||||
}
|
||||
if (this->GetProcessManager()->GetApplication()->IsDebugger())
|
||||
{
|
||||
this->GetProcessManager()->GetEventProvider()->Log(context,
|
||||
L"iisnode failed to initialize a new node.exe debugger process", WINEVENT_LEVEL_ERROR);
|
||||
}
|
||||
else
|
||||
{
|
||||
this->GetProcessManager()->GetEventProvider()->Log(context,
|
||||
L"iisnode failed to initialize a new node.exe process", WINEVENT_LEVEL_ERROR);
|
||||
}
|
||||
|
||||
if (currentDirectory)
|
||||
{
|
||||
delete [] currentDirectory;
|
||||
currentDirectory = NULL;
|
||||
}
|
||||
if (currentDirectory)
|
||||
{
|
||||
delete [] currentDirectory;
|
||||
currentDirectory = NULL;
|
||||
}
|
||||
|
||||
if(pSignalPipeName)
|
||||
{
|
||||
|
@ -262,315 +262,315 @@ Error:
|
|||
pSignalPipeName = NULL;
|
||||
}
|
||||
|
||||
if (suuid != NULL)
|
||||
{
|
||||
RpcStringFree(&suuid);
|
||||
suuid = NULL;
|
||||
}
|
||||
if (suuid != NULL)
|
||||
{
|
||||
RpcStringFree(&suuid);
|
||||
suuid = NULL;
|
||||
}
|
||||
|
||||
if (NULL != fullCommandLine)
|
||||
{
|
||||
delete[] fullCommandLine;
|
||||
fullCommandLine = NULL;
|
||||
}
|
||||
if (NULL != fullCommandLine)
|
||||
{
|
||||
delete[] fullCommandLine;
|
||||
fullCommandLine = NULL;
|
||||
}
|
||||
|
||||
if (NULL != processInformation.hThread)
|
||||
{
|
||||
CloseHandle(processInformation.hThread);
|
||||
processInformation.hThread = NULL;
|
||||
}
|
||||
if (NULL != processInformation.hThread)
|
||||
{
|
||||
CloseHandle(processInformation.hThread);
|
||||
processInformation.hThread = NULL;
|
||||
}
|
||||
|
||||
if (NULL != processInformation.hProcess)
|
||||
{
|
||||
TerminateProcess(processInformation.hProcess, 1);
|
||||
CloseHandle(processInformation.hProcess);
|
||||
processInformation.hProcess = NULL;
|
||||
}
|
||||
if (NULL != processInformation.hProcess)
|
||||
{
|
||||
TerminateProcess(processInformation.hProcess, 1);
|
||||
CloseHandle(processInformation.hProcess);
|
||||
processInformation.hProcess = NULL;
|
||||
}
|
||||
|
||||
if (NULL != newEnvironment)
|
||||
{
|
||||
delete[] newEnvironment;
|
||||
newEnvironment = NULL;
|
||||
}
|
||||
if (NULL != newEnvironment)
|
||||
{
|
||||
delete[] newEnvironment;
|
||||
newEnvironment = NULL;
|
||||
}
|
||||
|
||||
if (NULL != this->processWatcher)
|
||||
{
|
||||
ResumeThread(this->processWatcher);
|
||||
WaitForSingleObject(this->processWatcher, INFINITE);
|
||||
CloseHandle(this->processWatcher);
|
||||
this->processWatcher = NULL;
|
||||
}
|
||||
if (NULL != this->processWatcher)
|
||||
{
|
||||
ResumeThread(this->processWatcher);
|
||||
WaitForSingleObject(this->processWatcher, INFINITE);
|
||||
CloseHandle(this->processWatcher);
|
||||
this->processWatcher = NULL;
|
||||
}
|
||||
|
||||
if (NULL != this->startupInfo.hStdOutput && INVALID_HANDLE_VALUE != this->startupInfo.hStdOutput)
|
||||
{
|
||||
CloseHandle(this->startupInfo.hStdOutput);
|
||||
this->startupInfo.hStdOutput = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
if (NULL != this->startupInfo.hStdOutput && INVALID_HANDLE_VALUE != this->startupInfo.hStdOutput)
|
||||
{
|
||||
CloseHandle(this->startupInfo.hStdOutput);
|
||||
this->startupInfo.hStdOutput = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
if (NULL != this->startupInfo.hStdError && INVALID_HANDLE_VALUE != this->startupInfo.hStdError)
|
||||
{
|
||||
CloseHandle(this->startupInfo.hStdError);
|
||||
this->startupInfo.hStdError = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
if (NULL != this->startupInfo.hStdError && INVALID_HANDLE_VALUE != this->startupInfo.hStdError)
|
||||
{
|
||||
CloseHandle(this->startupInfo.hStdError);
|
||||
this->startupInfo.hStdError = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
return hr;
|
||||
return hr;
|
||||
}
|
||||
|
||||
unsigned int WINAPI CNodeProcess::ProcessWatcher(void* arg)
|
||||
{
|
||||
CNodeProcess* process = (CNodeProcess*)arg;
|
||||
DWORD exitCode;
|
||||
DWORD waitResult;
|
||||
CNodeEventProvider* log = process->GetProcessManager()->GetEventProvider();
|
||||
BOOL isDebugger = process->GetProcessManager()->GetApplication()->IsDebugger();
|
||||
CNodeProcess* process = (CNodeProcess*)arg;
|
||||
DWORD exitCode;
|
||||
DWORD waitResult;
|
||||
CNodeEventProvider* log = process->GetProcessManager()->GetEventProvider();
|
||||
BOOL isDebugger = process->GetProcessManager()->GetApplication()->IsDebugger();
|
||||
|
||||
while (!process->isClosing && process->process)
|
||||
{
|
||||
waitResult = WaitForSingleObjectEx(process->process, INFINITE, TRUE);
|
||||
if (process->process)
|
||||
{
|
||||
while (!process->isClosing && process->process)
|
||||
{
|
||||
waitResult = WaitForSingleObjectEx(process->process, INFINITE, TRUE);
|
||||
if (process->process)
|
||||
{
|
||||
if(GetExitCodeProcess(process->process, &exitCode) && STILL_ACTIVE != exitCode)
|
||||
{
|
||||
if (isDebugger)
|
||||
{
|
||||
log->Log(L"iisnode detected termination of node.exe debugger process", WINEVENT_LEVEL_ERROR);
|
||||
}
|
||||
else
|
||||
{
|
||||
log->Log(L"iisnode detected termination of node.exe process", WINEVENT_LEVEL_ERROR);
|
||||
}
|
||||
if (isDebugger)
|
||||
{
|
||||
log->Log(L"iisnode detected termination of node.exe debugger process", WINEVENT_LEVEL_ERROR);
|
||||
}
|
||||
else
|
||||
{
|
||||
log->Log(L"iisnode detected termination of node.exe process", WINEVENT_LEVEL_ERROR);
|
||||
}
|
||||
|
||||
if (!process->isClosing)
|
||||
{
|
||||
process->OnProcessExited();
|
||||
}
|
||||
if (!process->isClosing)
|
||||
{
|
||||
process->OnProcessExited();
|
||||
}
|
||||
|
||||
return exitCode;
|
||||
return exitCode;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// process handle was closed and set to NULL by ~CNodeProcess
|
||||
return ERROR_INVALID_HANDLE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
CNodeProcessManager* CNodeProcess::GetProcessManager()
|
||||
{
|
||||
return this->processManager;
|
||||
return this->processManager;
|
||||
}
|
||||
|
||||
HANDLE CNodeProcess::GetProcess()
|
||||
{
|
||||
return this->process;
|
||||
return this->process;
|
||||
}
|
||||
|
||||
DWORD CNodeProcess::GetPID()
|
||||
{
|
||||
return this->pid;
|
||||
return this->pid;
|
||||
}
|
||||
|
||||
DWORD CNodeProcess::GetActiveRequestCount()
|
||||
{
|
||||
return this->activeRequestPool.GetRequestCount();
|
||||
return this->activeRequestPool.GetRequestCount();
|
||||
}
|
||||
|
||||
HRESULT CNodeProcess::AcceptRequest(CNodeHttpStoredContext* context)
|
||||
{
|
||||
HRESULT hr;
|
||||
HRESULT hr;
|
||||
|
||||
CheckError(this->activeRequestPool.Add(context));
|
||||
context->SetNodeProcess(this);
|
||||
CheckError(CProtocolBridge::InitiateRequest(context));
|
||||
CheckError(this->activeRequestPool.Add(context));
|
||||
context->SetNodeProcess(this);
|
||||
CheckError(CProtocolBridge::InitiateRequest(context));
|
||||
|
||||
return S_OK;
|
||||
return S_OK;
|
||||
Error:
|
||||
|
||||
return hr;
|
||||
return hr;
|
||||
}
|
||||
|
||||
LPCTSTR CNodeProcess::GetNamedPipeName()
|
||||
{
|
||||
return this->namedPipe;
|
||||
return this->namedPipe;
|
||||
}
|
||||
|
||||
void CNodeProcess::OnRequestCompleted(CNodeHttpStoredContext* context)
|
||||
{
|
||||
this->activeRequestPool.Remove(); // this call may results in "this" being disposed on a different thread
|
||||
this->activeRequestPool.Remove(); // this call may results in "this" being disposed on a different thread
|
||||
}
|
||||
|
||||
void CNodeProcess::OnProcessExited()
|
||||
{
|
||||
this->isClosing = TRUE;
|
||||
this->hasProcessExited = TRUE;
|
||||
this->GetProcessManager()->RecycleProcess(this);
|
||||
this->isClosing = TRUE;
|
||||
this->hasProcessExited = TRUE;
|
||||
this->GetProcessManager()->RecycleProcess(this);
|
||||
}
|
||||
|
||||
void CNodeProcess::SignalWhenDrained(HANDLE handle)
|
||||
{
|
||||
this->activeRequestPool.SignalWhenDrained(handle);
|
||||
this->activeRequestPool.SignalWhenDrained(handle);
|
||||
}
|
||||
|
||||
HRESULT CNodeProcess::CreateStdHandles(IHttpContext* context)
|
||||
{
|
||||
this->startupInfo.hStdError = this->startupInfo.hStdInput = this->startupInfo.hStdOutput = INVALID_HANDLE_VALUE;
|
||||
this->startupInfo.dwFlags = STARTF_USESTDHANDLES;
|
||||
this->startupInfo.hStdError = this->startupInfo.hStdInput = this->startupInfo.hStdOutput = INVALID_HANDLE_VALUE;
|
||||
this->startupInfo.dwFlags = STARTF_USESTDHANDLES;
|
||||
|
||||
HRESULT hr;
|
||||
SECURITY_ATTRIBUTES security;
|
||||
HRESULT hr;
|
||||
SECURITY_ATTRIBUTES security;
|
||||
|
||||
// stdout == stderr
|
||||
// stdout == stderr
|
||||
|
||||
RtlZeroMemory(&security, sizeof SECURITY_ATTRIBUTES);
|
||||
security.bInheritHandle = TRUE;
|
||||
security.nLength = sizeof SECURITY_ATTRIBUTES;
|
||||
|
||||
ErrorIf(INVALID_HANDLE_VALUE == (this->startupInfo.hStdOutput = CreateFileW(
|
||||
L"NUL",
|
||||
GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||
&security,
|
||||
OPEN_EXISTING,
|
||||
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH,
|
||||
NULL)), GetLastError());
|
||||
RtlZeroMemory(&security, sizeof SECURITY_ATTRIBUTES);
|
||||
security.bInheritHandle = TRUE;
|
||||
security.nLength = sizeof SECURITY_ATTRIBUTES;
|
||||
|
||||
ErrorIf(INVALID_HANDLE_VALUE == (this->startupInfo.hStdOutput = CreateFileW(
|
||||
L"NUL",
|
||||
GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||
&security,
|
||||
OPEN_EXISTING,
|
||||
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH,
|
||||
NULL)), GetLastError());
|
||||
|
||||
ErrorIf(0 == DuplicateHandle(
|
||||
GetCurrentProcess(),
|
||||
this->startupInfo.hStdOutput,
|
||||
GetCurrentProcess(),
|
||||
&this->startupInfo.hStdError,
|
||||
0,
|
||||
TRUE,
|
||||
DUPLICATE_SAME_ACCESS),
|
||||
GetLastError());
|
||||
ErrorIf(0 == DuplicateHandle(
|
||||
GetCurrentProcess(),
|
||||
this->startupInfo.hStdOutput,
|
||||
GetCurrentProcess(),
|
||||
&this->startupInfo.hStdError,
|
||||
0,
|
||||
TRUE,
|
||||
DUPLICATE_SAME_ACCESS),
|
||||
GetLastError());
|
||||
|
||||
return S_OK;
|
||||
return S_OK;
|
||||
Error:
|
||||
|
||||
if (INVALID_HANDLE_VALUE != this->startupInfo.hStdOutput)
|
||||
{
|
||||
CloseHandle(this->startupInfo.hStdOutput);
|
||||
this->startupInfo.hStdOutput = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
if (INVALID_HANDLE_VALUE != this->startupInfo.hStdOutput)
|
||||
{
|
||||
CloseHandle(this->startupInfo.hStdOutput);
|
||||
this->startupInfo.hStdOutput = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
if (INVALID_HANDLE_VALUE != this->startupInfo.hStdError)
|
||||
{
|
||||
CloseHandle(this->startupInfo.hStdError);
|
||||
this->startupInfo.hStdError = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
if (INVALID_HANDLE_VALUE != this->startupInfo.hStdError)
|
||||
{
|
||||
CloseHandle(this->startupInfo.hStdError);
|
||||
this->startupInfo.hStdError = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
return hr;
|
||||
return hr;
|
||||
}
|
||||
|
||||
CConnectionPool* CNodeProcess::GetConnectionPool()
|
||||
{
|
||||
return &this->connectionPool;
|
||||
return &this->connectionPool;
|
||||
}
|
||||
|
||||
char* CNodeProcess::TryGetLog(IHttpContext* context, DWORD* size)
|
||||
{
|
||||
HRESULT hr;
|
||||
HANDLE file = INVALID_HANDLE_VALUE;
|
||||
char* log = NULL;
|
||||
*size = 0;
|
||||
PWSTR currentDirectory;
|
||||
DWORD currentDirectorySize;
|
||||
PWSTR logRelativeDirectory;
|
||||
DWORD logRelativeDirectoryLength;
|
||||
PWSTR logName;
|
||||
HANDLE findHandle = INVALID_HANDLE_VALUE;
|
||||
WIN32_FIND_DATAW findData;
|
||||
WCHAR tmp[64];
|
||||
DWORD computerNameSize;
|
||||
HRESULT hr;
|
||||
HANDLE file = INVALID_HANDLE_VALUE;
|
||||
char* log = NULL;
|
||||
*size = 0;
|
||||
PWSTR currentDirectory;
|
||||
DWORD currentDirectorySize;
|
||||
PWSTR logRelativeDirectory;
|
||||
DWORD logRelativeDirectoryLength;
|
||||
PWSTR logName;
|
||||
HANDLE findHandle = INVALID_HANDLE_VALUE;
|
||||
WIN32_FIND_DATAW findData;
|
||||
WCHAR tmp[64];
|
||||
DWORD computerNameSize;
|
||||
|
||||
// establish the log file directory name by composing the directory
|
||||
// of the script with the relative log directory name
|
||||
// establish the log file directory name by composing the directory
|
||||
// of the script with the relative log directory name
|
||||
|
||||
currentDirectory = (PWSTR)context->GetScriptTranslated(¤tDirectorySize);
|
||||
while (currentDirectorySize && currentDirectory[currentDirectorySize] != L'\\' && currentDirectory[currentDirectorySize] != L'/')
|
||||
currentDirectorySize--;
|
||||
logRelativeDirectory = CModuleConfiguration::GetLogDirectory(context);
|
||||
logRelativeDirectoryLength = wcslen(logRelativeDirectory);
|
||||
ErrorIf(NULL == (logName = (WCHAR*)context->AllocateRequestMemory((currentDirectorySize + logRelativeDirectoryLength + 256) * sizeof WCHAR)),
|
||||
ERROR_NOT_ENOUGH_MEMORY);
|
||||
wcsncpy(logName, currentDirectory, currentDirectorySize + 1);
|
||||
logName[currentDirectorySize + 1] = L'\0';
|
||||
wcscat(logName, logRelativeDirectory);
|
||||
if (logRelativeDirectoryLength && logRelativeDirectory[logRelativeDirectoryLength - 1] != L'\\')
|
||||
{
|
||||
wcscat(logName, L"\\");
|
||||
}
|
||||
currentDirectorySize = wcslen(logName);
|
||||
currentDirectory = (PWSTR)context->GetScriptTranslated(¤tDirectorySize);
|
||||
while (currentDirectorySize && currentDirectory[currentDirectorySize] != L'\\' && currentDirectory[currentDirectorySize] != L'/')
|
||||
currentDirectorySize--;
|
||||
logRelativeDirectory = CModuleConfiguration::GetLogDirectory(context);
|
||||
logRelativeDirectoryLength = wcslen(logRelativeDirectory);
|
||||
ErrorIf(NULL == (logName = (WCHAR*)context->AllocateRequestMemory((currentDirectorySize + logRelativeDirectoryLength + 256) * sizeof WCHAR)),
|
||||
ERROR_NOT_ENOUGH_MEMORY);
|
||||
wcsncpy(logName, currentDirectory, currentDirectorySize + 1);
|
||||
logName[currentDirectorySize + 1] = L'\0';
|
||||
wcscat(logName, logRelativeDirectory);
|
||||
if (logRelativeDirectoryLength && logRelativeDirectory[logRelativeDirectoryLength - 1] != L'\\')
|
||||
{
|
||||
wcscat(logName, L"\\");
|
||||
}
|
||||
currentDirectorySize = wcslen(logName);
|
||||
|
||||
// construct a wildcard stderr log file name from computer name and PID
|
||||
// construct a wildcard stderr log file name from computer name and PID
|
||||
|
||||
computerNameSize = GetEnvironmentVariableW(L"COMPUTERNAME", tmp, 64);
|
||||
ErrorIf(0 == computerNameSize, GetLastError());
|
||||
ErrorIf(64 < computerNameSize, E_FAIL);
|
||||
wcscat(logName, tmp);
|
||||
swprintf(tmp, L"-%d-stderr-*.txt", this->pid);
|
||||
wcscat(logName, tmp);
|
||||
|
||||
// find a file matching the wildcard name
|
||||
computerNameSize = GetEnvironmentVariableW(L"COMPUTERNAME", tmp, 64);
|
||||
ErrorIf(0 == computerNameSize, GetLastError());
|
||||
ErrorIf(64 < computerNameSize, E_FAIL);
|
||||
wcscat(logName, tmp);
|
||||
swprintf(tmp, L"-%d-stderr-*.txt", this->pid);
|
||||
wcscat(logName, tmp);
|
||||
|
||||
// find a file matching the wildcard name
|
||||
|
||||
ErrorIf(INVALID_HANDLE_VALUE == (findHandle = FindFirstFileW(logName, &findData)), GetLastError());
|
||||
FindClose(findHandle);
|
||||
findHandle = INVALID_HANDLE_VALUE;
|
||||
ErrorIf(INVALID_HANDLE_VALUE == (findHandle = FindFirstFileW(logName, &findData)), GetLastError());
|
||||
FindClose(findHandle);
|
||||
findHandle = INVALID_HANDLE_VALUE;
|
||||
|
||||
// construct the actual log file name to read
|
||||
// construct the actual log file name to read
|
||||
|
||||
logName[currentDirectorySize] = L'\0';
|
||||
wcscat(logName, findData.cFileName);
|
||||
logName[currentDirectorySize] = L'\0';
|
||||
wcscat(logName, findData.cFileName);
|
||||
|
||||
// read the log file
|
||||
// read the log file
|
||||
|
||||
ErrorIf(INVALID_HANDLE_VALUE == (file = CreateFileW(
|
||||
logName,
|
||||
GENERIC_READ,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
0,
|
||||
NULL)), GetLastError());
|
||||
ErrorIf(INVALID_HANDLE_VALUE == (file = CreateFileW(
|
||||
logName,
|
||||
GENERIC_READ,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
0,
|
||||
NULL)), GetLastError());
|
||||
|
||||
ErrorIf(INVALID_FILE_SIZE == (*size = GetFileSize(file, NULL)), GetLastError());
|
||||
ErrorIf(INVALID_FILE_SIZE == (*size = GetFileSize(file, NULL)), GetLastError());
|
||||
|
||||
if (*size > 65536)
|
||||
{
|
||||
// if log is larger than 64k, return only the last 64k
|
||||
if (*size > 65536)
|
||||
{
|
||||
// if log is larger than 64k, return only the last 64k
|
||||
|
||||
*size = 65536;
|
||||
ErrorIf(INVALID_SET_FILE_POINTER == SetFilePointer(file, *size, NULL, FILE_END), GetLastError());
|
||||
}
|
||||
*size = 65536;
|
||||
ErrorIf(INVALID_SET_FILE_POINTER == SetFilePointer(file, *size, NULL, FILE_END), GetLastError());
|
||||
}
|
||||
|
||||
ErrorIf(NULL == (log = (char*)context->AllocateRequestMemory(*size)), ERROR_NOT_ENOUGH_MEMORY);
|
||||
ErrorIf(0 == ReadFile(file, log, *size, size, NULL), GetLastError());
|
||||
ErrorIf(NULL == (log = (char*)context->AllocateRequestMemory(*size)), ERROR_NOT_ENOUGH_MEMORY);
|
||||
ErrorIf(0 == ReadFile(file, log, *size, size, NULL), GetLastError());
|
||||
|
||||
CloseHandle(file);
|
||||
file = INVALID_HANDLE_VALUE;
|
||||
CloseHandle(file);
|
||||
file = INVALID_HANDLE_VALUE;
|
||||
|
||||
return log;
|
||||
return log;
|
||||
|
||||
Error:
|
||||
|
||||
if (INVALID_HANDLE_VALUE != file)
|
||||
{
|
||||
CloseHandle(file);
|
||||
file = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
if (INVALID_HANDLE_VALUE != file)
|
||||
{
|
||||
CloseHandle(file);
|
||||
file = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
if (INVALID_HANDLE_VALUE != findHandle)
|
||||
{
|
||||
FindClose(findHandle);
|
||||
findHandle = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
if (INVALID_HANDLE_VALUE != findHandle)
|
||||
{
|
||||
FindClose(findHandle);
|
||||
findHandle = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
// log does not need to be freed - IIS will take care of it when IHttpContext is disposed
|
||||
// log does not need to be freed - IIS will take care of it when IHttpContext is disposed
|
||||
|
||||
*size = 0;
|
||||
*size = 0;
|
||||
|
||||
return NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -154,7 +154,7 @@ HRESULT CNodeProcessManager::Dispatch(CNodeHttpStoredContext* request)
|
|||
|
||||
if (request)
|
||||
{
|
||||
this->GetEventProvider()->Log(L"iisnode failed to accept a request beacuse the application is recycling", WINEVENT_LEVEL_ERROR, request->GetActivityId());
|
||||
this->GetEventProvider()->Log(request->GetHttpContext(), L"iisnode failed to accept a request beacuse the application is recycling", WINEVENT_LEVEL_ERROR, request->GetActivityId());
|
||||
CProtocolBridge::SendEmptyResponse(request, 503, CNodeConstants::IISNODE_ERROR_FAILED_ACCEPT_REQUEST_APP_RECYCLE, _T("Service Unavailable"), IISNODE_ERROR_APPLICATION_IS_RECYCLING);
|
||||
}
|
||||
|
||||
|
@ -163,7 +163,7 @@ HRESULT CNodeProcessManager::Dispatch(CNodeHttpStoredContext* request)
|
|||
return S_OK;
|
||||
Error:
|
||||
|
||||
this->GetEventProvider()->Log(
|
||||
this->GetEventProvider()->Log(request->GetHttpContext(),
|
||||
L"iisnode failed to initiate processing of a request", WINEVENT_LEVEL_ERROR);
|
||||
|
||||
if (!CProtocolBridge::SendIisnodeError(request, hr))
|
||||
|
|
|
@ -184,7 +184,7 @@ BOOL CProtocolBridge::SendIisnodeError(CNodeHttpStoredContext* ctx, HRESULT hr)
|
|||
{
|
||||
if (CProtocolBridge::SendIisnodeError(ctx->GetHttpContext(), hr))
|
||||
{
|
||||
ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
|
||||
ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(ctx->GetHttpContext(),
|
||||
L"iisnode request processing failed for reasons recognized by iisnode", WINEVENT_LEVEL_VERBOSE, ctx->GetActivityId());
|
||||
|
||||
if (INVALID_HANDLE_VALUE != ctx->GetPipe())
|
||||
|
@ -407,7 +407,7 @@ Error:
|
|||
|
||||
HRESULT CProtocolBridge::SendEmptyResponse(CNodeHttpStoredContext* context, USHORT status, USHORT subStatus, PCTSTR reason, HRESULT hresult, BOOL disableCache)
|
||||
{
|
||||
context->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
|
||||
context->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(context->GetHttpContext(),
|
||||
L"iisnode request processing failed for reasons unrecognized by iisnode", WINEVENT_LEVEL_VERBOSE, context->GetActivityId());
|
||||
|
||||
if (INVALID_HANDLE_VALUE != context->GetPipe())
|
||||
|
@ -567,12 +567,12 @@ void WINAPI CProtocolBridge::ChildContextCompleted(DWORD error, DWORD bytesTrans
|
|||
|
||||
if (S_OK == error)
|
||||
{
|
||||
ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
|
||||
ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(ctx->GetHttpContext(),
|
||||
L"iisnode finished processing child http request", WINEVENT_LEVEL_VERBOSE, ctx->GetActivityId());
|
||||
}
|
||||
else
|
||||
{
|
||||
ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
|
||||
ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(ctx->GetHttpContext(),
|
||||
L"iisnode failed to process child http request", WINEVENT_LEVEL_ERROR, ctx->GetActivityId());
|
||||
}
|
||||
|
||||
|
@ -632,9 +632,9 @@ void WINAPI CProtocolBridge::CreateNamedPipeConnection(DWORD error, DWORD bytesT
|
|||
|
||||
ctx->SetPipe(pipe);
|
||||
|
||||
ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
|
||||
ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(ctx->GetHttpContext(),
|
||||
L"iisnode created named pipe connection to the node.exe process", WINEVENT_LEVEL_VERBOSE, ctx->GetActivityId());
|
||||
|
||||
|
||||
CProtocolBridge::SendHttpRequestHeaders(ctx);
|
||||
|
||||
return;
|
||||
|
@ -647,13 +647,13 @@ Error:
|
|||
{
|
||||
if (hr == ERROR_PIPE_BUSY)
|
||||
{
|
||||
ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
|
||||
ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(ctx->GetHttpContext(),
|
||||
L"iisnode was unable to establish named pipe connection to the node.exe process because the named pipe server is too busy", WINEVENT_LEVEL_ERROR, ctx->GetActivityId());
|
||||
CProtocolBridge::SendEmptyResponse(ctx, 503, CNodeConstants::IISNODE_ERROR_PIPE_CONNECTION_TOO_BUSY, _T("Service Unavailable"), hr);
|
||||
}
|
||||
else
|
||||
{
|
||||
ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
|
||||
ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(ctx->GetHttpContext(),
|
||||
L"iisnode was unable to establish named pipe connection to the node.exe process", WINEVENT_LEVEL_ERROR, ctx->GetActivityId());
|
||||
CProtocolBridge::SendEmptyResponse( ctx,
|
||||
500,
|
||||
|
@ -667,7 +667,7 @@ Error:
|
|||
// the process has exited, likely due to initialization error
|
||||
// stop trying to establish the named pipe connection to minimize the failure latency
|
||||
|
||||
ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
|
||||
ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(ctx->GetHttpContext(),
|
||||
L"iisnode was unable to establish named pipe connection to the node.exe process before the process terminated", WINEVENT_LEVEL_ERROR, ctx->GetActivityId());
|
||||
CProtocolBridge::SendEmptyResponse( ctx,
|
||||
500,
|
||||
|
@ -678,7 +678,7 @@ Error:
|
|||
else
|
||||
{
|
||||
ctx->SetConnectionRetryCount(retry + 1);
|
||||
ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
|
||||
ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(ctx->GetHttpContext(),
|
||||
L"iisnode scheduled a retry of a named pipe connection to the node.exe process ", WINEVENT_LEVEL_INFO, ctx->GetActivityId());
|
||||
CProtocolBridge::PostponeProcessing(ctx, CModuleConfiguration::GetNamedPipeConnectionRetryDelay(ctx->GetHttpContext()));
|
||||
}
|
||||
|
@ -687,7 +687,7 @@ Error:
|
|||
{
|
||||
CloseHandle(pipe);
|
||||
pipe = INVALID_HANDLE_VALUE;
|
||||
ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
|
||||
ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(ctx->GetHttpContext(),
|
||||
L"iisnode was unable to configure the named pipe connection to the node.exe process", WINEVENT_LEVEL_ERROR, ctx->GetActivityId());
|
||||
CProtocolBridge::SendEmptyResponse( ctx,
|
||||
500,
|
||||
|
@ -752,7 +752,7 @@ void CProtocolBridge::SendHttpRequestHeaders(CNodeHttpStoredContext* context)
|
|||
{
|
||||
// completed synchronously
|
||||
|
||||
etw->Log(L"iisnode initiated sending http request headers to the node.exe process and completed synchronously",
|
||||
etw->Log(context->GetHttpContext(), L"iisnode initiated sending http request headers to the node.exe process and completed synchronously",
|
||||
WINEVENT_LEVEL_VERBOSE,
|
||||
&activityId);
|
||||
|
||||
|
@ -770,7 +770,7 @@ void CProtocolBridge::SendHttpRequestHeaders(CNodeHttpStoredContext* context)
|
|||
{
|
||||
// will complete asynchronously
|
||||
|
||||
etw->Log(L"iisnode initiated sending http request headers to the node.exe process and will complete asynchronously",
|
||||
etw->Log(context->GetHttpContext(), L"iisnode initiated sending http request headers to the node.exe process and will complete asynchronously",
|
||||
WINEVENT_LEVEL_VERBOSE,
|
||||
&activityId);
|
||||
}
|
||||
|
@ -788,7 +788,7 @@ void CProtocolBridge::SendHttpRequestHeaders(CNodeHttpStoredContext* context)
|
|||
}
|
||||
else
|
||||
{
|
||||
etw->Log(L"iisnode failed to initiate sending http request headers to the node.exe process",
|
||||
etw->Log(context->GetHttpContext(), L"iisnode failed to initiate sending http request headers to the node.exe process",
|
||||
WINEVENT_LEVEL_ERROR,
|
||||
&activityId);
|
||||
|
||||
|
@ -805,7 +805,7 @@ void CProtocolBridge::SendHttpRequestHeaders(CNodeHttpStoredContext* context)
|
|||
|
||||
Error:
|
||||
|
||||
etw->Log(L"iisnode failed to serialize http request headers",
|
||||
etw->Log(context->GetHttpContext(), L"iisnode failed to serialize http request headers",
|
||||
WINEVENT_LEVEL_ERROR,
|
||||
&activityId);
|
||||
|
||||
|
@ -824,7 +824,7 @@ void WINAPI CProtocolBridge::SendHttpRequestHeadersCompleted(DWORD error, DWORD
|
|||
CNodeHttpStoredContext* ctx = CNodeHttpStoredContext::Get(overlapped);
|
||||
|
||||
CheckError(error);
|
||||
ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
|
||||
ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(ctx->GetHttpContext(),
|
||||
L"iisnode finished sending http request headers to the node.exe process", WINEVENT_LEVEL_VERBOSE, ctx->GetActivityId());
|
||||
CProtocolBridge::ReadRequestBody(ctx);
|
||||
|
||||
|
@ -841,7 +841,7 @@ Error:
|
|||
}
|
||||
else
|
||||
{
|
||||
ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
|
||||
ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(ctx->GetHttpContext(),
|
||||
L"iisnode failed to send http request headers to the node.exe process", WINEVENT_LEVEL_ERROR, ctx->GetActivityId());
|
||||
CProtocolBridge::SendEmptyResponse( ctx,
|
||||
500,
|
||||
|
@ -883,7 +883,7 @@ void CProtocolBridge::ReadRequestBody(CNodeHttpStoredContext* context)
|
|||
|
||||
if (!completionPending)
|
||||
{
|
||||
context->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
|
||||
context->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(context->GetHttpContext(),
|
||||
L"iisnode initiated reading http request body chunk and completed synchronously", WINEVENT_LEVEL_VERBOSE, context->GetActivityId());
|
||||
|
||||
context->SetBytesCompleted(bytesReceived);
|
||||
|
@ -894,7 +894,7 @@ void CProtocolBridge::ReadRequestBody(CNodeHttpStoredContext* context)
|
|||
}
|
||||
else
|
||||
{
|
||||
context->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
|
||||
context->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(context->GetHttpContext(),
|
||||
L"iisnode initiated reading http request body chunk and will complete asynchronously", WINEVENT_LEVEL_VERBOSE, context->GetActivityId());
|
||||
}
|
||||
|
||||
|
@ -903,7 +903,7 @@ Error:
|
|||
|
||||
if (HRESULT_FROM_WIN32(ERROR_HANDLE_EOF) == hr)
|
||||
{
|
||||
context->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
|
||||
context->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(context->GetHttpContext(),
|
||||
L"iisnode detected the end of the http request body", WINEVENT_LEVEL_VERBOSE, context->GetActivityId());
|
||||
|
||||
if (context->GetIsUpgrade())
|
||||
|
@ -923,7 +923,7 @@ Error:
|
|||
}
|
||||
else
|
||||
{
|
||||
context->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
|
||||
context->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(context->GetHttpContext(),
|
||||
L"iisnode failed reading http request body", WINEVENT_LEVEL_ERROR, context->GetActivityId());
|
||||
|
||||
if (context->GetIsUpgrade())
|
||||
|
@ -949,13 +949,13 @@ void WINAPI CProtocolBridge::ReadRequestBodyCompleted(DWORD error, DWORD bytesTr
|
|||
|
||||
if (S_OK == error && bytesTransfered > 0)
|
||||
{
|
||||
ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
|
||||
ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(ctx->GetHttpContext(),
|
||||
L"iisnode read a chunk of http request body", WINEVENT_LEVEL_VERBOSE, ctx->GetActivityId());
|
||||
CProtocolBridge::SendRequestBody(ctx, bytesTransfered);
|
||||
}
|
||||
else if (ERROR_HANDLE_EOF == error || 0 == bytesTransfered)
|
||||
{
|
||||
ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
|
||||
ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(ctx->GetHttpContext(),
|
||||
L"iisnode detected the end of the http request body", WINEVENT_LEVEL_VERBOSE, ctx->GetActivityId());
|
||||
|
||||
if (ctx->GetIsUpgrade())
|
||||
|
@ -975,7 +975,7 @@ void WINAPI CProtocolBridge::ReadRequestBodyCompleted(DWORD error, DWORD bytesTr
|
|||
}
|
||||
else
|
||||
{
|
||||
ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
|
||||
ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(ctx->GetHttpContext(),
|
||||
L"iisnode failed reading http request body", WINEVENT_LEVEL_ERROR, ctx->GetActivityId());
|
||||
|
||||
if (ctx->GetIsUpgrade())
|
||||
|
@ -1060,7 +1060,7 @@ void CProtocolBridge::SendRequestBody(CNodeHttpStoredContext* context, DWORD chu
|
|||
{
|
||||
// completed synchronously
|
||||
|
||||
etw->Log(L"iisnode initiated sending http request body chunk to the node.exe process and completed synchronously",
|
||||
etw->Log(context->GetHttpContext(), L"iisnode initiated sending http request body chunk to the node.exe process and completed synchronously",
|
||||
WINEVENT_LEVEL_VERBOSE,
|
||||
&activityId);
|
||||
|
||||
|
@ -1079,7 +1079,7 @@ void CProtocolBridge::SendRequestBody(CNodeHttpStoredContext* context, DWORD chu
|
|||
{
|
||||
// will complete asynchronously
|
||||
|
||||
etw->Log(L"iisnode initiated sending http request body chunk to the node.exe process and will complete asynchronously",
|
||||
etw->Log(context->GetHttpContext(), L"iisnode initiated sending http request body chunk to the node.exe process and will complete asynchronously",
|
||||
WINEVENT_LEVEL_VERBOSE,
|
||||
&activityId);
|
||||
}
|
||||
|
@ -1090,7 +1090,7 @@ void CProtocolBridge::SendRequestBody(CNodeHttpStoredContext* context, DWORD chu
|
|||
// Ignore the write error and attempt to read the response instead (which might have been written by node.exe before the named pipe connection
|
||||
// was closed). This may also happen for WebSocket traffic.
|
||||
|
||||
etw->Log(L"iisnode detected the node.exe process closed the named pipe connection",
|
||||
etw->Log(context->GetHttpContext(), L"iisnode detected the node.exe process closed the named pipe connection",
|
||||
WINEVENT_LEVEL_VERBOSE,
|
||||
&activityId);
|
||||
|
||||
|
@ -1107,7 +1107,7 @@ void CProtocolBridge::SendRequestBody(CNodeHttpStoredContext* context, DWORD chu
|
|||
{
|
||||
// error
|
||||
|
||||
etw->Log(L"iisnode failed to initiate sending http request body chunk to the node.exe process",
|
||||
etw->Log(context->GetHttpContext(), L"iisnode failed to initiate sending http request body chunk to the node.exe process",
|
||||
WINEVENT_LEVEL_ERROR,
|
||||
&activityId);
|
||||
|
||||
|
@ -1135,13 +1135,13 @@ void WINAPI CProtocolBridge::SendRequestBodyCompleted(DWORD error, DWORD bytesTr
|
|||
|
||||
if (S_OK == error)
|
||||
{
|
||||
ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
|
||||
ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(ctx->GetHttpContext(),
|
||||
L"iisnode finished sending http request body chunk to the node.exe process", WINEVENT_LEVEL_VERBOSE, ctx->GetActivityId());
|
||||
CProtocolBridge::ReadRequestBody(ctx);
|
||||
}
|
||||
else
|
||||
{
|
||||
ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
|
||||
ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(ctx->GetHttpContext(),
|
||||
L"iisnode failed to send http request body chunk to the node.exe process", WINEVENT_LEVEL_ERROR, ctx->GetActivityId());
|
||||
|
||||
if (ctx->GetIsUpgrade())
|
||||
|
@ -1164,7 +1164,7 @@ void CProtocolBridge::StartReadResponse(CNodeHttpStoredContext* context)
|
|||
context->SetDataSize(0);
|
||||
context->SetParsingOffset(0);
|
||||
context->SetNextProcessor(CProtocolBridge::ProcessResponseStatusLine);
|
||||
context->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
|
||||
context->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(context->GetHttpContext(),
|
||||
L"iisnode starting to read http response", WINEVENT_LEVEL_VERBOSE, context->GetActivityId());
|
||||
CProtocolBridge::ContinueReadResponse(context);
|
||||
}
|
||||
|
@ -1188,7 +1188,7 @@ HRESULT CProtocolBridge::EnsureBuffer(CNodeHttpStoredContext* context)
|
|||
{
|
||||
// allocate more buffer memory
|
||||
|
||||
context->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
|
||||
context->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(context->GetHttpContext(),
|
||||
L"iisnode allocating more buffer memory to handle http response", WINEVENT_LEVEL_VERBOSE, context->GetActivityId());
|
||||
|
||||
DWORD* bufferLength = context->GetBufferSizeRef();
|
||||
|
@ -1242,7 +1242,7 @@ void CProtocolBridge::ContinueReadResponse(CNodeHttpStoredContext* context)
|
|||
{
|
||||
// read completed synchronously
|
||||
|
||||
etw->Log(L"iisnode initiated reading http response chunk and completed synchronously",
|
||||
etw->Log(context->GetHttpContext(), L"iisnode initiated reading http response chunk and completed synchronously",
|
||||
WINEVENT_LEVEL_VERBOSE,
|
||||
&activityId);
|
||||
|
||||
|
@ -1257,7 +1257,7 @@ void CProtocolBridge::ContinueReadResponse(CNodeHttpStoredContext* context)
|
|||
{
|
||||
// read will complete asynchronously
|
||||
|
||||
etw->Log(L"iisnode initiated reading http response chunk and will complete asynchronously",
|
||||
etw->Log(context->GetHttpContext(), L"iisnode initiated reading http response chunk and will complete asynchronously",
|
||||
WINEVENT_LEVEL_VERBOSE,
|
||||
&activityId);
|
||||
}
|
||||
|
@ -1271,7 +1271,7 @@ void CProtocolBridge::ContinueReadResponse(CNodeHttpStoredContext* context)
|
|||
{
|
||||
// error
|
||||
|
||||
etw->Log(L"iisnode failed to initialize reading of http response chunk",
|
||||
etw->Log(context->GetHttpContext(), L"iisnode failed to initialize reading of http response chunk",
|
||||
WINEVENT_LEVEL_ERROR,
|
||||
&activityId);
|
||||
|
||||
|
@ -1285,7 +1285,7 @@ void CProtocolBridge::ContinueReadResponse(CNodeHttpStoredContext* context)
|
|||
return;
|
||||
Error:
|
||||
|
||||
context->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
|
||||
context->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(context->GetHttpContext(),
|
||||
L"iisnode failed to allocate memory buffer to read http response chunk", WINEVENT_LEVEL_ERROR, &activityId);
|
||||
|
||||
CProtocolBridge::SendEmptyResponse( context,
|
||||
|
@ -1302,14 +1302,14 @@ void WINAPI CProtocolBridge::ProcessResponseStatusLine(DWORD error, DWORD bytesT
|
|||
HRESULT hr;
|
||||
CNodeHttpStoredContext* ctx = CNodeHttpStoredContext::Get(overlapped);
|
||||
|
||||
ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
|
||||
ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(ctx->GetHttpContext(),
|
||||
L"iisnode starting to process http response status line", WINEVENT_LEVEL_VERBOSE, ctx->GetActivityId());
|
||||
|
||||
CheckError(error);
|
||||
ctx->SetDataSize(ctx->GetDataSize() + bytesTransfered);
|
||||
CheckError(CHttpProtocol::ParseResponseStatusLine(ctx));
|
||||
|
||||
ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
|
||||
ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(ctx->GetHttpContext(),
|
||||
L"iisnode finished processing http response status line", WINEVENT_LEVEL_VERBOSE, ctx->GetActivityId());
|
||||
|
||||
ctx->SetNextProcessor(CProtocolBridge::ProcessResponseHeaders);
|
||||
|
@ -1324,7 +1324,7 @@ Error:
|
|||
}
|
||||
else
|
||||
{
|
||||
ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
|
||||
ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(ctx->GetHttpContext(),
|
||||
L"iisnode failed to process http response status line", WINEVENT_LEVEL_ERROR, ctx->GetActivityId());
|
||||
CProtocolBridge::SendEmptyResponse( ctx,
|
||||
500,
|
||||
|
@ -1455,7 +1455,7 @@ void WINAPI CProtocolBridge::ProcessResponseHeaders(DWORD error, DWORD bytesTran
|
|||
PCSTR contentLength;
|
||||
USHORT contentLengthLength;
|
||||
|
||||
ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
|
||||
ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(ctx->GetHttpContext(),
|
||||
L"iisnode starting to process http response headers", WINEVENT_LEVEL_VERBOSE, ctx->GetActivityId());
|
||||
|
||||
CheckError(error);
|
||||
|
@ -1469,7 +1469,7 @@ void WINAPI CProtocolBridge::ProcessResponseHeaders(DWORD error, DWORD bytesTran
|
|||
|
||||
if (!ctx->GetExpectResponseBody())
|
||||
{
|
||||
ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
|
||||
ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(ctx->GetHttpContext(),
|
||||
L"iisnode determined the HTTP response does not have entity body", WINEVENT_LEVEL_VERBOSE, ctx->GetActivityId());
|
||||
|
||||
CProtocolBridge::FinalizeResponse(ctx);
|
||||
|
@ -1518,7 +1518,7 @@ void WINAPI CProtocolBridge::ProcessResponseHeaders(DWORD error, DWORD bytesTran
|
|||
}
|
||||
}
|
||||
|
||||
ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
|
||||
ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(ctx->GetHttpContext(),
|
||||
L"iisnode finished processing http response headers", WINEVENT_LEVEL_VERBOSE, ctx->GetActivityId());
|
||||
|
||||
ctx->GetAsyncContext()->completionProcessor(S_OK, 0, ctx->GetOverlapped());
|
||||
|
@ -1533,7 +1533,7 @@ Error:
|
|||
}
|
||||
else
|
||||
{
|
||||
ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
|
||||
ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(ctx->GetHttpContext(),
|
||||
L"iisnode failed to process http response headers", WINEVENT_LEVEL_ERROR, ctx->GetActivityId());
|
||||
CProtocolBridge::SendEmptyResponse( ctx,
|
||||
500,
|
||||
|
@ -1550,7 +1550,7 @@ void WINAPI CProtocolBridge::ProcessChunkHeader(DWORD error, DWORD bytesTransfer
|
|||
HRESULT hr;
|
||||
CNodeHttpStoredContext* ctx = CNodeHttpStoredContext::Get(overlapped);
|
||||
|
||||
ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
|
||||
ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(ctx->GetHttpContext(),
|
||||
L"iisnode starting to process http response body chunk header", WINEVENT_LEVEL_VERBOSE, ctx->GetActivityId());
|
||||
|
||||
CheckError(error);
|
||||
|
@ -1558,7 +1558,7 @@ void WINAPI CProtocolBridge::ProcessChunkHeader(DWORD error, DWORD bytesTransfer
|
|||
ctx->SetDataSize(ctx->GetDataSize() + bytesTransfered);
|
||||
CheckError(CHttpProtocol::ParseChunkHeader(ctx));
|
||||
|
||||
ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
|
||||
ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(ctx->GetHttpContext(),
|
||||
L"iisnode finished processing http response body chunk header", WINEVENT_LEVEL_VERBOSE, ctx->GetActivityId());
|
||||
|
||||
ctx->SetNextProcessor(CProtocolBridge::ProcessResponseBody);
|
||||
|
@ -1574,7 +1574,7 @@ Error:
|
|||
}
|
||||
else
|
||||
{
|
||||
ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
|
||||
ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(ctx->GetHttpContext(),
|
||||
L"iisnode failed to process response body chunk header", WINEVENT_LEVEL_ERROR, ctx->GetActivityId());
|
||||
CProtocolBridge::SendEmptyResponse( ctx,
|
||||
500,
|
||||
|
@ -1608,7 +1608,7 @@ void WINAPI CProtocolBridge::ProcessResponseBody(DWORD error, DWORD bytesTransfe
|
|||
DWORD bytesSent;
|
||||
BOOL completionExpected;
|
||||
|
||||
ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
|
||||
ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(ctx->GetHttpContext(),
|
||||
L"iisnode starting to process http response body", WINEVENT_LEVEL_VERBOSE, ctx->GetActivityId());
|
||||
|
||||
CheckError(error);
|
||||
|
@ -1652,7 +1652,7 @@ void WINAPI CProtocolBridge::ProcessResponseBody(DWORD error, DWORD bytesTransfe
|
|||
&bytesSent,
|
||||
&completionExpected));
|
||||
|
||||
ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
|
||||
ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(ctx->GetHttpContext(),
|
||||
L"iisnode started sending http response body chunk", WINEVENT_LEVEL_VERBOSE, ctx->GetActivityId());
|
||||
|
||||
if (!completionExpected)
|
||||
|
@ -1711,7 +1711,7 @@ Error:
|
|||
}
|
||||
else
|
||||
{
|
||||
ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
|
||||
ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(ctx->GetHttpContext(),
|
||||
L"iisnode failed to send http response body chunk", WINEVENT_LEVEL_ERROR, ctx->GetActivityId());
|
||||
|
||||
if (ctx->GetIsUpgrade())
|
||||
|
@ -1761,7 +1761,7 @@ void WINAPI CProtocolBridge::SendResponseBodyCompleted(DWORD error, DWORD bytesT
|
|||
// Flushing of chunked responses is enabled
|
||||
|
||||
ctx->SetNextProcessor(CProtocolBridge::ContinueProcessResponseBodyAfterPartialFlush);
|
||||
ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
|
||||
ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(ctx->GetHttpContext(),
|
||||
L"iisnode initiated flushing http response body chunk", WINEVENT_LEVEL_VERBOSE, ctx->GetActivityId());
|
||||
ctx->GetHttpContext()->GetResponse()->Flush(TRUE, TRUE, &bytesSent, &completionExpected);
|
||||
}
|
||||
|
@ -1775,7 +1775,7 @@ void WINAPI CProtocolBridge::SendResponseBodyCompleted(DWORD error, DWORD bytesT
|
|||
return;
|
||||
Error:
|
||||
|
||||
ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
|
||||
ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(ctx->GetHttpContext(),
|
||||
L"iisnode failed to flush http response body chunk", WINEVENT_LEVEL_ERROR, ctx->GetActivityId());
|
||||
|
||||
if (ctx->GetIsUpgrade())
|
||||
|
@ -1801,7 +1801,7 @@ void WINAPI CProtocolBridge::ProcessUpgradeResponse(DWORD error, DWORD bytesTran
|
|||
CNodeHttpStoredContext* ctx = CNodeHttpStoredContext::Get(overlapped);
|
||||
|
||||
ctx->SetNextProcessor(CProtocolBridge::ContinueProcessResponseBodyAfterPartialFlush);
|
||||
ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
|
||||
ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(ctx->GetHttpContext(),
|
||||
L"iisnode initiated flushing http upgrade response headers", WINEVENT_LEVEL_VERBOSE, ctx->GetActivityId());
|
||||
ctx->GetHttpContext()->GetResponse()->Flush(TRUE, TRUE, &bytesSent, &completionExpected);
|
||||
|
||||
|
@ -1829,7 +1829,7 @@ void WINAPI CProtocolBridge::ContinueProcessResponseBodyAfterPartialFlush(DWORD
|
|||
return;
|
||||
Error:
|
||||
|
||||
ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
|
||||
ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(ctx->GetHttpContext(),
|
||||
L"iisnode failed to flush http response body chunk", WINEVENT_LEVEL_ERROR, ctx->GetActivityId());
|
||||
CProtocolBridge::SendEmptyResponse( ctx,
|
||||
500,
|
||||
|
@ -1849,7 +1849,7 @@ void CProtocolBridge::FinalizeUpgradeResponse(CNodeHttpStoredContext* context, H
|
|||
{
|
||||
context->GetNodeProcess()->OnRequestCompleted(context);
|
||||
|
||||
context->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
|
||||
context->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(context->GetHttpContext(),
|
||||
L"iisnode finished processing both directions of upgraded http request/response", WINEVENT_LEVEL_VERBOSE, context->GetActivityId());
|
||||
|
||||
context->SetRequestNotificationStatus(RQ_NOTIFICATION_CONTINUE);
|
||||
|
@ -1860,7 +1860,7 @@ void CProtocolBridge::FinalizeUpgradeResponse(CNodeHttpStoredContext* context, H
|
|||
}
|
||||
else
|
||||
{
|
||||
context->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
|
||||
context->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(context->GetHttpContext(),
|
||||
L"iisnode finished processing one direction of upgraded http request/response", WINEVENT_LEVEL_VERBOSE, context->GetActivityId());
|
||||
|
||||
context->SetRequestNotificationStatus(RQ_NOTIFICATION_PENDING);
|
||||
|
@ -1869,7 +1869,8 @@ void CProtocolBridge::FinalizeUpgradeResponse(CNodeHttpStoredContext* context, H
|
|||
|
||||
void CProtocolBridge::FinalizeResponse(CNodeHttpStoredContext* context)
|
||||
{
|
||||
context->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
|
||||
context->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(context->GetHttpContext(),
|
||||
|
||||
L"iisnode finished processing http request/response", WINEVENT_LEVEL_VERBOSE, context->GetActivityId());
|
||||
|
||||
if (context->GetCloseConnection())
|
||||
|
|
|
@ -28,5 +28,76 @@ function main() {
|
|||
webSocketSection.overrideModeDefault = 'Allow';
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var traceFailedRequestsSection = ahwrite.GetAdminSection("system.webServer/tracing/traceFailedRequests", "MACHINE/WEBROOT/APPHOST");
|
||||
|
||||
var traceFailedRequestsCollection = traceFailedRequestsSection.Collection;
|
||||
|
||||
var addElementPos = FindElement(traceFailedRequestsCollection, "add", ["path", "*"]);
|
||||
if (addElementPos == -1) throw "Element not found!";
|
||||
var addElement = traceFailedRequestsCollection.Item(addElementPos);
|
||||
|
||||
|
||||
var traceAreasCollection = addElement.ChildElements.Item("traceAreas").Collection;
|
||||
|
||||
var addElement1Pos = FindElement(traceAreasCollection, "add", ["provider", "WWW Server"]);
|
||||
if (addElement1Pos == -1) throw "Element not found!";
|
||||
var addElement1 = traceAreasCollection.Item(addElement1Pos);
|
||||
|
||||
addElement1.Properties.Item("areas").Value = "Authentication,Security,Filter,StaticFile,CGI,Compression,Cache,RequestNotifications,Module,FastCGI,WebSocket,Rewrite,RequestRouting,iisnode";
|
||||
}
|
||||
catch(e)
|
||||
{
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var traceProviderDefinitionsSection = ahwrite.GetAdminSection("system.webServer/tracing/traceProviderDefinitions", "MACHINE/WEBROOT/APPHOST");
|
||||
|
||||
var traceProviderDefinitionsCollection = traceProviderDefinitionsSection.Collection;
|
||||
|
||||
var addElementPos = FindElement(traceProviderDefinitionsCollection, "add", ["name", "WWW Server"]);
|
||||
if (addElementPos == -1) throw "Element not found!";
|
||||
var addElement = traceProviderDefinitionsCollection.Item(addElementPos);
|
||||
|
||||
|
||||
var areasCollection = addElement.ChildElements.Item("areas").Collection;
|
||||
|
||||
var addElement1 = areasCollection.CreateNewElement("add");
|
||||
addElement1.Properties.Item("name").Value = "iisnode";
|
||||
addElement1.Properties.Item("value").Value = 32768;
|
||||
areasCollection.AddElement(addElement1);
|
||||
}
|
||||
catch(e)
|
||||
{
|
||||
}
|
||||
|
||||
ahwrite.CommitChanges();
|
||||
}
|
||||
|
||||
function FindElement(collection, elementTagName, valuesToMatch) {
|
||||
for (var i = 0; i < collection.Count; i++) {
|
||||
var element = collection.Item(i);
|
||||
|
||||
if (element.Name == elementTagName) {
|
||||
var matches = true;
|
||||
for (var iVal = 0; iVal < valuesToMatch.length; iVal += 2) {
|
||||
var property = element.GetPropertyByName(valuesToMatch[iVal]);
|
||||
var value = property.Value;
|
||||
if (value != null) {
|
||||
value = value.toString();
|
||||
}
|
||||
if (value != valuesToMatch[iVal + 1]) {
|
||||
matches = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (matches) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
|
@ -15,4 +15,84 @@ function main() {
|
|||
catch (e) {
|
||||
// nothing to remove or IIS Express had been uninstalled before iisnode
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var versionMgr = new ActiveXObject("Microsoft.ApplicationHost.WritableAdminManager");
|
||||
var iisex = versionMgr.GetVersionObject("7.5", 2);
|
||||
var ahwrite = iisex.CreateObjectFromProgId("Microsoft.ApplicationHost.WritableAdminManager");
|
||||
var traceFailedRequestsSection = ahwrite.GetAdminSection("system.webServer/tracing/traceFailedRequests", "MACHINE/WEBROOT/APPHOST");
|
||||
|
||||
var traceFailedRequestsCollection = traceFailedRequestsSection.Collection;
|
||||
|
||||
var addElementPos = FindElement(traceFailedRequestsCollection, "add", ["path", "*"]);
|
||||
if (addElementPos == -1) throw "Element not found!";
|
||||
var addElement = traceFailedRequestsCollection.Item(addElementPos);
|
||||
|
||||
|
||||
var traceAreasCollection = addElement.ChildElements.Item("traceAreas").Collection;
|
||||
|
||||
var addElement1Pos = FindElement(traceAreasCollection, "add", ["provider", "WWW Server"]);
|
||||
if (addElement1Pos == -1) throw "Element not found!";
|
||||
var addElement1 = traceAreasCollection.Item(addElement1Pos);
|
||||
|
||||
addElement1.Properties.Item("areas").Value = "Authentication,Security,Filter,StaticFile,CGI,Compression,Cache,RequestNotifications,Module,FastCGI,WebSocket,Rewrite,RequestRouting";
|
||||
|
||||
ahwrite.CommitChanges();
|
||||
}
|
||||
catch(e) {
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var versionMgr = new ActiveXObject("Microsoft.ApplicationHost.WritableAdminManager");
|
||||
var iisex = versionMgr.GetVersionObject("7.5", 2);
|
||||
var ahwrite = iisex.CreateObjectFromProgId("Microsoft.ApplicationHost.WritableAdminManager");
|
||||
ahwrite.CommitPath = "MACHINE/WEBROOT/APPHOST";
|
||||
|
||||
var traceProviderDefinitionsSection = ahwrite.GetAdminSection("system.webServer/tracing/traceProviderDefinitions", "MACHINE/WEBROOT/APPHOST");
|
||||
|
||||
var traceProviderDefinitionsCollection = traceProviderDefinitionsSection.Collection;
|
||||
|
||||
var addElementPos = FindElement(traceProviderDefinitionsCollection, "add", ["name", "WWW Server"]);
|
||||
if (addElementPos == -1) throw "Element not found!";
|
||||
var addElement = traceProviderDefinitionsCollection.Item(addElementPos);
|
||||
|
||||
var areasCollection = addElement.ChildElements.Item("areas").Collection;
|
||||
|
||||
var addElement1Pos = FindElement(areasCollection, "add", ["name", "iisnode"]);
|
||||
if (addElement1Pos == -1) throw "Element not found!";
|
||||
|
||||
areasCollection.DeleteElement(addElement1Pos);
|
||||
|
||||
ahwrite.CommitChanges();
|
||||
}
|
||||
catch(e) {
|
||||
}
|
||||
}
|
||||
|
||||
function FindElement(collection, elementTagName, valuesToMatch) {
|
||||
for (var i = 0; i < collection.Count; i++) {
|
||||
var element = collection.Item(i);
|
||||
|
||||
if (element.Name == elementTagName) {
|
||||
var matches = true;
|
||||
for (var iVal = 0; iVal < valuesToMatch.length; iVal += 2) {
|
||||
var property = element.GetPropertyByName(valuesToMatch[iVal]);
|
||||
var value = property.Value;
|
||||
if (value != null) {
|
||||
value = value.toString();
|
||||
}
|
||||
if (value != valuesToMatch[iVal + 1]) {
|
||||
matches = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (matches) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
|
@ -1,8 +1,6 @@
|
|||
// Installs iisnode configuration section into system.webServer section group in
|
||||
// %systemroot%\system32\inetsrv\config\applicationHost.config (IIS)
|
||||
|
||||
// http://www.ksingla.net/2007/02/using_ahadmin_to_read_write_iis_configuration_part_2/
|
||||
|
||||
function main() {
|
||||
var ahwrite = new ActiveXObject("Microsoft.ApplicationHost.WritableAdminManager");
|
||||
var configManager = ahwrite.ConfigManager;
|
||||
|
@ -28,5 +26,76 @@ function main() {
|
|||
webSocketSection.overrideModeDefault = 'Allow';
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var traceFailedRequestsSection = ahwrite.GetAdminSection("system.webServer/tracing/traceFailedRequests", "MACHINE/WEBROOT/APPHOST");
|
||||
|
||||
var traceFailedRequestsCollection = traceFailedRequestsSection.Collection;
|
||||
|
||||
var addElementPos = FindElement(traceFailedRequestsCollection, "add", ["path", "*"]);
|
||||
if (addElementPos == -1) throw "Element not found!";
|
||||
var addElement = traceFailedRequestsCollection.Item(addElementPos);
|
||||
|
||||
|
||||
var traceAreasCollection = addElement.ChildElements.Item("traceAreas").Collection;
|
||||
|
||||
var addElement1Pos = FindElement(traceAreasCollection, "add", ["provider", "WWW Server"]);
|
||||
if (addElement1Pos == -1) throw "Element not found!";
|
||||
var addElement1 = traceAreasCollection.Item(addElement1Pos);
|
||||
|
||||
addElement1.Properties.Item("areas").Value = "Authentication,Security,Filter,StaticFile,CGI,Compression,Cache,RequestNotifications,Module,FastCGI,WebSocket,Rewrite,RequestRouting,iisnode";
|
||||
}
|
||||
catch(e)
|
||||
{
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var traceProviderDefinitionsSection = ahwrite.GetAdminSection("system.webServer/tracing/traceProviderDefinitions", "MACHINE/WEBROOT/APPHOST");
|
||||
|
||||
var traceProviderDefinitionsCollection = traceProviderDefinitionsSection.Collection;
|
||||
|
||||
var addElementPos = FindElement(traceProviderDefinitionsCollection, "add", ["name", "WWW Server"]);
|
||||
if (addElementPos == -1) throw "Element not found!";
|
||||
var addElement = traceProviderDefinitionsCollection.Item(addElementPos);
|
||||
|
||||
|
||||
var areasCollection = addElement.ChildElements.Item("areas").Collection;
|
||||
|
||||
var addElement1 = areasCollection.CreateNewElement("add");
|
||||
addElement1.Properties.Item("name").Value = "iisnode";
|
||||
addElement1.Properties.Item("value").Value = 32768;
|
||||
areasCollection.AddElement(addElement1);
|
||||
}
|
||||
catch(e)
|
||||
{
|
||||
}
|
||||
|
||||
ahwrite.CommitChanges();
|
||||
}
|
||||
|
||||
function FindElement(collection, elementTagName, valuesToMatch) {
|
||||
for (var i = 0; i < collection.Count; i++) {
|
||||
var element = collection.Item(i);
|
||||
|
||||
if (element.Name == elementTagName) {
|
||||
var matches = true;
|
||||
for (var iVal = 0; iVal < valuesToMatch.length; iVal += 2) {
|
||||
var property = element.GetPropertyByName(valuesToMatch[iVal]);
|
||||
var value = property.Value;
|
||||
if (value != null) {
|
||||
value = value.toString();
|
||||
}
|
||||
if (value != valuesToMatch[iVal + 1]) {
|
||||
matches = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (matches) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
|
@ -1,18 +1,94 @@
|
|||
// Removes iisnode configuration section from system.webServer section group in
|
||||
// %systemroot%\system32\inetsrv\config\applicationHost.config (IIS)
|
||||
|
||||
// http://www.ksingla.net/2007/02/using_ahadmin_to_read_write_iis_configuration_part_2/
|
||||
|
||||
function main() {
|
||||
var ahwrite = new ActiveXObject("Microsoft.ApplicationHost.WritableAdminManager");
|
||||
var configManager = ahwrite.ConfigManager;
|
||||
var appHostConfig = configManager.GetConfigFile("MACHINE/WEBROOT/APPHOST");
|
||||
var systemWebServer = appHostConfig.RootSectionGroup.Item("system.webServer");
|
||||
try {
|
||||
var ahwrite = new ActiveXObject("Microsoft.ApplicationHost.WritableAdminManager");
|
||||
var configManager = ahwrite.ConfigManager;
|
||||
var appHostConfig = configManager.GetConfigFile("MACHINE/WEBROOT/APPHOST");
|
||||
var systemWebServer = appHostConfig.RootSectionGroup.Item("system.webServer");
|
||||
systemWebServer.Sections.DeleteSection("iisnode");
|
||||
ahwrite.CommitChanges();
|
||||
}
|
||||
catch (e) {
|
||||
// nothing to remove
|
||||
}
|
||||
ahwrite.CommitChanges();
|
||||
|
||||
try
|
||||
{
|
||||
var adminManager = new ActiveXObject("Microsoft.ApplicationHost.WritableAdminManager");
|
||||
var traceFailedRequestsSection = adminManager.GetAdminSection("system.webServer/tracing/traceFailedRequests", "MACHINE/WEBROOT/APPHOST");
|
||||
|
||||
var traceFailedRequestsCollection = traceFailedRequestsSection.Collection;
|
||||
|
||||
var addElementPos = FindElement(traceFailedRequestsCollection, "add", ["path", "*"]);
|
||||
if (addElementPos == -1) throw "Element not found!";
|
||||
var addElement = traceFailedRequestsCollection.Item(addElementPos);
|
||||
|
||||
|
||||
var traceAreasCollection = addElement.ChildElements.Item("traceAreas").Collection;
|
||||
|
||||
var addElement1Pos = FindElement(traceAreasCollection, "add", ["provider", "WWW Server"]);
|
||||
if (addElement1Pos == -1) throw "Element not found!";
|
||||
var addElement1 = traceAreasCollection.Item(addElement1Pos);
|
||||
|
||||
addElement1.Properties.Item("areas").Value = "Authentication,Security,Filter,StaticFile,CGI,Compression,Cache,RequestNotifications,Module,FastCGI,WebSocket,Rewrite,RequestRouting";
|
||||
|
||||
adminManager.CommitChanges();
|
||||
}
|
||||
catch(e) {
|
||||
// nothing to remove
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var adminManager = new ActiveXObject('Microsoft.ApplicationHost.WritableAdminManager');
|
||||
adminManager.CommitPath = "MACHINE/WEBROOT/APPHOST";
|
||||
|
||||
var traceProviderDefinitionsSection = adminManager.GetAdminSection("system.webServer/tracing/traceProviderDefinitions", "MACHINE/WEBROOT/APPHOST");
|
||||
|
||||
var traceProviderDefinitionsCollection = traceProviderDefinitionsSection.Collection;
|
||||
|
||||
var addElementPos = FindElement(traceProviderDefinitionsCollection, "add", ["name", "WWW Server"]);
|
||||
if (addElementPos == -1) throw "Element not found!";
|
||||
var addElement = traceProviderDefinitionsCollection.Item(addElementPos);
|
||||
|
||||
var areasCollection = addElement.ChildElements.Item("areas").Collection;
|
||||
|
||||
var addElement1Pos = FindElement(areasCollection, "add", ["name", "iisnode"]);
|
||||
if (addElement1Pos == -1) throw "Element not found!";
|
||||
|
||||
areasCollection.DeleteElement(addElement1Pos);
|
||||
|
||||
adminManager.CommitChanges();
|
||||
}
|
||||
catch(e) {
|
||||
// nothing to remove
|
||||
}
|
||||
}
|
||||
|
||||
function FindElement(collection, elementTagName, valuesToMatch) {
|
||||
for (var i = 0; i < collection.Count; i++) {
|
||||
var element = collection.Item(i);
|
||||
|
||||
if (element.Name == elementTagName) {
|
||||
var matches = true;
|
||||
for (var iVal = 0; iVal < valuesToMatch.length; iVal += 2) {
|
||||
var property = element.GetPropertyByName(valuesToMatch[iVal]);
|
||||
var value = property.Value;
|
||||
if (value != null) {
|
||||
value = value.toString();
|
||||
}
|
||||
if (value != valuesToMatch[iVal + 1]) {
|
||||
matches = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (matches) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
|
@ -1 +1 @@
|
|||
0.2.14
|
||||
0.2.15
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
A simple test to see if recycle signal from node app worked.
|
||||
*/
|
||||
|
||||
var iisnodeassert = require("iisnodeassert")
|
||||
, assert = require('assert');
|
||||
|
||||
var firstPid = 0;
|
||||
var secondPid = 0;
|
||||
|
||||
iisnodeassert.sequence([
|
||||
iisnodeassert.get(10000, "/142_recycle_signal/hello.js", 200, "Hello, world!", function (res) {
|
||||
firstPid = res.headers['processpid'];
|
||||
console.log(firstPid);
|
||||
})
|
||||
]);
|
||||
|
||||
setTimeout(function() {
|
||||
iisnodeassert.sequence([
|
||||
iisnodeassert.get(10000, "/142_recycle_signal/hello.js", 200, "Hello, world!", function (res) {
|
||||
secondPid = res.headers['processpid'];
|
||||
console.log(secondPid);
|
||||
assert.ok( firstPid != secondPid, 'recycle was not successful');
|
||||
})
|
||||
]);
|
||||
}, 10000);
|
|
@ -0,0 +1,13 @@
|
|||
var http = require('http');
|
||||
var net = require('net');
|
||||
|
||||
http.createServer(function (req, res) {
|
||||
res.setHeader('processpid', process.pid);
|
||||
res.writeHead(200, {'Content-Type': 'text/html'});
|
||||
res.end('Hello, world!');
|
||||
setTimeout(function() {
|
||||
var stream = net.connect(process.env.IISNODE_CONTROL_PIPE);
|
||||
stream.write('recycle');
|
||||
stream.end();
|
||||
}, 3000);
|
||||
}).listen(process.env.PORT);
|
|
@ -0,0 +1,8 @@
|
|||
<configuration>
|
||||
<system.webServer>
|
||||
<handlers>
|
||||
<add name="iisnode" path="hello.js" verb="*" modules="iisnode" />
|
||||
</handlers>
|
||||
<iisnode recycleSignalEnabled="true" />
|
||||
</system.webServer>
|
||||
</configuration>
|
Загрузка…
Ссылка в новой задаче