Dr. Dobb's is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.


Channels ▼
RSS

ISAPI Proxy Filters for IIS


October 2002/ISAPI Proxy Filters for IIS

Listing 1: Source for JRunProxy.cpp

// JRunProxy.cpp

#include "stdafx.h"
// stdafx.h defines WIN32_LEAN_AND_MEAN and includes
// windows.h, httpfilt.h, and malloc.h.

// Typedefs for the filter's exported functions:
typedef BOOL  (WINAPI *JRunGetFilterVersion)(PHTTP_FILTER_VERSION);
typedef DWORD (WINAPI *JRunHttpFilterProc)(PHTTP_FILTER_CONTEXT, DWORD, LPVOID);
typedef BOOL  (WINAPI *JRunTerminateFilter)(DWORD);

// Addresses of procedures in the JRun DLL:
JRunGetFilterVersion GetFilterVersionProcAddress = NULL;
JRunHttpFilterProc   HttpFilterProcProcAddress   = NULL;
JRunTerminateFilter  TerminateFilterProcAddress  = NULL;

// A handle to the JRun module:
HMODULE hModule = NULL;

// Called by IIS to obtain information about our filter:
BOOL WINAPI GetFilterVersion(PHTTP_FILTER_VERSION pfv)
{
    // Load the JRun DLL:
    hModule = LoadLibrary("C:\\INetPub\\scripts\\jrun.dll");
    if(hModule == NULL) // failed to load the JRun DLL.
       return FALSE; // can't continue.

    // Get the address of GetFilterVersion:
    GetFilterVersionProcAddress = 
        (JRunGetFilterVersion)GetProcAddress(hModule, "GetFilterVersion");
    if(GetFilterVersionProcAddress == NULL) // couldn't find GetFilterVersion.
        return FALSE; // can't continue.

    // Get the address of HttpFilterProc:
    HttpFilterProcProcAddress=
        (JRunHttpFilterProc)GetProcAddress(hModule, "HttpFilterProc");
    if(HttpFilterProcProcAddress == NULL) // couldn't find HttpFilterProc.
        return FALSE; // can't continue;

    // TerminateFilter is an optionally exported function.
    // We don't return FALSE if we can't find it.
    TerminateFilterProcAddress =
        (JRunTerminateFilter)GetProcAddress(hModule, "TerminateFilter");

    // Call JRun's GetFilterVersion:
    if((GetFilterVersionProcAddress)(pfv))
    {
        // Fill in our own values in the HTTP_FILTER_VERSION structure:
        pfv->dwFilterVersion = MAKELONG(0, 1); // version 1.0.

        strcpy(pfv->lpszFilterDesc, "JRunProxy Filter"); // description.
        // Change the filter priority to LOW:
        pfv->dwFlags &= ~SF_NOTIFY_ORDER_MASK; // remove existing priority.
        pfv->dwFlags |= SF_NOTIFY_ORDER_LOW; // set low priority.
        return TRUE; // OK.
    }
    else // JRun's GetFilterVersion failed.
    {
        return FALSE; // can't continue.
    }
}

// Get the value of an HTTP header. Must free returned char*.
char* GetHeader(
    PHTTP_FILTER_CONTEXT pFilterContext,
    PHTTP_FILTER_PREPROC_HEADERS pHeaders,
    char *szHeader)
{
    DWORD dwBufferSize = 0;
	
    // This will fail because the receiving buffer is NULL.  We 
    // do this do determine the size of buffer that is needed.
    if(!pHeaders->GetHeader(pFilterContext, szHeader, NULL, &dwBufferSize) &&
        GetLastError() == ERROR_INSUFFICIENT_BUFFER)
    {
        // GetHeader failed above as expected, now
        // allocate a buffer of the required size:
        char *szHeaderValue = (char*)malloc(dwBufferSize);
		
        if(szHeaderValue) // Memory allocated OK.
        {
            // Now get the value of the HTTP header:
            if(pHeaders->GetHeader(pFilterContext, 
                szHeader, szHeaderValue, &dwBufferSize))
            {
                // Found the value of the HTTP header OK.
                return szHeaderValue;
            }
			
            // Couldn't find the value of the requested HTTP
            // header, so to free the allocated memory:
            free(szHeaderValue);
        }
    }
	
    // Couldn't find a value for this header or some other error occurred.
    return NULL; 
}

