diff --git a/src/config/iisnode_dev_x64.xml b/src/config/iisnode_dev_x64.xml index 9d6a435c..5f59502e 100644 --- a/src/config/iisnode_dev_x64.xml +++ b/src/config/iisnode_dev_x64.xml @@ -60,6 +60,7 @@ 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 ab17fba8..8789c487 100644 --- a/src/config/iisnode_dev_x86_on_x64.xml +++ b/src/config/iisnode_dev_x86_on_x64.xml @@ -60,6 +60,7 @@ 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 efab7f7d..a52700db 100644 --- a/src/config/iisnode_dev_x86_on_x86.xml +++ b/src/config/iisnode_dev_x86_on_x86.xml @@ -60,6 +60,7 @@ 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 a6c95a85..186d9a48 100644 --- a/src/config/iisnode_express_schema.xml +++ b/src/config/iisnode_express_schema.xml @@ -60,6 +60,7 @@ 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 fb39746b..c3b05704 100644 --- a/src/config/iisnode_express_schema_x64.xml +++ b/src/config/iisnode_express_schema_x64.xml @@ -60,6 +60,7 @@ 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 62e8004f..e78d76ce 100644 --- a/src/config/iisnode_schema.xml +++ b/src/config/iisnode_schema.xml @@ -60,6 +60,7 @@ 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 f1561969..b332a675 100644 --- a/src/config/iisnode_schema_x64.xml +++ b/src/config/iisnode_schema_x64.xml @@ -60,6 +60,7 @@ Details at http://learn.iis.net/page.aspx/241/configuration-extensibility/ + " diff --git a/src/iisnode/chttpprotocol.cpp b/src/iisnode/chttpprotocol.cpp index 4e70f92c..22e67c18 100644 --- a/src/iisnode/chttpprotocol.cpp +++ b/src/iisnode/chttpprotocol.cpp @@ -364,7 +364,20 @@ HRESULT CHttpProtocol::ParseResponseStatusLine(CNodeHttpStoredContext* context) data[newOffset] = 0; // zero-terminate the reason phrase to reuse it without copying IHttpResponse* response = context->GetHttpContext()->GetResponse(); - response->SetStatus(statusCode, data + offset, subStatusCode); + + if (CModuleConfiguration::GetSkipIISCustomErrors(context->GetHttpContext())) + { + // set fTrySkipCustomErrors so that error responses sent back from the node app through iisnode + // are passed through to the client instead of being intercepted by IIS when httpErrors existingResponse="Auto" + // this allows a mixed solution where custom error pages can be provided via IIS for errors that occur outside + // of iisnode's purview, while also allowing usually-more-helpful error responses from the node application + // to be passed through to the client rather than being intercepted by IIS. + response->SetStatus(statusCode, data + offset, subStatusCode, S_OK, NULL, TRUE); + } + else + { + response->SetStatus(statusCode, data + offset, subStatusCode); + } // adjust buffers diff --git a/src/iisnode/cmoduleconfiguration.cpp b/src/iisnode/cmoduleconfiguration.cpp index 3562ddd8..e2d193fc 100644 --- a/src/iisnode/cmoduleconfiguration.cpp +++ b/src/iisnode/cmoduleconfiguration.cpp @@ -898,6 +898,10 @@ HRESULT CModuleConfiguration::ApplyConfigOverrideKeyValue(IHttpContext* context, { CheckError(GetDWORD(valueStart, &config->idlePageOutTimePeriod)); } + else if(0 == stricmp(keyStart, "skipIISCustomErrors")) + { + CheckError(GetBOOL(valueStart, &config->skipIISCustomErrors)); + } return S_OK; Error: @@ -1258,6 +1262,7 @@ HRESULT CModuleConfiguration::GetConfig(IHttpContext* context, CModuleConfigurat CheckError(GetString(section, L"nodeProcessCommandLine", &c->nodeProcessCommandLine)); CheckError(GetString(section, L"interceptor", &c->interceptor)); CheckError(GetDWORD(section, L"idlePageOutTimePeriod", &c->idlePageOutTimePeriod)); + CheckError(GetBOOL(section, L"skipIISCustomErrors", &c->skipIISCustomErrors, FALSE)); // debuggerPathSegment @@ -1504,6 +1509,11 @@ LPWSTR CModuleConfiguration::GetConfigOverrides(IHttpContext* ctx) GETCONFIG(configOverrides) } +BOOL CModuleConfiguration::GetSkipIISCustomErrors(IHttpContext* ctx) +{ + GETCONFIG(skipIISCustomErrors) +} + HRESULT CModuleConfiguration::GenerateDebuggerConfig(IHttpContext* context, CModuleConfiguration *config) { HRESULT hr = S_OK; @@ -1592,12 +1602,12 @@ HRESULT CModuleConfiguration::GetDebuggerFilesPathSegmentHelper( DWORD *pdwDebuggerFilesPathSegmentSize ) { - HRESULT hr = S_OK; - HCRYPTPROV hProv = 0; + HRESULT hr = S_OK; + HCRYPTPROV hProv = 0; HCRYPTHASH hHash = 0; CHAR rgbDigits[] = "0123456789abcdef"; - BYTE rgbHash[32]; // sha256 ==> 32 bytes. - DWORD cbHash = 0; + BYTE rgbHash[32]; // sha256 ==> 32 bytes. + DWORD cbHash = 0; CHAR shaHash[MAX_HASH_CHAR + 1]; // we will only use first MAX_HASH_CHAR bytes of the sha256 hash ==> 32 hex chars. DWORD dwSHALength = 0; CHAR *pInput = NULL; @@ -1615,27 +1625,27 @@ HRESULT CModuleConfiguration::GetDebuggerFilesPathSegmentHelper( ErrorIf(dwInputSize != WideCharToMultiByte(CP_ACP, 0, pszScriptPath, dwScriptPathLen, pInput, dwInputSize, NULL, NULL), E_FAIL); pInput[dwInputSize] = '\0'; - // Get handle to the crypto provider - ErrorIf(!CryptAcquireContext(&hProv, - NULL, - NULL, - PROV_RSA_AES, - CRYPT_VERIFYCONTEXT), HRESULT_FROM_WIN32(GetLastError())); - + // Get handle to the crypto provider + ErrorIf(!CryptAcquireContext(&hProv, + NULL, + NULL, + PROV_RSA_AES, + CRYPT_VERIFYCONTEXT), HRESULT_FROM_WIN32(GetLastError())); + ErrorIf(!CryptCreateHash(hProv, CALG_SHA_256, 0, 0, &hHash), HRESULT_FROM_WIN32(GetLastError())); ErrorIf(!CryptHashData(hHash, (BYTE*) pInput, strnlen_s(pInput, dwInputSize), 0), HRESULT_FROM_WIN32(GetLastError())); // sha256 ==> 32 bytes. - cbHash = 32; - ErrorIf(!CryptGetHashParam(hHash, HP_HASHVAL, rgbHash, &cbHash, 0), HRESULT_FROM_WIN32(GetLastError())); - - dwIndex = 0; - // convert first (MAX_HASH_CHAR / 2) bytes to hexadecimal form. - for (DWORD i = 0; i < (MAX_HASH_CHAR / 2); i++, dwIndex=dwIndex+2) - { - shaHash[dwIndex] = rgbDigits[rgbHash[i] >> 4]; - shaHash[dwIndex+1] = rgbDigits[rgbHash[i] & 0xf]; + cbHash = 32; + ErrorIf(!CryptGetHashParam(hHash, HP_HASHVAL, rgbHash, &cbHash, 0), HRESULT_FROM_WIN32(GetLastError())); + + dwIndex = 0; + // convert first (MAX_HASH_CHAR / 2) bytes to hexadecimal form. + for (DWORD i = 0; i < (MAX_HASH_CHAR / 2); i++, dwIndex=dwIndex+2) + { + shaHash[dwIndex] = rgbDigits[rgbHash[i] >> 4]; + shaHash[dwIndex+1] = rgbDigits[rgbHash[i] & 0xf]; } shaHash[dwIndex] = '\0'; diff --git a/src/iisnode/cmoduleconfiguration.h b/src/iisnode/cmoduleconfiguration.h index 8151cd3b..2b01bd16 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 skipIISCustomErrors; BOOL nodeProcessStickySessions; static IHttpServer* server; @@ -130,6 +131,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 GetSkipIISCustomErrors(IHttpContext* ctx); static BOOL GetProcessStickySessions(IHttpContext* ctx); static HRESULT CreateNodeEnvironment(IHttpContext* ctx, DWORD debugPort, PCH namedPipe, PCH signalPipeName, PCH* env); @@ -139,4 +141,4 @@ class CModuleConfiguration : public IHttpStoredContext virtual void CleanupStoredContext(); }; -#endif \ No newline at end of file +#endif diff --git a/src/iisnode/cprotocolbridge.cpp b/src/iisnode/cprotocolbridge.cpp index ec7b2a75..4f0241ec 100644 --- a/src/iisnode/cprotocolbridge.cpp +++ b/src/iisnode/cprotocolbridge.cpp @@ -465,7 +465,11 @@ void CProtocolBridge::SendEmptyResponse(IHttpContext* httpCtx, USHORT status, US if (!httpCtx->GetResponseHeadersSent()) { httpCtx->GetResponse()->Clear(); + + // Internal iisnode errors should probably not set fTrySkipCustomErrors since these are just empty status responses. + // Let IIS capture and replace these responses with more detailed messages depending on the custom error mode. httpCtx->GetResponse()->SetStatus(status, reason, subStatus, hresult); + if (disableCache) { httpCtx->GetResponse()->SetHeader(HttpHeaderCacheControl, "no-cache", 8, TRUE); diff --git a/src/samples/configuration/iisnode.yml b/src/samples/configuration/iisnode.yml index 415b0bf9..76e1be42 100644 --- a/src/samples/configuration/iisnode.yml +++ b/src/samples/configuration/iisnode.yml @@ -141,4 +141,7 @@ enableXFF: false # HTTP request headers; for a list of IIS server variables available see # http://msdn.microsoft.com/en-us/library/ms524602(v=vs.90).aspx; for example "AUTH_USER,AUTH_TYPE" -promoteServerVars: \ No newline at end of file +promoteServerVars: + +# skipIISCustomErrors - controls whether iisnode will try to skip IIS custom error handling when existingResponse="Auto" +skipIISCustomErrors: false \ No newline at end of file diff --git a/src/samples/configuration/readme.htm b/src/samples/configuration/readme.htm index 7dacba7b..1408ec6e 100644 --- a/src/samples/configuration/readme.htm +++ b/src/samples/configuration/readme.htm @@ -145,6 +145,8 @@

