From 83879dfefab6b0bdd9f8dbe280a99a40c861c23e Mon Sep 17 00:00:00 2001 From: Ranjith Ramachandra Date: Thu, 21 Apr 2016 12:47:57 -0700 Subject: [PATCH 01/17] iisnode-debug.html --- iisnode-debug.html | 163 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 163 insertions(+) create mode 100644 iisnode-debug.html diff --git a/iisnode-debug.html b/iisnode-debug.html new file mode 100644 index 00000000..88fe9cf3 --- /dev/null +++ b/iisnode-debug.html @@ -0,0 +1,163 @@ + + + iisnode-debug + + + +

HTTP response diagnostics for iisnode

+ +

This request

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Processing time [ms]N/A
Named pipe connection retry countN/A
HRESULTN/A
Server DNS nameN/A
w3wp.exe PIDN/A
node.exe PIDN/A
+ +

Memory

+ + Memory consumption chart + +

Counters

+ + + + + + + + + + + + + + + + + + +
Active node.exe processes serving this applicationN/A
Active HTTP requests in this applicationN/A
Active HTTP requests in this node.exe processN/A
Total node.js requests processed by w3wp.exeN/A
+ +

Environment

+ + + + + + + + + + + + + + +
Version of iisnodeN/A
Server full DNS nameN/A
Full node.exe pathN/A
+ +

Actions

+ + Bugs, feedback, questions
+ iisnode project home page
+ + Debug node.js applications hosted in IIS using iisnode +
+ + Use Event Tracing for Windows (ETW) to get more diagnostics information +
+ + Windows Azure node.js developer center + + + + + \ No newline at end of file From 5a1dba67822abc03c6ed0ae5d5746988eb3170d9 Mon Sep 17 00:00:00 2001 From: Ranjith Ramachandra Date: Thu, 21 Apr 2016 12:51:50 -0700 Subject: [PATCH 02/17] Update iisnode-debug.html --- iisnode-debug.html | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/iisnode-debug.html b/iisnode-debug.html index 88fe9cf3..577b4512 100644 --- a/iisnode-debug.html +++ b/iisnode-debug.html @@ -1,3 +1,4 @@ + iisnode-debug @@ -160,4 +161,4 @@

Actions