// Returns TRUE if the notification should be handled by JRun.
BOOL RequestIsForJRun(
    PHTTP_FILTER_CONTEXT pFilterContext,
    PHTTP_FILTER_PREPROC_HEADERS pHeaders)
{
    // Assume request is not for JRun:
    BOOL bRequestIsForJRun = FALSE;

    // Get the value of the requested URL:
    char *szURL = GetHeader(pFilterContext, pHeaders, "URL");

    if(szURL) // Got the URL OK.
    {
        // Assume there is a default page set up in JRun:
        if(!strcmp(szURL, "/"))
        {
            bRequestIsForJRun = TRUE;
        }
        else // Is the request for a JavaServer Page (JSP) or servlet?
        {
            // Check for .jsp extension:
            char *pch = strrchr(szURL, '.');

            if(pch && !stricmp(pch, ".jsp"))
            {
                bRequestIsForJRun = TRUE; // request is for a JSP.
            }
            else
            {
                // make all lower case:
                for(pch = szURL; *pch; pch++)
                    *pch = (char)tolower(*pch);

                // check for /servlet/ and /WEB-INF/:
                if(strstr(szURL, "/servlet/") || // request is for a servlet.
                   strstr(szURL, "/web-inf/")) // let JRun reject this.
                {
                    bRequestIsForJRun = TRUE;
                }
            }

        // Free memory allocated by GetHeader:
        free(szURL);
    }

    return bRequestIsForJRun;
}

// Called by IIS whenever a notification event 
// for which the filter has registered occurs.
DWORD WINAPI HttpFilterProc(
	PHTTP_FILTER_CONTEXT pFilterContext,  
	DWORD dwNotificationType,
	LPVOID pvNotification)
{
    if(dwNotificationType == SF_NOTIFY_PREPROC_HEADERS)
    {
        PHTTP_FILTER_PREPROC_HEADERS pHeaders = 
            static_cast<PHTTP_FILTER_PREPROC_HEADERS>(pvNotification);

        // If the request isn't for JRun...
        if(!RequestIsForJRun(pFilterContext, pHeaders))
        {
            // ... bypass JRun and do what IIS would otherwise do:
            return SF_STATUS_REQ_NEXT_NOTIFICATION;
        }
    }
    else if(dwNotificationType == SF_NOTIFY_LOG)
    {
        PHTTP_FILTER_LOG pLog =
            static_cast<PHTTP_FILTER_LOG>(pvNotification);

        // If the target of the HTTP command is not JRun's filter DLL...
        if(strcmp(pLog->pszTarget, "/scripts/jrun.dll"))
        {
            // ... bypass JRun and do what IIS would otherwise do:
            return SF_STATUS_REQ_NEXT_NOTIFICATION;
        }
    }

    // Call JRun's HttpFilterProc:
    return (HttpFilterProcProcAddress)(pFilterContext,
        dwNotificationType, pvNotification);	
}

// Called by IIS to notify our filter that 
// it is going to be removed from memory.
BOOL WINAPI TerminateFilter(DWORD dwFlags)
{
    if(hModule)
    {
        // Call JRun's TerminateFilter function if
        // JRun exports this function (which it currently doesn't).
        if(TerminateFilterProcAddress != NULL)
            (TerminateFilterProcAddress)(dwFlags);

        // Unload the JRun DLL:
        FreeLibrary(hModule);
    }

    return TRUE;
}

Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.