maxRequestBufferSize: 8192 # increasing from the default # maxConcurrentRequestsPerProcess: 512 - commented out setting + * skipIISCustomErrors - controls whether iisnode will try to skip IIS >httpErrors< custom error handling when existingResponse="Auto" + --> <iisnode @@ -175,6 +177,7 @@

enableXFF="false" promoteServerVars="" configOverrides="node.conf" + skipIISCustomErrors="false" /> <!-- @@ -335,6 +338,10 @@

# HTTP request headers; for a list of IIS server variables available see # http://msdn.microsoft.com/en-us/library/ms524602(v=vs.90).aspx; for example "AUTH_USER,AUTH_TYPE" -promoteServerVars: +promoteServerVars: + +# skipIISCustomErrors - controls whether iisnode will try to skip IIS >httpErrors< custom error handling when existingResponse="Auto" +skipIISCustomErrors: false + diff --git a/src/samples/configuration/web.config b/src/samples/configuration/web.config index fed9441e..51fb003a 100644 --- a/src/samples/configuration/web.config +++ b/src/samples/configuration/web.config @@ -109,6 +109,8 @@ nodeProcessCountPerApplication: 2 maxRequestBufferSize: 8192 # increasing from the default # maxConcurrentRequestsPerProcess: 512 - commented out setting + + * skipIISCustomErrors - controls whether iisnode will try to skip IIS custom error handling when existingResponse="Auto" --> @@ -140,6 +142,7 @@ enableXFF="false" promoteServerVars="" configOverrides="iisnode.yml" + skipIISCustomErrors="false" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file