- \ No newline at end of file + From 4d633eee5441fccdab7294db5e7e517f8fbe70a0 Mon Sep 17 00:00:00 2001 From: Ranjith Ramachandra Date: Thu, 21 Apr 2016 12:52:30 -0700 Subject: [PATCH 03/17] Rename iisnode-debug.html to index.html --- iisnode-debug.html => index.html | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename iisnode-debug.html => index.html (100%) diff --git a/iisnode-debug.html b/index.html similarity index 100% rename from iisnode-debug.html rename to index.html From b3058d6697484cc806146fdd998348943ca600e4 Mon Sep 17 00:00:00 2001 From: Ranjith Mukkai Ramachandra Date: Thu, 9 Jun 2016 13:44:01 -0700 Subject: [PATCH 04/17] Fix env variables allocation issue --- src/iisnode/cmoduleconfiguration.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/iisnode/cmoduleconfiguration.cpp b/src/iisnode/cmoduleconfiguration.cpp index 46c0f538..b2979cba 100644 --- a/src/iisnode/cmoduleconfiguration.cpp +++ b/src/iisnode/cmoduleconfiguration.cpp @@ -187,7 +187,7 @@ HRESULT CModuleConfiguration::CreateNodeEnvironment(IHttpContext* ctx, DWORD deb // allocate memory for new environment variables - tmpSize = 32767 - environmentSize; + tmpSize = 65536; // hard coded for now, change this to auto allocate based on the values. ErrorIf(NULL == (tmpIndex = tmpStart = new char[tmpSize]), ERROR_NOT_ENOUGH_MEMORY); RtlZeroMemory(tmpIndex, tmpSize); From 8f9d43a61dd48fe0322eedf020aae457bfba3ea4 Mon Sep 17 00:00:00 2001 From: Ranjith Mukkai Ramachandra Date: Sun, 19 Feb 2017 11:18:16 -0800 Subject: [PATCH 05/17] fix w3wp crashes --- src/config/iisnode_dev_x64.xml | 3 +- src/config/iisnode_dev_x86_on_x64.xml | 3 +- src/config/iisnode_dev_x86_on_x86.xml | 3 +- src/config/iisnode_express_schema.xml | 3 +- src/config/iisnode_express_schema_x64.xml | 3 +- src/config/iisnode_schema.xml | 3 +- src/config/iisnode_schema_x64.xml | 3 +- src/iisnode/casyncmanager.cpp | 33 ++- src/iisnode/casyncmanager.h | 11 +- src/iisnode/cmoduleconfiguration.cpp | 22 +- src/iisnode/cmoduleconfiguration.h | 2 + src/iisnode/cnodeeventprovider.cpp | 4 + src/iisnode/cnodehttpmodule.cpp | 6 +- src/iisnode/cnodehttpstoredcontext.cpp | 6 +- src/iisnode/cnodehttpstoredcontext.h | 27 ++- src/iisnode/cnodeprocess.cpp | 12 + src/iisnode/cnodeprocessmanager.cpp | 101 ++++++++- src/iisnode/cnodeprocessmanager.h | 2 + src/iisnode/cprotocolbridge.cpp | 261 ++++++++++++++-------- src/iisnode/cprotocolbridge.h | 44 ++-- src/version.txt | 2 +- 21 files changed, 405 insertions(+), 149 deletions(-) diff --git a/src/config/iisnode_dev_x64.xml b/src/config/iisnode_dev_x64.xml index cab240cf..9d6a435c 100644 --- a/src/config/iisnode_dev_x64.xml +++ b/src/config/iisnode_dev_x64.xml @@ -32,7 +32,7 @@ Details at http://learn.iis.net/page.aspx/241/configuration-extensibility/ - + @@ -60,5 +60,6 @@ Details at http://learn.iis.net/page.aspx/241/configuration-extensibility/ + diff --git a/src/config/iisnode_dev_x86_on_x64.xml b/src/config/iisnode_dev_x86_on_x64.xml index aaa0bbc9..ab17fba8 100644 --- a/src/config/iisnode_dev_x86_on_x64.xml +++ b/src/config/iisnode_dev_x86_on_x64.xml @@ -32,7 +32,7 @@ Details at http://learn.iis.net/page.aspx/241/configuration-extensibility/ - + @@ -60,5 +60,6 @@ Details at http://learn.iis.net/page.aspx/241/configuration-extensibility/ + diff --git a/src/config/iisnode_dev_x86_on_x86.xml b/src/config/iisnode_dev_x86_on_x86.xml index 9606a25e..efab7f7d 100644 --- a/src/config/iisnode_dev_x86_on_x86.xml +++ b/src/config/iisnode_dev_x86_on_x86.xml @@ -32,7 +32,7 @@ Details at http://learn.iis.net/page.aspx/241/configuration-extensibility/ - + @@ -60,5 +60,6 @@ Details at http://learn.iis.net/page.aspx/241/configuration-extensibility/ + diff --git a/src/config/iisnode_express_schema.xml b/src/config/iisnode_express_schema.xml index 2ad9eddc..a6c95a85 100644 --- a/src/config/iisnode_express_schema.xml +++ b/src/config/iisnode_express_schema.xml @@ -32,7 +32,7 @@ Details at http://learn.iis.net/page.aspx/241/configuration-extensibility/ - + @@ -60,5 +60,6 @@ Details at http://learn.iis.net/page.aspx/241/configuration-extensibility/ + diff --git a/src/config/iisnode_express_schema_x64.xml b/src/config/iisnode_express_schema_x64.xml index ddf6368a..fb39746b 100644 --- a/src/config/iisnode_express_schema_x64.xml +++ b/src/config/iisnode_express_schema_x64.xml @@ -32,7 +32,7 @@ Details at http://learn.iis.net/page.aspx/241/configuration-extensibility/ - + @@ -60,5 +60,6 @@ Details at http://learn.iis.net/page.aspx/241/configuration-extensibility/ + diff --git a/src/config/iisnode_schema.xml b/src/config/iisnode_schema.xml index 4088c009..62e8004f 100644 --- a/src/config/iisnode_schema.xml +++ b/src/config/iisnode_schema.xml @@ -32,7 +32,7 @@ Details at http://learn.iis.net/page.aspx/241/configuration-extensibility/ - + @@ -60,5 +60,6 @@ Details at http://learn.iis.net/page.aspx/241/configuration-extensibility/ + diff --git a/src/config/iisnode_schema_x64.xml b/src/config/iisnode_schema_x64.xml index 8d454eae..f1561969 100644 --- a/src/config/iisnode_schema_x64.xml +++ b/src/config/iisnode_schema_x64.xml @@ -32,7 +32,7 @@ Details at http://learn.iis.net/page.aspx/241/configuration-extensibility/ - + @@ -60,5 +60,6 @@ Details at http://learn.iis.net/page.aspx/241/configuration-extensibility/ + diff --git a/src/iisnode/casyncmanager.cpp b/src/iisnode/casyncmanager.cpp index e0235e8b..50786340 100644 --- a/src/iisnode/casyncmanager.cpp +++ b/src/iisnode/casyncmanager.cpp @@ -4,14 +4,15 @@ extern RtlNtStatusToDosError pRtlNtStatusToDosError; void ASYNC_CONTEXT::RunSynchronousContinuations() { - while (this->continueSynchronously) + BOOL fCompletionPosted = FALSE; + while (!fCompletionPosted && this->continueSynchronously) { // The continueSynchronously is used to unwind the call stack // to avoid stack overflow in case of a synchronous IO completions this->continueSynchronously = FALSE; DWORD bytesCompleteted = this->bytesCompleteted; this->bytesCompleteted = 0; - this->completionProcessor(S_OK, bytesCompleteted, (LPOVERLAPPED)this); + this->completionProcessor(S_OK, bytesCompleteted, (LPOVERLAPPED)this, &fCompletionPosted); } } @@ -171,19 +172,31 @@ unsigned int WINAPI CAsyncManager::Worker(void* arg) { OVERLAPPED_ENTRY* entry = entries; for (int i = 0; i < entriesRemoved; i++) - { + { + BOOL fCompletionPosted = FALSE; + if (0L == entry->lpCompletionKey && NULL != (ctx = (ASYNC_CONTEXT*)entry->lpOverlapped) && NULL != ctx->completionProcessor) // regular IO completion - invoke custom processor { + error = (entry->lpOverlapped->Internal == STATUS_SUCCESS) ? ERROR_SUCCESS : pRtlNtStatusToDosError(entry->lpOverlapped->Internal); ctx = (ASYNC_CONTEXT*)entry->lpOverlapped; + ctx->completionProcessor( (0 == entry->dwNumberOfBytesTransferred && ERROR_SUCCESS == error) ? ERROR_NO_DATA : error, entry->dwNumberOfBytesTransferred, - (LPOVERLAPPED)ctx); - ctx->RunSynchronousContinuations(); + (LPOVERLAPPED)ctx, + &fCompletionPosted); + + if(!fCompletionPosted) + { + ctx->RunSynchronousContinuations(); + } + + CNodeHttpStoredContext* storedCtx = (CNodeHttpStoredContext*)ctx->data; + storedCtx->DereferenceNodeHttpStoredContext(); } else if (-1L == entry->lpCompletionKey) // shutdown initiated from Terminate { @@ -194,8 +207,14 @@ unsigned int WINAPI CAsyncManager::Worker(void* arg) if (-2L == entry->lpCompletionKey) // completion of an alertable wait state timer initialized from OnTimer { ctx = (ASYNC_CONTEXT*)entry->lpOverlapped; - ctx->completionProcessor(S_OK, 0, (LPOVERLAPPED)ctx); - ctx->RunSynchronousContinuations(); + ctx->completionProcessor(S_OK, 0, (LPOVERLAPPED)ctx, &fCompletionPosted); + if(!fCompletionPosted) + { + ctx->RunSynchronousContinuations(); + } + + CNodeHttpStoredContext* storedCtx = (CNodeHttpStoredContext*)ctx->data; + storedCtx->DereferenceNodeHttpStoredContext(); } else if (-3L == entry->lpCompletionKey) // continuation initiated form PostContinuation { diff --git a/src/iisnode/casyncmanager.h b/src/iisnode/casyncmanager.h index d3b5b044..be4a3ce5 100644 --- a/src/iisnode/casyncmanager.h +++ b/src/iisnode/casyncmanager.h @@ -1,9 +1,18 @@ #ifndef __CASYNCMANAGER_H__ #define __CASYNCMANAGER_H__ +typedef +VOID +(WINAPI *LPOVERLAPPED_COMPLETION_ROUTINE_IISNODE)( + _In_ DWORD dwErrorCode, + _In_ DWORD dwNumberOfBytesTransfered, + _Inout_ LPOVERLAPPED lpOverlapped, + _Inout_ BOOL * fCompletionPosted + ); + typedef struct { OVERLAPPED overlapped; // this member must be first in the struct - LPOVERLAPPED_COMPLETION_ROUTINE completionProcessor; + LPOVERLAPPED_COMPLETION_ROUTINE_IISNODE completionProcessor; BOOL continueSynchronously; void* data; HANDLE timer; diff --git a/src/iisnode/cmoduleconfiguration.cpp b/src/iisnode/cmoduleconfiguration.cpp index b2979cba..3562ddd8 100644 --- a/src/iisnode/cmoduleconfiguration.cpp +++ b/src/iisnode/cmoduleconfiguration.cpp @@ -87,15 +87,21 @@ CModuleConfiguration::~CModuleConfiguration() this->debuggerPathSegment = NULL; } + if( NULL != this->debugPortRange ) + { + delete [] this->debugPortRange; + this->debugPortRange = NULL; + } + if (NULL != this->node_env) { - delete this->node_env; + delete [] this->node_env; this->node_env = NULL; } if (NULL != this->watchedFiles) { - delete this->watchedFiles; + delete [] this->watchedFiles; this->watchedFiles = NULL; } @@ -814,6 +820,10 @@ HRESULT CModuleConfiguration::ApplyConfigOverrideKeyValue(IHttpContext* context, { CheckError(GetDWORD(valueStart, &config->maxLogFiles)); } + else if (0 == strcmpi(keyStart, "nodeProcessStickySessions")) + { + CheckError(GetBOOL(valueStart, &config->nodeProcessStickySessions)); + } else if (0 == strcmpi(keyStart, "loggingEnabled")) { CheckError(GetBOOL(valueStart, &config->loggingEnabled)); @@ -1228,6 +1238,7 @@ HRESULT CModuleConfiguration::GetConfig(IHttpContext* context, CModuleConfigurat CheckError(GetDWORD(section, L"maxTotalLogFileSizeInKB", &c->maxTotalLogFileSizeInKB)); CheckError(GetDWORD(section, L"maxLogFileSizeInKB", &c->maxLogFileSizeInKB)); CheckError(GetDWORD(section, L"maxLogFiles", &c->maxLogFiles)); + CheckError(GetBOOL(section, L"nodeProcessStickySessions", &c->nodeProcessStickySessions, FALSE)); CheckError(GetBOOL(section, L"loggingEnabled", &c->loggingEnabled, TRUE)); CheckError(GetBOOL(section, L"devErrorsEnabled", &c->devErrorsEnabled, TRUE)); CheckError(GetBOOL(section, L"flushResponse", &c->flushResponse, FALSE)); @@ -1236,7 +1247,7 @@ HRESULT CModuleConfiguration::GetConfig(IHttpContext* context, CModuleConfigurat CheckError(GetString(section, L"debuggerExtensionDll", &c->debuggerExtensionDll)); CheckError(GetBOOL(section, L"debugHeaderEnabled", &c->debugHeaderEnabled, FALSE)); CheckError(GetBOOL(section, L"recycleSignalEnabled", &c->recycleSignalEnabled, FALSE)); - CheckError(GetString(section, L"debuggerVirtualDir", &c->debuggerVirtualDir)); + CheckError(GetString(section, L"debuggerVirtualDir", &c->debuggerVirtualDir)); c->debuggerVirtualDirLength = wcslen(c->debuggerVirtualDir); CheckError(GetString(section, L"node_env", &c->node_env)); CheckError(GetString(section, L"debuggerPortRange", &c->debugPortRange)); @@ -1433,6 +1444,11 @@ BOOL CModuleConfiguration::GetDebuggingEnabled(IHttpContext* ctx) GETCONFIG(debuggingEnabled) } +BOOL CModuleConfiguration::GetProcessStickySessions(IHttpContext* ctx) +{ + GETCONFIG(nodeProcessStickySessions) +} + PWSTR CModuleConfiguration::GetDebuggerExtensionDll(IHttpContext* ctx) { GETCONFIG(debuggerExtensionDll) diff --git a/src/iisnode/cmoduleconfiguration.h b/src/iisnode/cmoduleconfiguration.h index c951fca3..8151cd3b 100644 --- a/src/iisnode/cmoduleconfiguration.h +++ b/src/iisnode/cmoduleconfiguration.h @@ -52,6 +52,7 @@ class CModuleConfiguration : public IHttpStoredContext static BOOL invalid; SRWLOCK srwlock; LPWSTR configOverrides; + BOOL nodeProcessStickySessions; static IHttpServer* server; static HTTP_MODULE_ID moduleId; @@ -129,6 +130,7 @@ class CModuleConfiguration : public IHttpStoredContext static BOOL GetEnableXFF(IHttpContext* ctx); static HRESULT GetPromoteServerVars(IHttpContext* ctx, char*** vars, int* count); static LPWSTR GetConfigOverrides(IHttpContext* ctx); + static BOOL GetProcessStickySessions(IHttpContext* ctx); static HRESULT CreateNodeEnvironment(IHttpContext* ctx, DWORD debugPort, PCH namedPipe, PCH signalPipeName, PCH* env); diff --git a/src/iisnode/cnodeeventprovider.cpp b/src/iisnode/cnodeeventprovider.cpp index 0d5b56f3..97df5d6c 100644 --- a/src/iisnode/cnodeeventprovider.cpp +++ b/src/iisnode/cnodeeventprovider.cpp @@ -107,10 +107,14 @@ HRESULT CNodeEventProvider::Log(IHttpContext *context, PCWSTR message, UCHAR lev } } + /* + commented because there might be a race condition after calling PostCompletion and then using the IHttpContext object. + Uncomment this only after making sure there is no race condition. (IHttpContext cannot be used after calling PostCompletion) if( IsEnabled( context->GetTraceContext(), level ) ) { CheckError( RaiseEvent( context->GetTraceContext(), message, level, activityId ) ); } + */ return S_OK; Error: diff --git a/src/iisnode/cnodehttpmodule.cpp b/src/iisnode/cnodehttpmodule.cpp index 41f8a2ef..0ca88d7f 100644 --- a/src/iisnode/cnodehttpmodule.cpp +++ b/src/iisnode/cnodehttpmodule.cpp @@ -219,7 +219,9 @@ REQUEST_NOTIFICATION_STATUS CNodeHttpModule::OnAsyncCompletion( bytesCompleted = async->bytesCompleteted; async->bytesCompleteted = 0; } - async->completionProcessor(pCompletionInfo->GetCompletionStatus(), bytesCompleted, ctx->GetOverlapped()); + BOOL fCompletionPosted = FALSE; + async->completionProcessor(pCompletionInfo->GetCompletionStatus(), bytesCompleted, ctx->GetOverlapped(), &fCompletionPosted); + async->RunSynchronousContinuations(); } @@ -266,6 +268,8 @@ REQUEST_NOTIFICATION_STATUS CNodeHttpModule::OnAsyncCompletion( break; }; + ctx->DereferenceNodeHttpStoredContext(); + return result; } diff --git a/src/iisnode/cnodehttpstoredcontext.cpp b/src/iisnode/cnodehttpstoredcontext.cpp index 80fc9fef..bb0e1eed 100644 --- a/src/iisnode/cnodehttpstoredcontext.cpp +++ b/src/iisnode/cnodehttpstoredcontext.cpp @@ -6,7 +6,7 @@ CNodeHttpStoredContext::CNodeHttpStoredContext(CNodeApplication* nodeApplication 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) + responseChunkBufferSize(0), m_cRefs(1) { IHttpTraceContext* tctx; LPCGUID pguid; @@ -75,7 +75,7 @@ CNodeApplication* CNodeHttpStoredContext::GetNodeApplication() return this->nodeApplication; } -void CNodeHttpStoredContext::SetNextProcessor(LPOVERLAPPED_COMPLETION_ROUTINE processor) +void CNodeHttpStoredContext::SetNextProcessor(LPOVERLAPPED_COMPLETION_ROUTINE_IISNODE processor) { this->asyncContext.completionProcessor = processor; this->SetContinueSynchronously(FALSE); @@ -95,7 +95,7 @@ LPOVERLAPPED CNodeHttpStoredContext::InitializeOverlapped() void CNodeHttpStoredContext::CleanupStoredContext() { - delete this; + DereferenceNodeHttpStoredContext(); } CNodeProcess* CNodeHttpStoredContext::GetNodeProcess() diff --git a/src/iisnode/cnodehttpstoredcontext.h b/src/iisnode/cnodehttpstoredcontext.h index ae116f0a..f38875d7 100644 --- a/src/iisnode/cnodehttpstoredcontext.h +++ b/src/iisnode/cnodehttpstoredcontext.h @@ -40,12 +40,35 @@ class CNodeHttpStoredContext : public IHttpStoredContext HTTP_DATA_CHUNK responseChunk; DWORD responseChunkBufferSize; CNodeEventProvider* eventProvider; + ~CNodeHttpStoredContext(); + + mutable LONG m_cRefs; public: // Context is owned by the caller CNodeHttpStoredContext(CNodeApplication* nodeApplication, CNodeEventProvider* eventProvider, IHttpContext* context); - ~CNodeHttpStoredContext(); + + VOID + ReferenceNodeHttpStoredContext( + VOID + ) + { + InterlockedIncrement(&m_cRefs); + } + + VOID + DereferenceNodeHttpStoredContext( + VOID + ) + { + _ASSERT(m_cRefs != 0); + + if (InterlockedDecrement(&m_cRefs) == 0) + { + delete this; + } + } IHttpContext* GetHttpContext(); CNodeApplication* GetNodeApplication(); @@ -78,7 +101,7 @@ class CNodeHttpStoredContext : public IHttpStoredContext IHttpContext* GetChildContext(); DWORD GetBytesCompleted(); - void SetNextProcessor(LPOVERLAPPED_COMPLETION_ROUTINE processor); + void SetNextProcessor(LPOVERLAPPED_COMPLETION_ROUTINE_IISNODE processor); void SetNodeProcess(CNodeProcess* process); void SetPipe(HANDLE pipe); void SetConnectionRetryCount(DWORD count); diff --git a/src/iisnode/cnodeprocess.cpp b/src/iisnode/cnodeprocess.cpp index 1ab6683d..f9e0ed06 100644 --- a/src/iisnode/cnodeprocess.cpp +++ b/src/iisnode/cnodeprocess.cpp @@ -20,6 +20,18 @@ CNodeProcess::~CNodeProcess() this->process = 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; + } + if (NULL != this->processWatcher) { // The following check prevents a dead-lock between process watcher thread calling OnProcessExited diff --git a/src/iisnode/cnodeprocessmanager.cpp b/src/iisnode/cnodeprocessmanager.cpp index cb6df5d6..ea29394c 100644 --- a/src/iisnode/cnodeprocessmanager.cpp +++ b/src/iisnode/cnodeprocessmanager.cpp @@ -2,7 +2,7 @@ CNodeProcessManager::CNodeProcessManager(CNodeApplication* application, IHttpContext* context) : application(application), processes(NULL), currentProcess(0), isClosing(FALSE), - refCount(1), gracefulShutdownProcessCount(0) + refCount(1), gracefulShutdownProcessCount(0), stickySessions(FALSE) { if (this->GetApplication()->IsDebugMode()) { @@ -13,6 +13,8 @@ CNodeProcessManager::CNodeProcessManager(CNodeApplication* application, IHttpCon this->processCount = CModuleConfiguration::GetNodeProcessCountPerApplication(context); } + this->stickySessions = CModuleConfiguration::GetProcessStickySessions(context); + // cache event provider since the application can be disposed prior to CNodeProcessManager this->eventProvider = this->GetApplication()->GetApplicationManager()->GetEventProvider(); @@ -107,10 +109,49 @@ HRESULT CNodeProcessManager::AddProcess(int ordinal, IHttpContext* context) return hr; } +int CNodeProcessManager::ExtractStickySessionsProcess( PCSTR pszCookie ) +{ + const CHAR* pszKey = "iisnode.session.cookie"; + const CHAR* pszDivider = "="; + const CHAR* pszNext = ";"; + CHAR acProcess[10]; // characters needed for MAXDWORD64 + memset(acProcess, 0, sizeof(acProcess)); + + const CHAR* pStart = strstr(pszCookie, pszKey); + const CHAR* pEnd = NULL; + + if( pStart != NULL ) + { + pStart = strstr(pStart, pszDivider); + if( pStart != NULL ) + { + // skip the '='; + pStart++; + if( pStart != NULL ) + { + pEnd = strstr(pStart, pszNext); + if(!pEnd) + { + pEnd = pStart; + while (*pEnd) /* Works because end-of-string and FALSE are identical. */ + { + pEnd++; + } + } + memcpy(acProcess, pStart, pEnd - pStart); // copy result + return atoi(acProcess); + } + } + } + + return -1; +} + HRESULT CNodeProcessManager::Dispatch(CNodeHttpStoredContext* request) { HRESULT hr; unsigned int tmpProcess, processToUse; + int processInCookie = -1; CheckNull(request); @@ -122,23 +163,56 @@ HRESULT CNodeProcessManager::Dispatch(CNodeHttpStoredContext* request) if (!this->isClosing) { + // + // if sticky sessions is enabled, use the process specified in the cookie else // employ a round robin routing logic to get a "ticket" to use a process with a specific ordinal number - - if (1 == this->processCount) + // + + if(this->stickySessions) // sticky sessions { - processToUse = 0; + PCSTR pszCookieHeader = NULL; + pszCookieHeader = request->GetHttpContext()->GetRequest()->GetHeader(HttpHeaderCookie); + if(pszCookieHeader != NULL) // There might be a sticky session + { + processInCookie = ExtractStickySessionsProcess(pszCookieHeader); + } } - else + + if( processInCookie < 0) { - do + // + // employ a round robin routing logic to get a "ticket" to use a process with a specific ordinal number + // + + if (1 == this->processCount) + { + processToUse = 0; + } + else { - tmpProcess = this->currentProcess; - processToUse = (tmpProcess + 1) % this->processCount; - } while (tmpProcess != InterlockedCompareExchange(&this->currentProcess, processToUse, tmpProcess)); + do + { + tmpProcess = this->currentProcess; + processToUse = (tmpProcess + 1) % this->processCount; + } while (tmpProcess != InterlockedCompareExchange(&this->currentProcess, processToUse, tmpProcess)); + } + } + else + { + // ensure the cookie did not carry a value outside of the possible processes + processToUse = (unsigned int)processInCookie % this->processCount; } - // try dispatch to that process + if(this->stickySessions && (processInCookie < 0)) + { + // Set cookie for sticky session with selected process + CHAR buffer [255]; + int cCount = sprintf (buffer, "iisnode.session.cookie=%d", processToUse); + ErrorIf( cCount < 0, E_OUTOFMEMORY ); + CheckError(request->GetHttpContext()->GetResponse()->SetHeader(HttpHeaderSetCookie, buffer, cCount, FALSE)); + } + // try dispatch to that process if (NULL != this->processes[processToUse]) { CheckError(this->processes[processToUse]->AcceptRequest(request)); @@ -172,7 +246,9 @@ HRESULT CNodeProcessManager::Dispatch(CNodeHttpStoredContext* request) if (request) { 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); + + BOOL fCompletionPosted = FALSE; + CProtocolBridge::SendEmptyResponse(request, 503, CNodeConstants::IISNODE_ERROR_FAILED_ACCEPT_REQUEST_APP_RECYCLE, _T("Service Unavailable"), IISNODE_ERROR_APPLICATION_IS_RECYCLING, &fCompletionPosted); } this->DecRef(); // incremented at the beginning of this method @@ -185,7 +261,8 @@ HRESULT CNodeProcessManager::Dispatch(CNodeHttpStoredContext* request) if (!CProtocolBridge::SendIisnodeError(request, hr)) { - CProtocolBridge::SendEmptyResponse(request, 503, CNodeConstants::IISNODE_ERROR_INIT_PROCESS_REQUEST, _T("Service Unavailable"), hr); + BOOL fCompletionPosted = FALSE; + CProtocolBridge::SendEmptyResponse(request, 503, CNodeConstants::IISNODE_ERROR_INIT_PROCESS_REQUEST, _T("Service Unavailable"), hr, &fCompletionPosted); } this->DecRef(); // incremented at the beginning of this method diff --git a/src/iisnode/cnodeprocessmanager.h b/src/iisnode/cnodeprocessmanager.h index 0c41737e..ac0d741f 100644 --- a/src/iisnode/cnodeprocessmanager.h +++ b/src/iisnode/cnodeprocessmanager.h @@ -22,6 +22,7 @@ class CNodeProcessManager CNodeApplication* application; CNodeProcess** processes; DWORD processCount; + BOOL stickySessions; unsigned int currentProcess; SRWLOCK srwlock; DWORD gracefulShutdownTimeout; @@ -40,6 +41,7 @@ class CNodeProcessManager CNodeProcessManager(CNodeApplication* application, IHttpContext* context); ~CNodeProcessManager(); + int ExtractStickySessionsProcess( PCSTR pszCookie ); HRESULT EmptyWorkingSet(); CNodeApplication* GetApplication(); HRESULT Initialize(IHttpContext* context); diff --git a/src/iisnode/cprotocolbridge.cpp b/src/iisnode/cprotocolbridge.cpp index 726758ff..83bf6a23 100644 --- a/src/iisnode/cprotocolbridge.cpp +++ b/src/iisnode/cprotocolbridge.cpp @@ -7,6 +7,9 @@ HRESULT CProtocolBridge::PostponeProcessing(CNodeHttpStoredContext* context, DWO delay.QuadPart = dueTime; delay.QuadPart *= -10000; // convert from ms to 100ns units + // will be dereferenced in AsynManager::Worker + context->ReferenceNodeHttpStoredContext(); + return async->SetTimer(context->GetAsyncContext(), &delay); } @@ -193,10 +196,12 @@ BOOL CProtocolBridge::SendIisnodeError(CNodeHttpStoredContext* ctx, HRESULT hr) ctx->SetPipe(INVALID_HANDLE_VALUE); } + BOOL fCompletionPosted = FALSE; CProtocolBridge::FinalizeResponseCore( ctx, RQ_NOTIFICATION_FINISH_REQUEST, hr, + &fCompletionPosted, ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider(), L"iisnode posts completion from SendIisnodeError", WINEVENT_LEVEL_VERBOSE); @@ -405,7 +410,7 @@ BOOL CProtocolBridge::SendDevError(CNodeHttpStoredContext* context, return false; } -HRESULT CProtocolBridge::SendEmptyResponse(CNodeHttpStoredContext* context, USHORT status, USHORT subStatus, PCTSTR reason, HRESULT hresult, BOOL disableCache) +HRESULT CProtocolBridge::SendEmptyResponse(CNodeHttpStoredContext* context, USHORT status, USHORT subStatus, PCTSTR reason, HRESULT hresult, BOOL *pfCompletionPosted, BOOL disableCache) { context->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(context->GetHttpContext(), L"iisnode request processing failed for reasons unrecognized by iisnode", WINEVENT_LEVEL_VERBOSE, context->GetActivityId()); @@ -427,6 +432,7 @@ HRESULT CProtocolBridge::SendEmptyResponse(CNodeHttpStoredContext* context, USHO context, RQ_NOTIFICATION_FINISH_REQUEST, hresult, + pfCompletionPosted, context->GetNodeApplication()->GetApplicationManager()->GetEventProvider(), L"iisnode posts completion from SendEmtpyResponse", WINEVENT_LEVEL_VERBOSE); @@ -474,6 +480,7 @@ HRESULT CProtocolBridge::InitiateRequest(CNodeHttpStoredContext* context) BOOL mainDebuggerPage = FALSE; IHttpContext* child = NULL; BOOL completionExpected; + BOOL fCompletionPosted = FALSE; // determine what the target path of the request is @@ -536,13 +543,13 @@ HRESULT CProtocolBridge::InitiateRequest(CNodeHttpStoredContext* context) CheckError(context->GetHttpContext()->ExecuteRequest(TRUE, child, 0, NULL, &completionExpected)); if (!completionExpected) { - CProtocolBridge::ChildContextCompleted(S_OK, 0, context->GetOverlapped()); + CProtocolBridge::ChildContextCompleted(S_OK, 0, context->GetOverlapped(), &fCompletionPosted); } } else { context->SetNextProcessor(CProtocolBridge::CreateNamedPipeConnection); - CProtocolBridge::CreateNamedPipeConnection(S_OK, 0, context->InitializeOverlapped()); + CProtocolBridge::CreateNamedPipeConnection(S_OK, 0, context->InitializeOverlapped(), &fCompletionPosted); } return S_OK; @@ -558,7 +565,7 @@ HRESULT CProtocolBridge::InitiateRequest(CNodeHttpStoredContext* context) return hr; } -void WINAPI CProtocolBridge::ChildContextCompleted(DWORD error, DWORD bytesTransfered, LPOVERLAPPED overlapped) +void WINAPI CProtocolBridge::ChildContextCompleted(DWORD error, DWORD bytesTransfered, LPOVERLAPPED overlapped, BOOL * pfCompletionPosted) { CNodeHttpStoredContext* ctx = CNodeHttpStoredContext::Get(overlapped); @@ -584,6 +591,7 @@ void WINAPI CProtocolBridge::ChildContextCompleted(DWORD error, DWORD bytesTrans ctx, RQ_NOTIFICATION_CONTINUE, error, + pfCompletionPosted, ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider(), L"iisnode posts completion from ChildContextCompleted", WINEVENT_LEVEL_VERBOSE); @@ -591,7 +599,7 @@ void WINAPI CProtocolBridge::ChildContextCompleted(DWORD error, DWORD bytesTrans return; } -void WINAPI CProtocolBridge::CreateNamedPipeConnection(DWORD error, DWORD bytesTransfered, LPOVERLAPPED overlapped) +void WINAPI CProtocolBridge::CreateNamedPipeConnection(DWORD error, DWORD bytesTransfered, LPOVERLAPPED overlapped, BOOL * pfCompletionPosted) { HRESULT hr; CNodeHttpStoredContext* ctx = CNodeHttpStoredContext::Get(overlapped); @@ -635,7 +643,7 @@ void WINAPI CProtocolBridge::CreateNamedPipeConnection(DWORD error, DWORD bytesT 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); + CProtocolBridge::SendHttpRequestHeaders(ctx, pfCompletionPosted); return; @@ -649,7 +657,7 @@ void WINAPI CProtocolBridge::CreateNamedPipeConnection(DWORD error, DWORD bytesT { 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); + CProtocolBridge::SendEmptyResponse(ctx, 503, CNodeConstants::IISNODE_ERROR_PIPE_CONNECTION_TOO_BUSY, _T("Service Unavailable"), hr, pfCompletionPosted); } else { @@ -659,7 +667,8 @@ void WINAPI CProtocolBridge::CreateNamedPipeConnection(DWORD error, DWORD bytesT 500, CNodeConstants::IISNODE_ERROR_PIPE_CONNECTION, _T("Internal Server Error"), - hr ); + hr, + pfCompletionPosted); } } else if (ctx->GetNodeProcess()->HasProcessExited()) @@ -673,7 +682,8 @@ void WINAPI CProtocolBridge::CreateNamedPipeConnection(DWORD error, DWORD bytesT 500, CNodeConstants::IISNODE_ERROR_PIPE_CONNECTION_BEFORE_PROCESS_TERMINATED, _T("Internal Server Error"), - hr ); + hr, + pfCompletionPosted); } else { @@ -693,13 +703,14 @@ void WINAPI CProtocolBridge::CreateNamedPipeConnection(DWORD error, DWORD bytesT 500, CNodeConstants::IISNODE_ERROR_CONFIGURE_PIPE_CONNECTION, _T("Internal Server Error"), - hr ); + hr, + pfCompletionPosted); } return; } -void CProtocolBridge::SendHttpRequestHeaders(CNodeHttpStoredContext* context) +void CProtocolBridge::SendHttpRequestHeaders(CNodeHttpStoredContext* context, BOOL *pfCompletionPosted) { HRESULT hr; DWORD length; @@ -754,11 +765,15 @@ void CProtocolBridge::SendHttpRequestHeaders(CNodeHttpStoredContext* context) CheckError(CHttpProtocol::SerializeRequestHeaders(context, context->GetBufferRef(), context->GetBufferSizeRef(), &length)); context->SetNextProcessor(CProtocolBridge::SendHttpRequestHeadersCompleted); + + context->ReferenceNodeHttpStoredContext(); if (WriteFile(context->GetPipe(), context->GetBuffer(), length, NULL, context->InitializeOverlapped())) { // completed synchronously + context->DereferenceNodeHttpStoredContext(); + etw->Log(context->GetHttpContext(), L"iisnode initiated sending http request headers to the node.exe process and completed synchronously", WINEVENT_LEVEL_VERBOSE, &activityId); @@ -768,16 +783,18 @@ void CProtocolBridge::SendHttpRequestHeaders(CNodeHttpStoredContext* context) // - see http://msdn.microsoft.com/en-us/library/windows/desktop/aa365683(v=vs.85).aspx // and http://msdn.microsoft.com/en-us/library/windows/desktop/aa365538(v=vs.85).aspx - CProtocolBridge::SendHttpRequestHeadersCompleted(S_OK, 0, context->GetOverlapped()); + CProtocolBridge::SendHttpRequestHeadersCompleted(S_OK, 0, context->GetOverlapped(), pfCompletionPosted); } else { hr = GetLastError(); if (ERROR_IO_PENDING == hr) { + // async WriteFile - will be dereferenced in AsyncManager::Worker } else { + context->DereferenceNodeHttpStoredContext(); // error if (context->GetIsConnectionFromPool()) @@ -786,7 +803,7 @@ void CProtocolBridge::SendHttpRequestHeaders(CNodeHttpStoredContext* context) // try to create a brand new connection instead context->SetConnectionRetryCount(1); - CProtocolBridge::CreateNamedPipeConnection(S_OK, 0, context->GetOverlapped()); + CProtocolBridge::CreateNamedPipeConnection(S_OK, 0, context->GetOverlapped(), pfCompletionPosted); } else { @@ -798,7 +815,8 @@ void CProtocolBridge::SendHttpRequestHeaders(CNodeHttpStoredContext* context) 500, CNodeConstants::IISNODE_ERROR_FAILED_INIT_SEND_HTTP_HEADERS, _T("Internal Server Error"), - hr ); + hr , + pfCompletionPosted); } } } @@ -815,12 +833,13 @@ void CProtocolBridge::SendHttpRequestHeaders(CNodeHttpStoredContext* context) 500, CNodeConstants::IISNODE_ERROR_FAILED_SERIALIZE_HTTP_HEADERS, _T("Internal Server Error"), - hr ); + hr, + pfCompletionPosted); return; } -void WINAPI CProtocolBridge::SendHttpRequestHeadersCompleted(DWORD error, DWORD bytesTransfered, LPOVERLAPPED overlapped) +void WINAPI CProtocolBridge::SendHttpRequestHeadersCompleted(DWORD error, DWORD bytesTransfered, LPOVERLAPPED overlapped, BOOL * pfCompletionPosted) { HRESULT hr; CNodeHttpStoredContext* ctx = CNodeHttpStoredContext::Get(overlapped); @@ -828,7 +847,7 @@ void WINAPI CProtocolBridge::SendHttpRequestHeadersCompleted(DWORD error, DWORD CheckError(error); 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); + CProtocolBridge::ReadRequestBody(ctx, pfCompletionPosted); return; Error: @@ -839,7 +858,7 @@ void WINAPI CProtocolBridge::SendHttpRequestHeadersCompleted(DWORD error, DWORD // try to create a brand new connection instead ctx->SetConnectionRetryCount(1); - CProtocolBridge::CreateNamedPipeConnection(S_OK, 0, ctx->GetOverlapped()); + CProtocolBridge::CreateNamedPipeConnection(S_OK, 0, ctx->GetOverlapped(), pfCompletionPosted); } else { @@ -849,22 +868,28 @@ void WINAPI CProtocolBridge::SendHttpRequestHeadersCompleted(DWORD error, DWORD 500, CNodeConstants::IISNODE_ERROR_FAILED_SEND_HTTP_HEADERS, _T("Internal Server Error"), - hr ); + hr, + pfCompletionPosted); } return; } -void CProtocolBridge::ReadRequestBody(CNodeHttpStoredContext* context) +void CProtocolBridge::ReadRequestBody(CNodeHttpStoredContext* context, BOOL *pfCompletionPosted) { HRESULT hr; DWORD bytesReceived = 0; BOOL completionPending = FALSE; BOOL continueSynchronouslyNow = TRUE; + BOOL fReferenced = FALSE; if (0 < context->GetHttpContext()->GetRequest()->GetRemainingEntityBytes() || context->GetIsUpgrade()) { context->SetNextProcessor(CProtocolBridge::ReadRequestBodyCompleted); + + // if async, will be dereferenced in OnAsyncCompletion + context->ReferenceNodeHttpStoredContext(); + fReferenced = TRUE; if (context->GetIsChunked()) { @@ -877,6 +902,8 @@ void CProtocolBridge::ReadRequestBody(CNodeHttpStoredContext* context) if (!completionPending) { + context->DereferenceNodeHttpStoredContext(); + context->SetContinueSynchronously(TRUE); continueSynchronouslyNow = FALSE; context->SetBytesCompleted(bytesReceived); @@ -891,7 +918,7 @@ void CProtocolBridge::ReadRequestBody(CNodeHttpStoredContext* context) context->SetBytesCompleted(bytesReceived); if (continueSynchronouslyNow) { - CProtocolBridge::ReadRequestBodyCompleted(S_OK, 0, context->GetOverlapped()); + CProtocolBridge::ReadRequestBodyCompleted(S_OK, 0, context->GetOverlapped(), pfCompletionPosted); } } else @@ -910,17 +937,16 @@ void CProtocolBridge::ReadRequestBody(CNodeHttpStoredContext* context) if (context->GetIsUpgrade()) { - CProtocolBridge::FinalizeUpgradeResponse(context, S_OK); + CProtocolBridge::FinalizeUpgradeResponse(context, S_OK, pfCompletionPosted); } else if (context->GetIsChunked() && !context->GetIsLastChunk()) { // send the terminating zero-length chunk - - CProtocolBridge::ReadRequestBodyCompleted(S_OK, 0, context->GetOverlapped()); + CProtocolBridge::ReadRequestBodyCompleted(S_OK, 0, context->GetOverlapped(), pfCompletionPosted); } else { - CProtocolBridge::StartReadResponse(context); + CProtocolBridge::StartReadResponse(context, pfCompletionPosted); } } else @@ -930,7 +956,7 @@ void CProtocolBridge::ReadRequestBody(CNodeHttpStoredContext* context) if (context->GetIsUpgrade()) { - CProtocolBridge::FinalizeUpgradeResponse(context, HRESULT_FROM_WIN32(hr)); + CProtocolBridge::FinalizeUpgradeResponse(context, HRESULT_FROM_WIN32(hr), pfCompletionPosted); } else { @@ -938,14 +964,20 @@ void CProtocolBridge::ReadRequestBody(CNodeHttpStoredContext* context) 500, CNodeConstants::IISNODE_ERROR_FAILED_READ_REQ_BODY, _T("Internal Server Error"), - HRESULT_FROM_WIN32(hr) ); + HRESULT_FROM_WIN32(hr), + pfCompletionPosted); } } + if (fReferenced) + { + context->DereferenceNodeHttpStoredContext(); + } + return; } -void WINAPI CProtocolBridge::ReadRequestBodyCompleted(DWORD error, DWORD bytesTransfered, LPOVERLAPPED overlapped) +void WINAPI CProtocolBridge::ReadRequestBodyCompleted(DWORD error, DWORD bytesTransfered, LPOVERLAPPED overlapped, BOOL * pfCompletionPosted) { CNodeHttpStoredContext* ctx = CNodeHttpStoredContext::Get(overlapped); @@ -953,7 +985,7 @@ void WINAPI CProtocolBridge::ReadRequestBodyCompleted(DWORD error, DWORD bytesTr { 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); + CProtocolBridge::SendRequestBody(ctx, bytesTransfered, pfCompletionPosted); } else if (ERROR_HANDLE_EOF == error || 0 == bytesTransfered) { @@ -962,17 +994,17 @@ void WINAPI CProtocolBridge::ReadRequestBodyCompleted(DWORD error, DWORD bytesTr if (ctx->GetIsUpgrade()) { - CProtocolBridge::FinalizeUpgradeResponse(ctx, S_OK); + CProtocolBridge::FinalizeUpgradeResponse(ctx, S_OK, pfCompletionPosted); } else if (ctx->GetIsChunked() && !ctx->GetIsLastChunk()) { // send the zero-length last chunk to indicate the end of a chunked entity body - CProtocolBridge::SendRequestBody(ctx, 0); + CProtocolBridge::SendRequestBody(ctx, 0, pfCompletionPosted); } else { - CProtocolBridge::StartReadResponse(ctx); + CProtocolBridge::StartReadResponse(ctx, pfCompletionPosted); } } else @@ -982,7 +1014,7 @@ void WINAPI CProtocolBridge::ReadRequestBodyCompleted(DWORD error, DWORD bytesTr if (ctx->GetIsUpgrade()) { - CProtocolBridge::FinalizeUpgradeResponse(ctx, error); + CProtocolBridge::FinalizeUpgradeResponse(ctx, error, pfCompletionPosted); } else { @@ -990,12 +1022,13 @@ void WINAPI CProtocolBridge::ReadRequestBodyCompleted(DWORD error, DWORD bytesTr 500, CNodeConstants::IISNODE_ERROR_FAILED_READ_REQ_BODY_COMPLETED, _T("Internal Server Error"), - error ); + error, + pfCompletionPosted); } } } -void CProtocolBridge::SendRequestBody(CNodeHttpStoredContext* context, DWORD chunkLength) +void CProtocolBridge::SendRequestBody(CNodeHttpStoredContext* context, DWORD chunkLength, BOOL *pfCompletionPosted) { // capture ETW provider since after a successful call to WriteFile the context may be asynchronously deleted @@ -1058,10 +1091,15 @@ void CProtocolBridge::SendRequestBody(CNodeHttpStoredContext* context, DWORD chu context->SetNextProcessor(CProtocolBridge::SendRequestBodyCompleted); + // will derefence in AsyncManager::Worker + context->ReferenceNodeHttpStoredContext(); + if (WriteFile(context->GetPipe(), (void*)buffer, length, NULL, context->InitializeOverlapped())) { // completed synchronously + context->DereferenceNodeHttpStoredContext(); + etw->Log(context->GetHttpContext(), L"iisnode initiated sending http request body chunk to the node.exe process and completed synchronously", WINEVENT_LEVEL_VERBOSE, &activityId); @@ -1071,7 +1109,7 @@ void CProtocolBridge::SendRequestBody(CNodeHttpStoredContext* context, DWORD chu // - see http://msdn.microsoft.com/en-us/library/windows/desktop/aa365683(v=vs.85).aspx // and http://msdn.microsoft.com/en-us/library/windows/desktop/aa365538(v=vs.85).aspx - CProtocolBridge::SendRequestBodyCompleted(S_OK, 0, context->GetOverlapped()); + CProtocolBridge::SendRequestBodyCompleted(S_OK, 0, context->GetOverlapped(), pfCompletionPosted); } else { @@ -1087,7 +1125,7 @@ void CProtocolBridge::SendRequestBody(CNodeHttpStoredContext* context, DWORD chu } else if (ERROR_NO_DATA == hr) { - // Node.exe has closed the named pipe. This means it does not expect any more request data, but it does not mean there is no response. + context->DereferenceNodeHttpStoredContext(); // Node.exe has closed the named pipe. This means it does not expect any more request data, but it does not mean there is no response. // This may happen even for POST requests if the node.js application does not register event handlers for the 'data' or 'end' request events. // 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. @@ -1098,16 +1136,17 @@ void CProtocolBridge::SendRequestBody(CNodeHttpStoredContext* context, DWORD chu if (context->GetIsUpgrade()) { - CProtocolBridge::FinalizeUpgradeResponse(context, S_OK); + CProtocolBridge::FinalizeUpgradeResponse(context, S_OK, pfCompletionPosted); } else { - CProtocolBridge::StartReadResponse(context); + CProtocolBridge::StartReadResponse(context, pfCompletionPosted); } } else { // error + context->DereferenceNodeHttpStoredContext(); etw->Log(context->GetHttpContext(), L"iisnode failed to initiate sending http request body chunk to the node.exe process", WINEVENT_LEVEL_ERROR, @@ -1115,7 +1154,7 @@ void CProtocolBridge::SendRequestBody(CNodeHttpStoredContext* context, DWORD chu if (context->GetIsUpgrade()) { - CProtocolBridge::FinalizeUpgradeResponse(context, hr); + CProtocolBridge::FinalizeUpgradeResponse(context, hr, pfCompletionPosted); } else { @@ -1123,7 +1162,8 @@ void CProtocolBridge::SendRequestBody(CNodeHttpStoredContext* context, DWORD chu 500, CNodeConstants::IISNODE_ERROR_FAILED_INIT_SEND_REQ_BODY, _T("Internal Server Error"), - hr ); + hr, + pfCompletionPosted ); } } } @@ -1131,7 +1171,7 @@ void CProtocolBridge::SendRequestBody(CNodeHttpStoredContext* context, DWORD chu return; } -void WINAPI CProtocolBridge::SendRequestBodyCompleted(DWORD error, DWORD bytesTransfered, LPOVERLAPPED overlapped) +void WINAPI CProtocolBridge::SendRequestBodyCompleted(DWORD error, DWORD bytesTransfered, LPOVERLAPPED overlapped, BOOL * pfCompletionPosted) { CNodeHttpStoredContext* ctx = CNodeHttpStoredContext::Get(overlapped); @@ -1139,7 +1179,7 @@ void WINAPI CProtocolBridge::SendRequestBodyCompleted(DWORD error, DWORD bytesTr { 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); + CProtocolBridge::ReadRequestBody(ctx, pfCompletionPosted); } else { @@ -1148,7 +1188,7 @@ void WINAPI CProtocolBridge::SendRequestBodyCompleted(DWORD error, DWORD bytesTr if (ctx->GetIsUpgrade()) { - CProtocolBridge::FinalizeUpgradeResponse(ctx, error); + CProtocolBridge::FinalizeUpgradeResponse(ctx, error, pfCompletionPosted); } else { @@ -1156,19 +1196,20 @@ void WINAPI CProtocolBridge::SendRequestBodyCompleted(DWORD error, DWORD bytesTr 500, CNodeConstants::IISNODE_ERROR_FAILED_SEND_REQ_BODY, _T("Internal Server Error"), - error ); + error, + pfCompletionPosted); } } } -void CProtocolBridge::StartReadResponse(CNodeHttpStoredContext* context) +void CProtocolBridge::StartReadResponse(CNodeHttpStoredContext* context, BOOL *pfCompletionPosted) { context->SetDataSize(0); context->SetParsingOffset(0); context->SetNextProcessor(CProtocolBridge::ProcessResponseStatusLine); context->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(context->GetHttpContext(), L"iisnode starting to read http response", WINEVENT_LEVEL_VERBOSE, context->GetActivityId()); - CProtocolBridge::ContinueReadResponse(context); + CProtocolBridge::ContinueReadResponse(context, pfCompletionPosted); } HRESULT CProtocolBridge::EnsureBuffer(CNodeHttpStoredContext* context) @@ -1222,7 +1263,7 @@ HRESULT CProtocolBridge::EnsureBuffer(CNodeHttpStoredContext* context) } -void CProtocolBridge::ContinueReadResponse(CNodeHttpStoredContext* context) +void CProtocolBridge::ContinueReadResponse(CNodeHttpStoredContext* context, BOOL *pfCompletionPosted) { HRESULT hr; DWORD bytesRead = 0; @@ -1235,6 +1276,9 @@ void CProtocolBridge::ContinueReadResponse(CNodeHttpStoredContext* context) CheckError(CProtocolBridge::EnsureBuffer(context)); + // will dereference in AsyncManager::Worker + context->ReferenceNodeHttpStoredContext(); + if (ReadFile( context->GetPipe(), (char*)context->GetBuffer() + context->GetDataSize(), @@ -1243,6 +1287,7 @@ void CProtocolBridge::ContinueReadResponse(CNodeHttpStoredContext* context) context->InitializeOverlapped())) { // read completed synchronously + context->DereferenceNodeHttpStoredContext(); etw->Log(context->GetHttpContext(), L"iisnode initiated reading http response chunk and completed synchronously", WINEVENT_LEVEL_VERBOSE, @@ -1253,7 +1298,7 @@ void CProtocolBridge::ContinueReadResponse(CNodeHttpStoredContext* context) // - see http://msdn.microsoft.com/en-us/library/windows/desktop/aa365683(v=vs.85).aspx // and http://msdn.microsoft.com/en-us/library/windows/desktop/aa365538(v=vs.85).aspx - context->GetAsyncContext()->completionProcessor(S_OK, bytesRead, context->GetOverlapped()); + context->GetAsyncContext()->completionProcessor(S_OK, bytesRead, context->GetOverlapped(), pfCompletionPosted); } else if (ERROR_IO_PENDING == (hr = GetLastError())) { @@ -1265,13 +1310,15 @@ void CProtocolBridge::ContinueReadResponse(CNodeHttpStoredContext* context) } else if (ERROR_BROKEN_PIPE == hr && context->GetCloseConnection()) { + context->DereferenceNodeHttpStoredContext(); // Termination of a connection indicates the end of the response body if Connection: close response header was present - CProtocolBridge::FinalizeResponse(context); + CProtocolBridge::FinalizeResponse(context, pfCompletionPosted); } else { // error + context->DereferenceNodeHttpStoredContext(); etw->Log(context->GetHttpContext(), L"iisnode failed to initialize reading of http response chunk", WINEVENT_LEVEL_ERROR, @@ -1281,7 +1328,8 @@ void CProtocolBridge::ContinueReadResponse(CNodeHttpStoredContext* context) 500, CNodeConstants::IISNODE_ERROR_FAILED_INIT_READ_RESPONSE, _T("Internal Server Error"), - hr ); + hr, + pfCompletionPosted); } return; @@ -1294,12 +1342,13 @@ void CProtocolBridge::ContinueReadResponse(CNodeHttpStoredContext* context) 500, CNodeConstants::IISNODE_ERROR_FAILED_ALLOC_MEM_READ_RESPONSE, _T("Internal Server Error"), - hr ); + hr, + pfCompletionPosted); return; } -void WINAPI CProtocolBridge::ProcessResponseStatusLine(DWORD error, DWORD bytesTransfered, LPOVERLAPPED overlapped) +void WINAPI CProtocolBridge::ProcessResponseStatusLine(DWORD error, DWORD bytesTransfered, LPOVERLAPPED overlapped, BOOL * pfCompletionPosted) { HRESULT hr; CNodeHttpStoredContext* ctx = CNodeHttpStoredContext::Get(overlapped); @@ -1315,14 +1364,14 @@ void WINAPI CProtocolBridge::ProcessResponseStatusLine(DWORD error, DWORD bytesT L"iisnode finished processing http response status line", WINEVENT_LEVEL_VERBOSE, ctx->GetActivityId()); ctx->SetNextProcessor(CProtocolBridge::ProcessResponseHeaders); - CProtocolBridge::ProcessResponseHeaders(S_OK, 0, ctx->GetOverlapped()); + CProtocolBridge::ProcessResponseHeaders(S_OK, 0, ctx->GetOverlapped(), pfCompletionPosted); return; Error: if (ERROR_MORE_DATA == hr) { - CProtocolBridge::ContinueReadResponse(ctx); + CProtocolBridge::ContinueReadResponse(ctx, pfCompletionPosted); } else { @@ -1332,7 +1381,8 @@ void WINAPI CProtocolBridge::ProcessResponseStatusLine(DWORD error, DWORD bytesT 500, CNodeConstants::IISNODE_ERROR_FAILED_PROCESS_HTTP_STATUS_LINE, _T("Internal Server Error"), - hr ); + hr, + pfCompletionPosted); } return; @@ -1450,7 +1500,7 @@ HRESULT CProtocolBridge::AddDebugHeader(CNodeHttpStoredContext* context) return hr; } -void WINAPI CProtocolBridge::ProcessResponseHeaders(DWORD error, DWORD bytesTransfered, LPOVERLAPPED overlapped) +void WINAPI CProtocolBridge::ProcessResponseHeaders(DWORD error, DWORD bytesTransfered, LPOVERLAPPED overlapped, BOOL * pfCompletionPosted) { HRESULT hr; CNodeHttpStoredContext* ctx = CNodeHttpStoredContext::Get(overlapped); @@ -1474,7 +1524,7 @@ void WINAPI CProtocolBridge::ProcessResponseHeaders(DWORD error, DWORD bytesTran 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); + CProtocolBridge::FinalizeResponse(ctx, pfCompletionPosted); } else { @@ -1523,7 +1573,7 @@ void WINAPI CProtocolBridge::ProcessResponseHeaders(DWORD error, DWORD bytesTran 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()); + ctx->GetAsyncContext()->completionProcessor(S_OK, 0, ctx->GetOverlapped(), pfCompletionPosted); } return; @@ -1531,7 +1581,7 @@ void WINAPI CProtocolBridge::ProcessResponseHeaders(DWORD error, DWORD bytesTran if (ERROR_MORE_DATA == hr) { - CProtocolBridge::ContinueReadResponse(ctx); + CProtocolBridge::ContinueReadResponse(ctx, pfCompletionPosted); } else { @@ -1541,13 +1591,14 @@ void WINAPI CProtocolBridge::ProcessResponseHeaders(DWORD error, DWORD bytesTran 500, CNodeConstants::IISNODE_ERROR_FAILED_PROCESS_HTTP_HEADERS, _T("Internal Server Error"), - hr ); + hr, + pfCompletionPosted); } return; } -void WINAPI CProtocolBridge::ProcessChunkHeader(DWORD error, DWORD bytesTransfered, LPOVERLAPPED overlapped) +void WINAPI CProtocolBridge::ProcessChunkHeader(DWORD error, DWORD bytesTransfered, LPOVERLAPPED overlapped, BOOL * pfCompletionPosted) { HRESULT hr; CNodeHttpStoredContext* ctx = CNodeHttpStoredContext::Get(overlapped); @@ -1564,7 +1615,8 @@ void WINAPI CProtocolBridge::ProcessChunkHeader(DWORD error, DWORD bytesTransfer L"iisnode finished processing http response body chunk header", WINEVENT_LEVEL_VERBOSE, ctx->GetActivityId()); ctx->SetNextProcessor(CProtocolBridge::ProcessResponseBody); - CProtocolBridge::ProcessResponseBody(S_OK, 0, ctx->GetOverlapped()); + + CProtocolBridge::ProcessResponseBody(S_OK, 0, ctx->GetOverlapped(), pfCompletionPosted); return; @@ -1572,7 +1624,7 @@ void WINAPI CProtocolBridge::ProcessChunkHeader(DWORD error, DWORD bytesTransfer if (ERROR_MORE_DATA == hr) { - CProtocolBridge::ContinueReadResponse(ctx); + CProtocolBridge::ContinueReadResponse(ctx, pfCompletionPosted); } else { @@ -1582,13 +1634,14 @@ void WINAPI CProtocolBridge::ProcessChunkHeader(DWORD error, DWORD bytesTransfer 500, CNodeConstants::IISNODE_ERROR_FAILED_PROCESS_RESPONSE_BODY_CHUNK_HEADER, _T("Internal Server Error"), - hr ); + hr, + pfCompletionPosted); } return; } -void CProtocolBridge::EnsureRequestPumpStarted(CNodeHttpStoredContext* context) +void CProtocolBridge::EnsureRequestPumpStarted(CNodeHttpStoredContext* context, BOOL *pfCompletionPosted) { if (context->GetOpaqueFlagSet() && !context->GetRequestPumpStarted()) { @@ -1596,19 +1649,20 @@ void CProtocolBridge::EnsureRequestPumpStarted(CNodeHttpStoredContext* context) // only after the 101 Switching Protocols response had been sent. context->SetRequestPumpStarted(); - CProtocolBridge::ReadRequestBody(context->GetUpgradeContext()); + CProtocolBridge::ReadRequestBody(context->GetUpgradeContext(), pfCompletionPosted); ASYNC_CONTEXT* async = context->GetUpgradeContext()->GetAsyncContext(); async->RunSynchronousContinuations(); } } -void WINAPI CProtocolBridge::ProcessResponseBody(DWORD error, DWORD bytesTransfered, LPOVERLAPPED overlapped) +void WINAPI CProtocolBridge::ProcessResponseBody(DWORD error, DWORD bytesTransfered, LPOVERLAPPED overlapped, BOOL * pfCompletionPosted) { HRESULT hr; CNodeHttpStoredContext* ctx = CNodeHttpStoredContext::Get(overlapped); HTTP_DATA_CHUNK* chunk; DWORD bytesSent; BOOL completionExpected; + BOOL fReferenced = FALSE; ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(ctx->GetHttpContext(), L"iisnode starting to process http response body", WINEVENT_LEVEL_VERBOSE, ctx->GetActivityId()); @@ -1646,6 +1700,10 @@ void WINAPI CProtocolBridge::ProcessResponseBody(DWORD error, DWORD bytesTransfe ctx->SetNextProcessor(CProtocolBridge::SendResponseBodyCompleted); ctx->SetBytesCompleted(bytesToSend); + // will be dereferenced in OnAsyncCompletion + ctx->ReferenceNodeHttpStoredContext(); + fReferenced = TRUE; + CheckError(ctx->GetHttpContext()->GetResponse()->WriteEntityChunks( chunk, 1, @@ -1659,6 +1717,7 @@ void WINAPI CProtocolBridge::ProcessResponseBody(DWORD error, DWORD bytesTransfe if (!completionExpected) { + ctx->DereferenceNodeHttpStoredContext(); ctx->SetContinueSynchronously(TRUE); } } @@ -1667,7 +1726,7 @@ void WINAPI CProtocolBridge::ProcessResponseBody(DWORD error, DWORD bytesTransfe // process next chunk of the chunked encoding ctx->SetNextProcessor(CProtocolBridge::ProcessChunkHeader); - CProtocolBridge::ProcessChunkHeader(S_OK, 0, ctx->GetOverlapped()); + CProtocolBridge::ProcessChunkHeader(S_OK, 0, ctx->GetOverlapped(), pfCompletionPosted); } else { @@ -1680,7 +1739,7 @@ void WINAPI CProtocolBridge::ProcessResponseBody(DWORD error, DWORD bytesTransfe { // read more body data - CProtocolBridge::ContinueReadResponse(ctx); + CProtocolBridge::ContinueReadResponse(ctx, pfCompletionPosted); } else { @@ -1688,11 +1747,11 @@ void WINAPI CProtocolBridge::ProcessResponseBody(DWORD error, DWORD bytesTransfe if (ctx->GetIsUpgrade()) { - CProtocolBridge::FinalizeUpgradeResponse(ctx, S_OK); + CProtocolBridge::FinalizeUpgradeResponse(ctx, S_OK, pfCompletionPosted); } else { - CProtocolBridge::FinalizeResponse(ctx); + CProtocolBridge::FinalizeResponse(ctx, pfCompletionPosted); } } @@ -1703,13 +1762,13 @@ void WINAPI CProtocolBridge::ProcessResponseBody(DWORD error, DWORD bytesTransfe { // Termination of a connection indicates the end of the upgraded request - CProtocolBridge::FinalizeUpgradeResponse(ctx, S_OK); + CProtocolBridge::FinalizeUpgradeResponse(ctx, S_OK, pfCompletionPosted); } else if (ERROR_BROKEN_PIPE == hr && ctx->GetCloseConnection()) { // Termination of a connection indicates the end of the response body if Connection: close response header was present - CProtocolBridge::FinalizeResponse(ctx); + CProtocolBridge::FinalizeResponse(ctx, pfCompletionPosted); } else { @@ -1718,7 +1777,7 @@ void WINAPI CProtocolBridge::ProcessResponseBody(DWORD error, DWORD bytesTransfe if (ctx->GetIsUpgrade()) { - CProtocolBridge::FinalizeUpgradeResponse(ctx, hr); + CProtocolBridge::FinalizeUpgradeResponse(ctx, hr, pfCompletionPosted); } else { @@ -1726,14 +1785,20 @@ void WINAPI CProtocolBridge::ProcessResponseBody(DWORD error, DWORD bytesTransfe 500, CNodeConstants::IISNODE_ERROR_FAILED_SEND_RESPONSE_BODY_CHUNK, _T("Internal Server Error"), - hr ); + hr, + pfCompletionPosted); } } + if (fReferenced) + { + ctx->DereferenceNodeHttpStoredContext(); + } + return; } -void WINAPI CProtocolBridge::SendResponseBodyCompleted(DWORD error, DWORD bytesTransfered, LPOVERLAPPED overlapped) +void WINAPI CProtocolBridge::SendResponseBodyCompleted(DWORD error, DWORD bytesTransfered, LPOVERLAPPED overlapped, BOOL * pfCompletionPosted) { HRESULT hr; CNodeHttpStoredContext* ctx = CNodeHttpStoredContext::Get(overlapped); @@ -1754,7 +1819,7 @@ void WINAPI CProtocolBridge::SendResponseBodyCompleted(DWORD error, DWORD bytesT if (ctx->GetIsLastChunk() && ctx->GetChunkLength() == ctx->GetChunkTransmitted()) { - CProtocolBridge::FinalizeResponse(ctx); + CProtocolBridge::FinalizeResponse(ctx, pfCompletionPosted); } else { @@ -1770,7 +1835,7 @@ void WINAPI CProtocolBridge::SendResponseBodyCompleted(DWORD error, DWORD bytesT if (!completionExpected) { - CProtocolBridge::ContinueProcessResponseBodyAfterPartialFlush(S_OK, 0, ctx->GetOverlapped()); + CProtocolBridge::ContinueProcessResponseBodyAfterPartialFlush(S_OK, 0, ctx->GetOverlapped(), pfCompletionPosted); } } @@ -1782,7 +1847,7 @@ void WINAPI CProtocolBridge::SendResponseBodyCompleted(DWORD error, DWORD bytesT if (ctx->GetIsUpgrade()) { - CProtocolBridge::FinalizeUpgradeResponse(ctx, hr); + CProtocolBridge::FinalizeUpgradeResponse(ctx, hr, pfCompletionPosted); } else { @@ -1790,13 +1855,14 @@ void WINAPI CProtocolBridge::SendResponseBodyCompleted(DWORD error, DWORD bytesT 500, CNodeConstants::IISNODE_ERROR_FAILED_FLUSH_RESPONSE_BODY, _T("Internal Server Error"), - hr ); + hr, + pfCompletionPosted); } return; } -void WINAPI CProtocolBridge::ProcessUpgradeResponse(DWORD error, DWORD bytesTransfered, LPOVERLAPPED overlapped) +void WINAPI CProtocolBridge::ProcessUpgradeResponse(DWORD error, DWORD bytesTransfered, LPOVERLAPPED overlapped, BOOL * pfCompletionPosted) { BOOL completionExpected; DWORD bytesSent; @@ -1809,12 +1875,12 @@ void WINAPI CProtocolBridge::ProcessUpgradeResponse(DWORD error, DWORD bytesTran if (!completionExpected) { - CProtocolBridge::ContinueProcessResponseBodyAfterPartialFlush(S_OK, 0, ctx->GetOverlapped()); + CProtocolBridge::ContinueProcessResponseBodyAfterPartialFlush(S_OK, 0, ctx->GetOverlapped(), pfCompletionPosted); } } -void WINAPI CProtocolBridge::ContinueProcessResponseBodyAfterPartialFlush(DWORD error, DWORD bytesTransfered, LPOVERLAPPED overlapped) +void WINAPI CProtocolBridge::ContinueProcessResponseBodyAfterPartialFlush(DWORD error, DWORD bytesTransfered, LPOVERLAPPED overlapped, BOOL * pfCompletionPosted) { HRESULT hr; CNodeHttpStoredContext* ctx = CNodeHttpStoredContext::Get(overlapped); @@ -1822,11 +1888,11 @@ void WINAPI CProtocolBridge::ContinueProcessResponseBodyAfterPartialFlush(DWORD CheckError(error); // Start reading the request bytes if the request was an accepted HTTP Upgrade - CProtocolBridge::EnsureRequestPumpStarted(ctx); + CProtocolBridge::EnsureRequestPumpStarted(ctx, pfCompletionPosted); // Continue on to reading the response body ctx->SetNextProcessor(CProtocolBridge::ProcessResponseBody); - CProtocolBridge::ProcessResponseBody(S_OK, 0, ctx->GetOverlapped()); + CProtocolBridge::ProcessResponseBody(S_OK, 0, ctx->GetOverlapped(), pfCompletionPosted); return; Error: @@ -1837,12 +1903,13 @@ void WINAPI CProtocolBridge::ContinueProcessResponseBodyAfterPartialFlush(DWORD 500, CNodeConstants::IISNODE_ERROR_FAILED_FLUSH_RESPONSE_BODY_PARTIAL_FLUSH, _T("Internal Server Error"), - hr ); + hr, + pfCompletionPosted); return; } -void CProtocolBridge::FinalizeUpgradeResponse(CNodeHttpStoredContext* context, HRESULT hresult) +void CProtocolBridge::FinalizeUpgradeResponse(CNodeHttpStoredContext* context, HRESULT hresult, BOOL *pfCompletionPosted) { context->SetNextProcessor(NULL); context->SetHresult(hresult); @@ -1858,7 +1925,12 @@ void CProtocolBridge::FinalizeUpgradeResponse(CNodeHttpStoredContext* context, H CloseHandle(context->GetPipe()); context->SetPipe(INVALID_HANDLE_VALUE); context->GetHttpContext()->GetResponse()->SetNeedDisconnect(); + + // will dereference in OnAsyncCompletion + context->ReferenceNodeHttpStoredContext(); + context->GetHttpContext()->PostCompletion(0); + *pfCompletionPosted = TRUE; } else { @@ -1869,7 +1941,7 @@ void CProtocolBridge::FinalizeUpgradeResponse(CNodeHttpStoredContext* context, H } } -void CProtocolBridge::FinalizeResponse(CNodeHttpStoredContext* context) +void CProtocolBridge::FinalizeResponse(CNodeHttpStoredContext* context, BOOL *pfCompletionPosted) { context->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(context->GetHttpContext(), @@ -1889,12 +1961,13 @@ void CProtocolBridge::FinalizeResponse(CNodeHttpStoredContext* context) context, RQ_NOTIFICATION_CONTINUE, S_OK, + pfCompletionPosted, context->GetNodeApplication()->GetApplicationManager()->GetEventProvider(), L"iisnode posts completion from FinalizeResponse", WINEVENT_LEVEL_VERBOSE); } -HRESULT CProtocolBridge::FinalizeResponseCore(CNodeHttpStoredContext* context, REQUEST_NOTIFICATION_STATUS status, HRESULT error, CNodeEventProvider* log, PCWSTR etw, UCHAR level) +HRESULT CProtocolBridge::FinalizeResponseCore(CNodeHttpStoredContext* context, REQUEST_NOTIFICATION_STATUS status, HRESULT error, BOOL *pfCompletionPosted, CNodeEventProvider* log, PCWSTR etw, UCHAR level) { context->SetRequestNotificationStatus(status); context->SetNextProcessor(NULL); @@ -1910,8 +1983,12 @@ HRESULT CProtocolBridge::FinalizeResponseCore(CNodeHttpStoredContext* context, R if (0 == context->DecreasePendingAsyncOperationCount()) // decreases ref count increased in the ctor of CNodeApplication::Dispatch { + // will be dereferenced in OnAsyncCompletion + context->ReferenceNodeHttpStoredContext(); + log->Log(etw, level, context->GetActivityId()); context->GetHttpContext()->PostCompletion(0); + *pfCompletionPosted = TRUE; } return S_OK; @@ -1937,10 +2014,14 @@ HRESULT CProtocolBridge::SendDebugRedirect(CNodeHttpStoredContext* context, CNod response->SetStatus(301, "Moved Permanently"); CheckError(context->GetHttpContext()->GetResponse()->Redirect(path, FALSE, TRUE)); + + BOOL fCompletionPosted = FALSE; + CProtocolBridge::FinalizeResponseCore( context, RQ_NOTIFICATION_FINISH_REQUEST, S_OK, + &fCompletionPosted, log, L"iisnode redirected debugging request", WINEVENT_LEVEL_VERBOSE); diff --git a/src/iisnode/cprotocolbridge.h b/src/iisnode/cprotocolbridge.h index 5ce4ab80..054f5e59 100644 --- a/src/iisnode/cprotocolbridge.h +++ b/src/iisnode/cprotocolbridge.h @@ -11,48 +11,48 @@ class CProtocolBridge // utility static HRESULT PostponeProcessing(CNodeHttpStoredContext* context, DWORD dueTime); static HRESULT EnsureBuffer(CNodeHttpStoredContext* context); - static HRESULT FinalizeResponseCore(CNodeHttpStoredContext * context, REQUEST_NOTIFICATION_STATUS status, HRESULT error, CNodeEventProvider* log, PCWSTR etw, UCHAR level); + static HRESULT FinalizeResponseCore(CNodeHttpStoredContext * context, REQUEST_NOTIFICATION_STATUS status, HRESULT error, BOOL *pfCompletionPosted, CNodeEventProvider* log, PCWSTR etw, UCHAR level); static BOOL IsLocalCall(IHttpContext* ctx); static BOOL SendDevError(CNodeHttpStoredContext* context, USHORT status, USHORT subStatus, PCTSTR reason, HRESULT hresult, BOOL disableCache = FALSE); static HRESULT AddDebugHeader(CNodeHttpStoredContext* context); // processing stages - static void WINAPI ChildContextCompleted(DWORD error, DWORD bytesTransfered, LPOVERLAPPED overlapped); - static void WINAPI CreateNamedPipeConnection(DWORD error, DWORD bytesTransfered, LPOVERLAPPED overlapped); + static void WINAPI ChildContextCompleted(DWORD error, DWORD bytesTransfered, LPOVERLAPPED overlapped, BOOL * fCompletionPosted); + static void WINAPI CreateNamedPipeConnection(DWORD error, DWORD bytesTransfered, LPOVERLAPPED overlapped, BOOL * fCompletionPosted); - static void SendHttpRequestHeaders(CNodeHttpStoredContext* context); - static void WINAPI SendHttpRequestHeadersCompleted(DWORD error, DWORD bytesTransfered, LPOVERLAPPED overlapped); + static void SendHttpRequestHeaders(CNodeHttpStoredContext* context, BOOL *pfCompletionPosted); + static void WINAPI SendHttpRequestHeadersCompleted(DWORD error, DWORD bytesTransfered, LPOVERLAPPED overlapped, BOOL * fCompletionPosted); - static void ReadRequestBody(CNodeHttpStoredContext* context); - static void WINAPI ReadRequestBodyCompleted(DWORD error, DWORD bytesTransfered, LPOVERLAPPED overlapped); + static void ReadRequestBody(CNodeHttpStoredContext* context, BOOL * fCompletionPosted); + static void WINAPI ReadRequestBodyCompleted(DWORD error, DWORD bytesTransfered, LPOVERLAPPED overlapped, BOOL * fCompletionPosted); - static void SendRequestBody(CNodeHttpStoredContext* context, DWORD chunkLength); - static void WINAPI SendRequestBodyCompleted(DWORD error, DWORD bytesTransfered, LPOVERLAPPED overlapped); + static void SendRequestBody(CNodeHttpStoredContext* context, DWORD chunkLength, BOOL *pfCompletionPosted); + static void WINAPI SendRequestBodyCompleted(DWORD error, DWORD bytesTransfered, LPOVERLAPPED overlapped, BOOL * fCompletionPosted); - static void StartReadResponse(CNodeHttpStoredContext* context); - static void ContinueReadResponse(CNodeHttpStoredContext* context); - static void WINAPI ProcessResponseStatusLine(DWORD error, DWORD bytesTransfered, LPOVERLAPPED overlapped); - static void WINAPI ProcessResponseHeaders(DWORD error, DWORD bytesTransfered, LPOVERLAPPED overlapped); + static void StartReadResponse(CNodeHttpStoredContext* context, BOOL *pfCompletionPosted); + static void ContinueReadResponse(CNodeHttpStoredContext* context, BOOL *pfCompletionPosted); + static void WINAPI ProcessResponseStatusLine(DWORD error, DWORD bytesTransfered, LPOVERLAPPED overlapped, BOOL * fCompletionPosted); + static void WINAPI ProcessResponseHeaders(DWORD error, DWORD bytesTransfered, LPOVERLAPPED overlapped, BOOL * fCompletionPosted); - static void WINAPI ProcessChunkHeader(DWORD error, DWORD bytesTransfered, LPOVERLAPPED overlapped); - static void WINAPI ProcessResponseBody(DWORD error, DWORD bytesTransfered, LPOVERLAPPED overlapped); + static void WINAPI ProcessChunkHeader(DWORD error, DWORD bytesTransfered, LPOVERLAPPED overlapped, BOOL * fCompletionPosted); + static void WINAPI ProcessResponseBody(DWORD error, DWORD bytesTransfered, LPOVERLAPPED overlapped, BOOL * fCompletionPosted); - static void WINAPI ProcessUpgradeResponse(DWORD error, DWORD bytesTransfered, LPOVERLAPPED overlapped); - static void WINAPI ContinueProcessResponseBodyAfterPartialFlush(DWORD error, DWORD bytesTransfered, LPOVERLAPPED overlapped); + static void WINAPI ProcessUpgradeResponse(DWORD error, DWORD bytesTransfered, LPOVERLAPPED overlapped, BOOL * fCompletionPosted); + static void WINAPI ContinueProcessResponseBodyAfterPartialFlush(DWORD error, DWORD bytesTransfered, LPOVERLAPPED overlapped, BOOL * fCompletionPosted); - static void EnsureRequestPumpStarted(CNodeHttpStoredContext* context); + static void EnsureRequestPumpStarted(CNodeHttpStoredContext* context, BOOL *pfCompletionPosted); - static void FinalizeResponse(CNodeHttpStoredContext* context); - static void FinalizeUpgradeResponse(CNodeHttpStoredContext* context, HRESULT hresult); + static void FinalizeResponse(CNodeHttpStoredContext* context, BOOL *pfCompletionPosted); + static void FinalizeUpgradeResponse(CNodeHttpStoredContext* context, HRESULT hresult, BOOL *pfCompletionPosted); public: - static void WINAPI SendResponseBodyCompleted(DWORD error, DWORD bytesTransfered, LPOVERLAPPED overlapped); + static void WINAPI SendResponseBodyCompleted(DWORD error, DWORD bytesTransfered, LPOVERLAPPED overlapped, BOOL * fCompletionPosted); static HRESULT InitiateRequest(CNodeHttpStoredContext* context); static BOOL SendIisnodeError(IHttpContext* httpCtx, HRESULT hr); static BOOL SendIisnodeError(CNodeHttpStoredContext* ctx, HRESULT hr); - static HRESULT SendEmptyResponse(CNodeHttpStoredContext* context, USHORT status, USHORT subStatus, PCTSTR reason, HRESULT hresult, BOOL disableCache = FALSE); + static HRESULT SendEmptyResponse(CNodeHttpStoredContext* context, USHORT status, USHORT subStatus, PCTSTR reason, HRESULT hresult, BOOL *pfCompletionPosted, BOOL disableCache = FALSE); static HRESULT SendSyncResponse(IHttpContext* httpCtx, USHORT status, PCTSTR reason, HRESULT hresult, BOOL disableCache, PCSTR htmlBody); static void SendEmptyResponse(IHttpContext* httpCtx, USHORT status, USHORT subStatus, PCTSTR reason, HRESULT hresult, BOOL disableCache = FALSE); static HRESULT SendDebugRedirect(CNodeHttpStoredContext* context, CNodeEventProvider* log); diff --git a/src/version.txt b/src/version.txt index d88290b2..e1bd0c6a 100644 --- a/src/version.txt +++ b/src/version.txt @@ -1 +1 @@ -0.2.21 +0.2.23 From 9b05ea4c6023c3138a52d67aa590f35bb6010e25 Mon Sep 17 00:00:00 2001 From: Ranjith Mukkai Ramachandra Date: Sun, 19 Feb 2017 12:19:15 -0800 Subject: [PATCH 06/17] node sticky sessions fix --- src/iisnode/cnodeprocessmanager.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/iisnode/cnodeprocessmanager.cpp b/src/iisnode/cnodeprocessmanager.cpp index ea29394c..4d02f263 100644 --- a/src/iisnode/cnodeprocessmanager.cpp +++ b/src/iisnode/cnodeprocessmanager.cpp @@ -135,11 +135,19 @@ int CNodeProcessManager::ExtractStickySessionsProcess( PCSTR pszCookie ) pEnd = pStart; while (*pEnd) /* Works because end-of-string and FALSE are identical. */ { + if((pEnd - pStart) >= sizeof(acProcess)) + { + break; + } pEnd++; } } - memcpy(acProcess, pStart, pEnd - pStart); // copy result - return atoi(acProcess); + + if((pEnd - pStart) < sizeof(acProcess)) + { + memcpy(acProcess, pStart, pEnd - pStart); // copy result + return atoi(acProcess); + } } } } From 1183694d376e874df60e9c7a20a264c31d80935f Mon Sep 17 00:00:00 2001 From: Ranjith Mukkai Ramachandra Date: Sun, 19 Feb 2017 12:20:06 -0800 Subject: [PATCH 07/17] Increase version to 0.2.24 --- src/version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/version.txt b/src/version.txt index e1bd0c6a..905c198e 100644 --- a/src/version.txt +++ b/src/version.txt @@ -1 +1 @@ -0.2.23 +0.2.24 From 2c5c85f3390fdc80120f1674bbbf26b46180164c Mon Sep 17 00:00:00 2001 From: Ranjith Mukkai Ramachandra Date: Sun, 19 Feb 2017 20:03:12 -0800 Subject: [PATCH 08/17] Fix w3wp crash when flushResponse=true --- src/iisnode/cprotocolbridge.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/iisnode/cprotocolbridge.cpp b/src/iisnode/cprotocolbridge.cpp index 83bf6a23..905199f9 100644 --- a/src/iisnode/cprotocolbridge.cpp +++ b/src/iisnode/cprotocolbridge.cpp @@ -1804,6 +1804,7 @@ void WINAPI CProtocolBridge::SendResponseBodyCompleted(DWORD error, DWORD bytesT CNodeHttpStoredContext* ctx = CNodeHttpStoredContext::Get(overlapped); DWORD bytesSent; BOOL completionExpected = FALSE; + BOOL fReference = FALSE; CheckError(error); @@ -1830,12 +1831,18 @@ void WINAPI CProtocolBridge::SendResponseBodyCompleted(DWORD error, DWORD bytesT ctx->SetNextProcessor(CProtocolBridge::ContinueProcessResponseBodyAfterPartialFlush); ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(ctx->GetHttpContext(), L"iisnode initiated flushing http response body chunk", WINEVENT_LEVEL_VERBOSE, ctx->GetActivityId()); + ctx->ReferenceNodeHttpStoredContext(); + fReference = TRUE; ctx->GetHttpContext()->GetResponse()->Flush(TRUE, TRUE, &bytesSent, &completionExpected); } if (!completionExpected) { CProtocolBridge::ContinueProcessResponseBodyAfterPartialFlush(S_OK, 0, ctx->GetOverlapped(), pfCompletionPosted); + if(fReference) + { + ctx->DereferenceNodeHttpStoredContext(); + } } } @@ -1864,18 +1871,20 @@ void WINAPI CProtocolBridge::SendResponseBodyCompleted(DWORD error, DWORD bytesT void WINAPI CProtocolBridge::ProcessUpgradeResponse(DWORD error, DWORD bytesTransfered, LPOVERLAPPED overlapped, BOOL * pfCompletionPosted) { - BOOL completionExpected; + BOOL completionExpected = FALSE; DWORD bytesSent; CNodeHttpStoredContext* ctx = CNodeHttpStoredContext::Get(overlapped); ctx->SetNextProcessor(CProtocolBridge::ContinueProcessResponseBodyAfterPartialFlush); ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(ctx->GetHttpContext(), L"iisnode initiated flushing http upgrade response headers", WINEVENT_LEVEL_VERBOSE, ctx->GetActivityId()); + ctx->ReferenceNodeHttpStoredContext(); ctx->GetHttpContext()->GetResponse()->Flush(TRUE, TRUE, &bytesSent, &completionExpected); if (!completionExpected) { CProtocolBridge::ContinueProcessResponseBodyAfterPartialFlush(S_OK, 0, ctx->GetOverlapped(), pfCompletionPosted); + ctx->DereferenceNodeHttpStoredContext(); } } From da4e5e1f3843dec979f8c9d0a72851cf5f3487c0 Mon Sep 17 00:00:00 2001 From: Ranjith Mukkai Ramachandra Date: Sun, 19 Feb 2017 20:03:44 -0800 Subject: [PATCH 09/17] Increase version to 0.2.25 --- src/version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/version.txt b/src/version.txt index 905c198e..84a6a30d 100644 --- a/src/version.txt +++ b/src/version.txt @@ -1 +1 @@ -0.2.24 +0.2.25 From 1bf74c5f66aed1d2290f8333cb1bf5b8624e71b6 Mon Sep 17 00:00:00 2001 From: Ranjith Mukkai Ramachandra Date: Tue, 21 Feb 2017 14:53:30 -0800 Subject: [PATCH 10/17] Fix context RefCount when debugger is enabled --- src/iisnode/cprotocolbridge.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/iisnode/cprotocolbridge.cpp b/src/iisnode/cprotocolbridge.cpp index 905199f9..980d600e 100644 --- a/src/iisnode/cprotocolbridge.cpp +++ b/src/iisnode/cprotocolbridge.cpp @@ -539,11 +539,14 @@ HRESULT CProtocolBridge::InitiateRequest(CNodeHttpStoredContext* context) CheckError(child->GetRequest()->SetUrl(context->GetTargetUrl(), context->GetTargetUrlLength(), FALSE)); context->SetChildContext(child); context->SetNextProcessor(CProtocolBridge::ChildContextCompleted); - + + context->ReferenceNodeHttpStoredContext(); + CheckError(context->GetHttpContext()->ExecuteRequest(TRUE, child, 0, NULL, &completionExpected)); if (!completionExpected) { CProtocolBridge::ChildContextCompleted(S_OK, 0, context->GetOverlapped(), &fCompletionPosted); + context->DereferenceNodeHttpStoredContext(); } } else From c53c71e4b8ea7287785e2d4775120d14315627a0 Mon Sep 17 00:00:00 2001 From: Ranjith Mukkai Ramachandra Date: Tue, 21 Feb 2017 14:53:55 -0800 Subject: [PATCH 11/17] Fix context RefCount when debugger is enabled v0.2.26 --- src/version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/version.txt b/src/version.txt index 84a6a30d..7ada3a2d 100644 --- a/src/version.txt +++ b/src/version.txt @@ -1 +1 @@ -0.2.25 +0.2.26 From 6478fdea206547c4e1b0b0bb97186368d5a05f56 Mon Sep 17 00:00:00 2001 From: Ranjith Mukkai Ramachandra Date: Tue, 21 Feb 2017 14:56:02 -0800 Subject: [PATCH 12/17] Fix context RefCount when debugger is enabled v0.2.26 --- src/iisnode/cprotocolbridge.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/iisnode/cprotocolbridge.cpp b/src/iisnode/cprotocolbridge.cpp index 980d600e..ec7b2a75 100644 --- a/src/iisnode/cprotocolbridge.cpp +++ b/src/iisnode/cprotocolbridge.cpp @@ -481,6 +481,7 @@ HRESULT CProtocolBridge::InitiateRequest(CNodeHttpStoredContext* context) IHttpContext* child = NULL; BOOL completionExpected; BOOL fCompletionPosted = FALSE; + BOOL fReference = FALSE; // determine what the target path of the request is @@ -541,12 +542,14 @@ HRESULT CProtocolBridge::InitiateRequest(CNodeHttpStoredContext* context) context->SetNextProcessor(CProtocolBridge::ChildContextCompleted); context->ReferenceNodeHttpStoredContext(); + fReference = TRUE; CheckError(context->GetHttpContext()->ExecuteRequest(TRUE, child, 0, NULL, &completionExpected)); if (!completionExpected) { CProtocolBridge::ChildContextCompleted(S_OK, 0, context->GetOverlapped(), &fCompletionPosted); context->DereferenceNodeHttpStoredContext(); + fReference = FALSE; } } else @@ -565,6 +568,11 @@ HRESULT CProtocolBridge::InitiateRequest(CNodeHttpStoredContext* context) context->SetChildContext(NULL); } + if(fReference) + { + context->DereferenceNodeHttpStoredContext(); + } + return hr; } From d8f9f59f25073869ca54b30de943e9ca163eb70e Mon Sep 17 00:00:00 2001 From: Jenny Lawrance Date: Wed, 17 Jan 2018 14:18:54 -0800 Subject: [PATCH 13/17] iisnode crash fix --- src/iisnode/cnodehttpmodule.cpp | 11 +++++++++++ src/version.txt | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/iisnode/cnodehttpmodule.cpp b/src/iisnode/cnodehttpmodule.cpp index 0ca88d7f..a4876b68 100644 --- a/src/iisnode/cnodehttpmodule.cpp +++ b/src/iisnode/cnodehttpmodule.cpp @@ -239,6 +239,17 @@ REQUEST_NOTIFICATION_STATUS CNodeHttpModule::OnAsyncCompletion( // result = RQ_NOTIFICATION_CONTINUE; } + else + { + if (0 == value) // decreases ref count set to 1 in the ctor of CNodeHttpStoredContext + { + result = ctx->GetRequestNotificationStatus(); + } + else + { + result = RQ_NOTIFICATION_PENDING; + } + } switch (result) { diff --git a/src/version.txt b/src/version.txt index 7ada3a2d..18de5ee1 100644 --- a/src/version.txt +++ b/src/version.txt @@ -1 +1 @@ -0.2.26 +0.2.27 From 3f5df2355033d316e5c73da524ddadafe83fe863 Mon Sep 17 00:00:00 2001 From: Maxim Malov Date: Mon, 8 Oct 2018 15:22:33 +0600 Subject: [PATCH 14/17] Remove advertisement link From https://github.com/tjanczuk/iisnode/pull/634 --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 73fa4b5e..53563560 100644 --- a/README.md +++ b/README.md @@ -50,7 +50,6 @@ This can be a head-scratcher since IIS Express 8 gives you both 32-bit and 64-bi **Howtos** ======= - [the basics](http://tomasz.janczuk.org/2011/08/hosting-nodejs-applications-in-iis-on.html) -- [the basics (Pусский перевод)](http://softdroid.net/hosting-nodejs-applications-ru) - [**NEW: websockets**] (http://tomasz.janczuk.org/2012/11/how-to-use-websockets-with-nodejs-apps.html) - [using with express framework](http://tomasz.janczuk.org/2011/08/hosting-express-nodejs-applications-in.html) - [using with URL rewrite module](http://tomasz.janczuk.org/2011/08/using-url-rewriting-with-nodejs.html) From aeab97217c79c4688babd2d6770dcff0368cffe6 Mon Sep 17 00:00:00 2001 From: Matt Ezell Date: Wed, 10 Oct 2018 09:24:23 -0500 Subject: [PATCH 15/17] Replaced debugging link Previous debugging link now takes you to a product sales site. I've replaced the bad link with an updated link which demonstrates how to debug IISNode hosted applications via VSCode --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 53563560..130404da 100644 --- a/README.md +++ b/README.md @@ -60,7 +60,7 @@ This can be a head-scratcher since IIS Express 8 gives you both 32-bit and 64-bi - [using with MVC](http://weblogs.asp.net/jgalloway/archive/2011/10/26/using-node-js-in-an-asp-net-mvc-application-with-iisnode.aspx) - [portuguese: node.js no windows: instalando o iisnode](http://vivina.com.br/nodejs-windows-parte-2) - [integrated debugging](http://tomasz.janczuk.org/2011/11/debug-nodejs-applications-on-windows.html) -- [**NEW: integrated debugging with node-inspector v0.7.3**](http://www.ranjithr.com/?p=98) +- [Debugging via VSCode](https://blog.immatt.com/2018/10/09/iisnode-modern-debugging-via-vscode/) - [pub/sub server using faye](http://weblogs.asp.net/cibrax/archive/2011/12/12/transform-your-iis-into-a-real-time-pub-sub-engine-with-faye-node.aspx) - [appharbor uses iisnode](http://blog.appharbor.com/2012/01/19/announcing-node-js-support) From 247d1e4ddb4be12072a202a35c43dfbdc96cbeb0 Mon Sep 17 00:00:00 2001 From: Purva Vasudeo Date: Thu, 9 Jul 2020 10:45:23 -0700 Subject: [PATCH 16/17] Clean old handle before creating a new one Clean old handle before creating a new one --- src/iisnode/cprotocolbridge.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/iisnode/cprotocolbridge.cpp b/src/iisnode/cprotocolbridge.cpp index ec7b2a75..996af08f 100644 --- a/src/iisnode/cprotocolbridge.cpp +++ b/src/iisnode/cprotocolbridge.cpp @@ -626,6 +626,12 @@ void WINAPI CProtocolBridge::CreateNamedPipeConnection(DWORD error, DWORD bytesT if (INVALID_HANDLE_VALUE == pipe) { + // Clean up old pipe handle, otherwise there will be a handle leak + HANDLE oldPipe = ctx->GetPipe(); + if (oldPipe != NULL && oldPipe != INVALID_HANDLE_VALUE) { + CloseHandle(oldPipe); + } + ErrorIf(INVALID_HANDLE_VALUE == (pipe = CreateFile( ctx->GetNodeProcess()->GetNamedPipeName(), GENERIC_READ | GENERIC_WRITE, From e0180d75e0a1b104b9fa985adc8374ba2110818d Mon Sep 17 00:00:00 2001 From: "microsoft-github-policy-service[bot]" <77245923+microsoft-github-policy-service[bot]@users.noreply.github.com> Date: Mon, 28 Nov 2022 19:36:10 +0000 Subject: [PATCH 17/17] Microsoft mandatory file --- SECURITY.md | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 SECURITY.md diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 00000000..e138ec5d --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,41 @@ + + +## Security + +Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/). + +If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/opensource/security/definition), please report it to us as described below. + +## Reporting Security Issues + +**Please do not report security vulnerabilities through public GitHub issues.** + +Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/opensource/security/create-report). + +If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/opensource/security/pgpkey). + +You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://aka.ms/opensource/security/msrc). + +Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue: + + * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) + * Full paths of source file(s) related to the manifestation of the issue + * The location of the affected source code (tag/branch/commit or direct URL) + * Any special configuration required to reproduce the issue + * Step-by-step instructions to reproduce the issue + * Proof-of-concept or exploit code (if possible) + * Impact of the issue, including how an attacker might exploit the issue + +This information will help us triage your report more quickly. + +If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/opensource/security/bounty) page for more details about our active programs. + +## Preferred Languages + +We prefer all communications to be in English. + +## Policy + +Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/opensource/security/cvd). + +