Jeff Sanders Technical Blog

I am a Microsoft employee that has worked on all aspects of the Web Stack for a long time. I hope these blogs are useful to you! Use this information at your own risk.


<< Go Back

A Simple Wildcard Mapped Isapi Extension To Remove A Header

- 20 Jun 2011

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 #include

// basic pass-through ISAPI extension
// based on the C++ sample ISAPI extension at http://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;
    &nb
sp;               }

                    //
                    // 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);
                    }
                 &n
bsp;  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!

<< Go Back