mod_rewrite functionality in ISAPI


The following example provides some example code which shows how to rewrite for incoming URL requests for a home directory, into the form 'http://www.username.myisp.com/page'.

This is a more sophisticated version of the previous example, against registering to be called on hook SF_NOTIFY_PREPROC_HEADERS via GetFilterVersion(). Instead of simply rewriting the URL via SetHeader(), we issue a '302 Redirect' to the browser, which will (hopefully) stop them pestering us again on this URL in future.

Note that we call WriteClient() to send this header back to the browser, and then return SF_STATUS_REQ_FINISHED so that no further ISAPI filters (which are chained) will be called for this request, and the web server will then close the connection once the header has been written to the browser.

As noted in the comment below, this scheme works extremely well with BIND 8's support for wildcarded hostnames and Zeus's Subserver module. This means you can simply mkdir() a new directory, put some content in, and access it immediately via a custom URL of the form *.myisp.com, where * can be any directory and DNS name that is valid on the Internet.

/*!
 * Example 'mod_rewrite' functionality.
 *
 * This modules shows how to transparently map requests for
 * http://www.myisp.com/user/page to
 * http://www.user.myisp.com/page
 *
 * This is designed for ISPs wanting to migrate from legacy hosting systems
 * to Zeus's support for Subservers, allowing mass-hosting customers to have
 * their own domain.  This works extremely well with BIND 8.x's support for
 * wildcarded DNS.  You setup a single DNS record for 
 * www.*.myisp.com -> * IP address.
 */

#include <httpfilt.h>
#include <string.h>


/*!
 * ISAPI run-time callback
 */

static char* HOSTINGDOMAIN = "hosting.myisp.com";   /* new hosting domain */
static char* HOLDPAGE      = "myisp.net";       /* where to send bad urls */

DWORD WINAPI
HttpFilterProc( PHTTP_FILTER_CONTEXT pfc,
      DWORD notificationType,
      LPVOID notificationInfo )
{
   char url[1024];
   char dest[1024+128], *p;
   int i;
   PHTTP_FILTER_PREPROC_HEADERS tbl = notificationInfo;

   memcpy( dest, "Location: http://www.", 21 );
   p = dest + 21;

   /* Retrieve the url asked for */
   if( tbl->GetHeader( pfc, "url", url, &i ) == TRUE ) {
      /* calculate destination */
      char* u = url;
      while(       *u == '/' ) u++;              /* strip off leading '/' */
      if( !*u ) {
         /* no user-name!, send hold-page */
         strcpy( p, HOLDPAGE );
      } else {
         while( *u && *u != '/' ) *p++ = *u++;      /* copy over user name */
         *p++ = '.';                                /* add '.' */
         strcpy( p, HOSTINGDOMAIN );                /* add new hosting domain */
         p += strlen( HOSTINGDOMAIN );
         strcpy( p, u );                            /* add rest of URL */
      }
   } else {
      /* failure - just redirect to ISP front-page */
      strcpy( p, HOLDPAGE );
   }

   /* Redirect to dest */
   pfc->ServerSupportFunction( pfc, SF_REQ_SEND_RESPONSE_HEADER,
                  "302", (LPDWORD)dest, 0 );

   i = 0;
   pfc->WriteClient( pfc, "", &i, 0 );
   return SF_STATUS_REQ_FINISHED;
}


/*!
 * ISAPI intialisation entry point
 */

BOOL WINAPI
GetFilterVersion( HTTP_FILTER_VERSION *ver )
{
   ver->dwFilterVersion = HTTP_FILTER_REVISION;
   strncpy( ver->lpszFilterDesc, "mod_rewrite example",
         SF_MAX_FILTER_DESC_LEN );
   /* We want to hook onto the pre-processing headers stage */
   ver->dwFlags = SF_NOTIFY_PREPROC_HEADERS;

   return TRUE;
}