From 66d9afdf873723c3f2d4903f4d308ba894fcb7e4 Mon Sep 17 00:00:00 2001 From: rramachand21 Date: Mon, 4 Aug 2014 09:46:13 -0700 Subject: [PATCH] iisnode events in FREB --- src/iisnode/chttpprotocol.cpp | 4 +- src/iisnode/cnodeapplication.cpp | 4 +- src/iisnode/cnodeapplicationmanager.cpp | 187 ++-- src/iisnode/cnodeapplicationmanager.h | 3 +- src/iisnode/cnodeeventprovider.cpp | 139 ++- src/iisnode/cnodeeventprovider.h | 155 ++- src/iisnode/cnodehttpmodule.cpp | 28 +- src/iisnode/cnodehttpstoredcontext.cpp | 336 +++---- src/iisnode/cnodeprocess.cpp | 906 +++++++++--------- src/iisnode/cnodeprocessmanager.cpp | 4 +- src/iisnode/cprotocolbridge.cpp | 113 +-- .../iisnode-express-msi/addiisnodesection.js | 71 ++ .../removeiisnodesection.js | 80 ++ src/setup/iisnode-msi/addiisnodesection.js | 73 +- src/setup/iisnode-msi/removeiisnodesection.js | 90 +- src/version.txt | 2 +- test/functional/tests/143_recycle_signal.js | 26 + .../www/142_recycle_signal/hello.js | 13 + .../www/142_recycle_signal/web.config | 8 + 19 files changed, 1414 insertions(+), 828 deletions(-) create mode 100644 test/functional/tests/143_recycle_signal.js create mode 100644 test/functional/www/142_recycle_signal/hello.js create mode 100644 test/functional/www/142_recycle_signal/web.config diff --git a/src/iisnode/chttpprotocol.cpp b/src/iisnode/chttpprotocol.cpp index 38fae8a3..4e70f92c 100644 --- a/src/iisnode/chttpprotocol.cpp +++ b/src/iisnode/chttpprotocol.cpp @@ -375,7 +375,7 @@ HRESULT CHttpProtocol::ParseResponseStatusLine(CNodeHttpStoredContext* context) 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 @@ HRESULT CHttpProtocol::ParseChunkHeader(CNodeHttpStoredContext* context) 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; diff --git a/src/iisnode/cnodeapplication.cpp b/src/iisnode/cnodeapplication.cpp index f3fa41ca..5a4e079b 100644 --- a/src/iisnode/cnodeapplication.cpp +++ b/src/iisnode/cnodeapplication.cpp @@ -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(); diff --git a/src/iisnode/cnodeapplicationmanager.cpp b/src/iisnode/cnodeapplicationmanager.cpp index e3ac4f83..4d3cd10e 100644 --- a/src/iisnode/cnodeapplicationmanager.cpp +++ b/src/iisnode/cnodeapplicationmanager.cpp @@ -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 @@ HRESULT CNodeApplicationManager::InitializeCore(IHttpContext* context) 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 @@ HRESULT CNodeApplicationManager::GetOrCreateNodeApplicationCore(PCWSTR physicalP 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 @@ HRESULT CNodeApplicationManager::GetOrCreateDebuggedNodeApplicationCore(PCWSTR p 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; } diff --git a/src/iisnode/cnodeapplicationmanager.h b/src/iisnode/cnodeapplicationmanager.h index 94058e08..a308d469 100644 --- a/src/iisnode/cnodeapplicationmanager.h +++ b/src/iisnode/cnodeapplicationmanager.h @@ -40,6 +40,7 @@ class CNodeApplicationManager HMODULE inspector; LONG totalRequests; + BOOL _fSignalPipeInitialized; HANDLE signalPipe; HANDLE controlSignalHandlerThread; LPWSTR signalPipeName; @@ -65,7 +66,7 @@ class CNodeApplicationManager 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: diff --git a/src/iisnode/cnodeeventprovider.cpp b/src/iisnode/cnodeeventprovider.cpp index 87f2331c..0d5b56f3 100644 --- a/src/iisnode/cnodeeventprovider.cpp +++ b/src/iisnode/cnodeeventprovider.cpp @@ -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) - { - FreeLibrary(this->advapi); - this->advapi = NULL; - } + if (this->advapi && this->eventUnregister && this->handle) + { + this->eventUnregister(this->handle); + this->handle = 0; + } + + 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; - - 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; + 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)); + } + } + + return S_OK; +Error: + 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; + return hr; } diff --git a/src/iisnode/cnodeeventprovider.h b/src/iisnode/cnodeeventprovider.h index 25388ee3..6bd03263 100644 --- a/src/iisnode/cnodeeventprovider.h +++ b/src/iisnode/cnodeeventprovider.h @@ -1,6 +1,9 @@ #ifndef __CNODEEVENTPROVIDER_H__ #define __CNODEEVENTPROVIDER_H__ +#include +#include + 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(); - HRESULT Initialize(); - bool IsEnabled(UCHAR level); - HRESULT Log(PCWSTR message, UCHAR level, GUID* activityId = NULL); + HRESULT Log(PCWSTR message, UCHAR level, GUID* activityId = NULL); + HRESULT Log(IHttpContext *context, PCWSTR message, UCHAR level, GUID* activityId = NULL); }; diff --git a/src/iisnode/cnodehttpmodule.cpp b/src/iisnode/cnodehttpmodule.cpp index 4be68f89..e391a0ad 100644 --- a/src/iisnode/cnodehttpmodule.cpp +++ b/src/iisnode/cnodehttpmodule.cpp @@ -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 @@ REQUEST_NOTIFICATION_STATUS CNodeHttpModule::OnExecuteRequestHandler( { 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 @@ REQUEST_NOTIFICATION_STATUS CNodeHttpModule::OnExecuteRequestHandler( { 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()); diff --git a/src/iisnode/cnodehttpstoredcontext.cpp b/src/iisnode/cnodehttpstoredcontext.cpp index 01ad9983..80fc9fef 100644 --- a/src/iisnode/cnodehttpstoredcontext.cpp +++ b/src/iisnode/cnodehttpstoredcontext.cpp @@ -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; } diff --git a/src/iisnode/cnodeprocess.cpp b/src/iisnode/cnodeprocess.cpp index dfcf579a..1ab6683d 100644 --- a/src/iisnode/cnodeprocess.cpp +++ b/src/iisnode/cnodeprocess.cpp @@ -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; - - 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 (!this->hasProcessExited) - { - WaitForSingleObject(this->processWatcher, INFINITE); - } - CloseHandle(this->processWatcher); - this->processWatcher = NULL; - } + this->isClosing = TRUE; + + 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 (!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); - - // initialize connection pool - - 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; - - // 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); - - // 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); - } - - 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"\""); + RtlZeroMemory(&processInformation, sizeof processInformation); + RtlZeroMemory(&startupInfo, sizeof startupInfo); + + // initialize connection pool + + 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; + + // 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); + + // 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); + } + + 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"\""); 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)); - - // 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'; - - // create startup info for the node.js process - - RtlZeroMemory(&this->startupInfo, sizeof this->startupInfo); - GetStartupInfoW(&startupInfo); - CheckError(this->CreateStdHandles(context)); - - // 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); - - // 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; - } - - 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())); - } - - 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); - - // clean up - - delete [] currentDirectory; - currentDirectory = NULL; - delete [] newEnvironment; - newEnvironment = NULL; - delete [] fullCommandLine; - fullCommandLine = NULL; - CloseHandle(processInformation.hThread); - processInformation.hThread = NULL; + &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) + + 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 + + RtlZeroMemory(&this->startupInfo, sizeof this->startupInfo); + GetStartupInfoW(&startupInfo); + CheckError(this->CreateStdHandles(context)); + + // 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); + + // 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; + } + + 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())); + } + + 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); + + // clean up + + 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); - } - - return S_OK; + 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; 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 (currentDirectory) - { - delete [] currentDirectory; - currentDirectory = NULL; - } + 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(pSignalPipeName) { @@ -262,315 +262,315 @@ HRESULT CNodeProcess::Initialize(IHttpContext* context) pSignalPipeName = NULL; } - if (suuid != NULL) - { - RpcStringFree(&suuid); - suuid = NULL; - } - - if (NULL != fullCommandLine) - { - delete[] fullCommandLine; - fullCommandLine = 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 != 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->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; - } - - return hr; + if (suuid != NULL) + { + RpcStringFree(&suuid); + suuid = NULL; + } + + if (NULL != fullCommandLine) + { + delete[] fullCommandLine; + fullCommandLine = 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 != 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->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; + } + + 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(); - - while (!process->isClosing && process->process) - { - waitResult = WaitForSingleObjectEx(process->process, INFINITE, TRUE); - if (process->process) - { + 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) + { 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 (!process->isClosing) - { - process->OnProcessExited(); - } - - return 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 (!process->isClosing) + { + process->OnProcessExited(); + } + + 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; - - HRESULT hr; - SECURITY_ATTRIBUTES security; - - // 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()); - - ErrorIf(0 == DuplicateHandle( - GetCurrentProcess(), - this->startupInfo.hStdOutput, - GetCurrentProcess(), - &this->startupInfo.hStdError, - 0, - TRUE, - DUPLICATE_SAME_ACCESS), - GetLastError()); - - return S_OK; + this->startupInfo.hStdError = this->startupInfo.hStdInput = this->startupInfo.hStdOutput = INVALID_HANDLE_VALUE; + this->startupInfo.dwFlags = STARTF_USESTDHANDLES; + + HRESULT hr; + SECURITY_ATTRIBUTES security; + + // 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()); + + ErrorIf(0 == DuplicateHandle( + GetCurrentProcess(), + this->startupInfo.hStdOutput, + GetCurrentProcess(), + &this->startupInfo.hStdError, + 0, + TRUE, + DUPLICATE_SAME_ACCESS), + GetLastError()); + + 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; - - // 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); - - // 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 - - ErrorIf(INVALID_HANDLE_VALUE == (findHandle = FindFirstFileW(logName, &findData)), GetLastError()); - FindClose(findHandle); - findHandle = INVALID_HANDLE_VALUE; - - // construct the actual log file name to read - - logName[currentDirectorySize] = L'\0'; - wcscat(logName, findData.cFileName); - - // 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_FILE_SIZE == (*size = GetFileSize(file, NULL)), GetLastError()); - - 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()); - } - - 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; - - return log; + 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 + + 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 + + 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; + + // construct the actual log file name to read + + logName[currentDirectorySize] = L'\0'; + wcscat(logName, findData.cFileName); + + // 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_FILE_SIZE == (*size = GetFileSize(file, NULL)), GetLastError()); + + 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()); + } + + 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; + + 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; } diff --git a/src/iisnode/cnodeprocessmanager.cpp b/src/iisnode/cnodeprocessmanager.cpp index cafb63c0..3bf18f14 100644 --- a/src/iisnode/cnodeprocessmanager.cpp +++ b/src/iisnode/cnodeprocessmanager.cpp @@ -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)) diff --git a/src/iisnode/cprotocolbridge.cpp b/src/iisnode/cprotocolbridge.cpp index 8db68e47..9071a639 100644 --- a/src/iisnode/cprotocolbridge.cpp +++ b/src/iisnode/cprotocolbridge.cpp @@ -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 @@ BOOL CProtocolBridge::SendDevError(CNodeHttpStoredContext* context, 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 @@ void WINAPI CProtocolBridge::CreateNamedPipeConnection(DWORD error, DWORD bytesT { 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 @@ void WINAPI CProtocolBridge::CreateNamedPipeConnection(DWORD error, DWORD bytesT // 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 @@ void WINAPI CProtocolBridge::CreateNamedPipeConnection(DWORD error, DWORD bytesT 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 @@ void WINAPI CProtocolBridge::CreateNamedPipeConnection(DWORD error, DWORD bytesT { 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 @@ void WINAPI CProtocolBridge::SendHttpRequestHeadersCompleted(DWORD error, DWORD } 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 @@ void CProtocolBridge::ReadRequestBody(CNodeHttpStoredContext* context) 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 @@ void CProtocolBridge::ReadRequestBody(CNodeHttpStoredContext* context) } 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 @@ void WINAPI CProtocolBridge::ProcessResponseStatusLine(DWORD error, DWORD bytesT } 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 @@ void WINAPI CProtocolBridge::ProcessResponseHeaders(DWORD error, DWORD bytesTran } 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 @@ void WINAPI CProtocolBridge::ProcessChunkHeader(DWORD error, DWORD bytesTransfer } 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 @@ void WINAPI CProtocolBridge::ProcessResponseBody(DWORD error, DWORD bytesTransfe } 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()) diff --git a/src/setup/iisnode-express-msi/addiisnodesection.js b/src/setup/iisnode-express-msi/addiisnodesection.js index ba5b7876..daf344b1 100644 --- a/src/setup/iisnode-express-msi/addiisnodesection.js +++ b/src/setup/iisnode-express-msi/addiisnodesection.js @@ -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; } \ No newline at end of file diff --git a/src/setup/iisnode-express-msi/removeiisnodesection.js b/src/setup/iisnode-express-msi/removeiisnodesection.js index 101c3429..d7c0c8aa 100644 --- a/src/setup/iisnode-express-msi/removeiisnodesection.js +++ b/src/setup/iisnode-express-msi/removeiisnodesection.js @@ -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; } \ No newline at end of file diff --git a/src/setup/iisnode-msi/addiisnodesection.js b/src/setup/iisnode-msi/addiisnodesection.js index af923449..47605e99 100644 --- a/src/setup/iisnode-msi/addiisnodesection.js +++ b/src/setup/iisnode-msi/addiisnodesection.js @@ -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; +} \ No newline at end of file diff --git a/src/setup/iisnode-msi/removeiisnodesection.js b/src/setup/iisnode-msi/removeiisnodesection.js index 896c45ae..de5cd82c 100644 --- a/src/setup/iisnode-msi/removeiisnodesection.js +++ b/src/setup/iisnode-msi/removeiisnodesection.js @@ -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; } \ No newline at end of file diff --git a/src/version.txt b/src/version.txt index a17709ec..ad8696b4 100644 --- a/src/version.txt +++ b/src/version.txt @@ -1 +1 @@ -0.2.14 +0.2.15 diff --git a/test/functional/tests/143_recycle_signal.js b/test/functional/tests/143_recycle_signal.js new file mode 100644 index 00000000..ce070023 --- /dev/null +++ b/test/functional/tests/143_recycle_signal.js @@ -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); \ No newline at end of file diff --git a/test/functional/www/142_recycle_signal/hello.js b/test/functional/www/142_recycle_signal/hello.js new file mode 100644 index 00000000..5de0f43b --- /dev/null +++ b/test/functional/www/142_recycle_signal/hello.js @@ -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); \ No newline at end of file diff --git a/test/functional/www/142_recycle_signal/web.config b/test/functional/www/142_recycle_signal/web.config new file mode 100644 index 00000000..255a95d9 --- /dev/null +++ b/test/functional/www/142_recycle_signal/web.config @@ -0,0 +1,8 @@ + + + + + + + +