A simple WildCard mapped ISAPI extension, to remove a header
I needed a simple WildCard Extension to remove a header and could not find one. This needs a little more error checking code but can get the job done. If you use it and add some enhancements or find problems, let me know and I will tune up the example!
#include <windows.h>
#include <httpext.h>
// basic pass-through ISAPI extension
// based on the C++ sample ISAPI extension at https://msdn.microsoft.com/en-us/library/ms525758(v=vs.90).aspx#Y1930
//
BOOL WINAPI GetExtensionVersion( HSE_VERSION_INFO *pVer )
{
return TRUE;
}
// here we have the ability to clean up any memory we may have allocated.
VOID WINAPI ExecuteUrlCompletionCallback( LPEXTENSION_CONTROL_BLOCK pECB,
PVOID pUrlInfo,
DWORD /* cbIO */,
DWORD /* dwError */ )
{
HSE_EXEC_UNICODE_URL_INFO *pHseExecUrlInfo = (HSE_EXEC_UNICODE_URL_INFO *)pUrlInfo;
HSE_EXEC_URL_STATUS hseExecUrlStatus;
// Set HTTP Status code on ISAPI so that logging works properly
// cbIO and dwError should always be 0
if ( !pECB->ServerSupportFunction( pECB->ConnID,
HSE_REQ_GET_EXEC_URL_STATUS,
&hseExecUrlStatus,
NULL,
NULL ) )
{
OutputDebugString("ExecuteUrlCompletionCallback: Was not able to fetch the HTTP status code.\n");
}
else
{
OutputDebugString("ExecuteUrlCompletionCallback: propagating HTTP status code.\n");
pECB->dwHttpStatusCode = hseExecUrlStatus.uHttpStatusCode;
SetLastError( hseExecUrlStatus.dwWin32Error );
}
(void)pECB->ServerSupportFunction ( pECB->ConnID,
HSE_REQ_DONE_WITH_SESSION,
NULL,
NULL,
NULL );
if(pHseExecUrlInfo)
{
if (pHseExecUrlInfo->pszChildHeaders)
{
OutputDebugString("ExecuteUrlCompletionCallback: status set, freeing pHseExecUrlInfo->pszChildHeaders.\n");
free(pHseExecUrlInfo->pszChildHeaders);
}
OutputDebugString("ExecuteUrlCompletionCallback: status set, freeing pHseExecUrlInfo.\n");
free(pHseExecUrlInfo);
}
else
{
OutputDebugString("ExecuteUrlCompletionCallback: status set, not freeing pHseExecUrlInfo because it's null.\n");
}
}
DWORD WINAPI HttpExtensionProc( EXTENSION_CONTROL_BLOCK *pECB )
{
HSE_EXEC_UNICODE_URL_INFO *pHseExecUrlInfo;
pHseExecUrlInfo = (HSE_EXEC_UNICODE_URL_INFO*)malloc(sizeof(HSE_EXEC_UNICODE_URL_INFO));
if(pHseExecUrlInfo)
{
ZeroMemory(pHseExecUrlInfo, sizeof(HSE_EXEC_UNICODE_URL_INFO) );
// get raw headers and look for transfer encoding chunked:
CHAR szBuf[MAX_PATH + 1];
CHAR* pszBuf = szBuf;
DWORD dwBuf = MAX_PATH + 1;
DWORD dwMaxBufSize = 1024;
LPSTR szVariableName = "ALL_RAW";
if ( !pECB->GetServerVariable(pECB->ConnID,
szVariableName,
pszBuf,
&dwBuf) )
{
if ( GetLastError() == ERROR_INSUFFICIENT_BUFFER )
{
//
// Not large enough buffer. Reallocate.
// Make sure to not reallocate size blindly (DoS)...
//
if ( dwBuf > dwMaxBufSize )
{
goto Failed;
}
pszBuf = new CHAR[dwBuf];
if ( pszBuf != NULL )
{
//
// Try GetServerVariable again
//
if ( !pECB->GetServerVariable(pECB->ConnID,
szVariableName,
pszBuf,
&dwBuf) )
{
//
// Unexpected failure. Fail
//
goto Failed;
}
//
// Successfully fetched value into heap buffer
//
}
else
{
//
// Failed to allocate memory. Fail
//
goto Failed;
}
}
else
{
//
// Deal with GetLastError() however you wish
// May optionally decide to fail
//
// GetLastError() == ERROR_INVALID_INDEX
// szVariableName is not a valid server variable name
//
goto Failed;
}
}
//
// pszBuf points to variable value. Use it.
// dwBuf indicates how big the buffer is (NULL included)
//
char *pFoundChunked = strstr(pszBuf,"chunked");
if (pFoundChunked!=NULL)
{
char *pFoundContentLen = strstr(pszBuf,"Content-Length:");
if (pFoundContentLen!=NULL)
{
char *pFoundTransferEncoding = strstr(pszBuf,"Transfer-Encoding:");
if (pFoundTransferEncoding != NULL)
{
// we have both Content-Length and chunked. Because of the issue with wildcard mapped extensions in IIS, we need to eliminate the
// chunked header.
char *newHeaders = (char *)malloc(sizeof(char)*dwBuf);
char *ptr=newHeaders;
//TODO add logic to ensure malloc succeeded!
// if there is a /r/n before this point we will copy all of the stuff before this header, otherwise
// this is the first header.
char *pFoundEndTransfer = strstr(pFoundTransferEncoding,"\r\n");
if (pFoundEndTransfer != NULL)
{
// get past the \r\n
pFoundEndTransfer++;
pFoundEndTransfer++;
if (pszBuf != pFoundTransferEncoding)
{
//first copy the headers before the chunked.
strncpy(ptr,pszBuf,pFoundTransferEncoding-pszBuf);
//now move past the end of the encoding
ptr+=pFoundTransferEncoding-pszBuf;
}
// copy from the end of the transfer header the rest of the headers
strcpy(ptr,pFoundEndTransfer);
}
else
{
// there is nothing after the encoding header
// Copy up until where we found the buffer.
strncpy(ptr,pszBuf,pFoundTransferEncoding-pszBuf);
ptr+= pFoundTransferEncoding-pszBuf;
ptr-=2; //remove terminating "\r\n"
//copy a null to terminate the string
*ptr='\0';
}
// set the new headers on the request!
pHseExecUrlInfo->pszChildHeaders = newHeaders;
}
}
}
//
// If we've allocated a buffer, cleanup
//
Failed:
if ( pszBuf != NULL &&
pszBuf != szBuf )
{
delete [] pszBuf;
}
if(pECB->ServerSupportFunction( pECB->ConnID,
HSE_REQ_IO_COMPLETION,
ExecuteUrlCompletionCallback,
NULL,
(LPDWORD)pHseExecUrlInfo ))
{
if( pECB->ServerSupportFunction( pECB->ConnID,
HSE_REQ_EXEC_UNICODE_URL,
pHseExecUrlInfo,
NULL,
NULL ) )
{
OutputDebugString("HttpExtensionProc_worker - done returning HSE_STATUS_PENDING\n");
return HSE_STATUS_PENDING;
} else {
OutputDebugString("HttpExtensionProc_worker - done returning HSE_STATUS_ERROR\n");
return HSE_STATUS_ERROR;
}
}
else
{
OutputDebugString("HttpExtensionProc_worker - HSE_REQ_IO_COMPLETION failed, returning HSE_STATUS_ERROR\n");
return HSE_STATUS_ERROR;
}
}
else
{
OutputDebugString("HttpExtensionProc_worker - malloc failed, returning HSE_STATUS_ERROR\n");
return HSE_STATUS_ERROR;
}
}
BOOL WINAPI TerminateExtension( DWORD dwFlags )
{
return TRUE;
}
Let me know if this helps you!