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
+