Visit our Sponsor   Visit our Sponsor
delphi3000.com - the free delphi knowledge platform
delphi3000.com - the free delphi knowledge platform
500 Users Online NOW
Have a look at your member-status

connecting people's knowledge


  - Recent ArticlesRSS feed for Recent Articles on delphi3000.com
  - List of All Articles
  - Top Viewed Articles
  - Articles (+Attachem.)
  - Articles Of Interest
  - Categories
  - Top Uploader
  - Search
  - Index

  - My Home
  - Submit an Article
  - My Articles
  - My Personal Data
  - My Bookmarks
  - Activities
  - Login/Logout

  - Sign Up
  - Why Sign Up
  - Newsletter

  - Press
  - Advertise

  - Contact
  - Feedback





Community
Borland
ClubeDelphi
Dr. Bob
UK-BUG
Delphi Meetings
Planeta Delphi



Loremo - the 1.5 liter car coming in 2009




Startblatt.de






Share this article with friendsShare this article with friends
Rate this articleRate this article - to keep the quality of delphi3000.com !
Comment this article or read through previous comments (4)


Writing a simple ISAPI Filter for IIS.Format this article printer-friendly!Bookmark function is only available for registered users!
How to map subdomains into specific directories?
Product:
Delphi 4.x (or higher)
Category:
Internet / Web
Skill Level:
Scoring:
Last Update:
04/25/2005
Search Keys:
delphi delphi3000 article borland vcl code-snippet ISAPI filter domain subdomain url mapping
Times Scored:
8
Visits:
13215
Uploader: Daniel Wischnewski
Company: Delphi-PRAXiS
Reference: gate(n)etwork.com
 
Question/Problem/Abstract:
This article shows you the basics of creating a simple ISAPI filter and how to use one to map sub-domains into specific folders.

http://daniel.yourdomain.com
will map the same way as
http://www.yourdomain.com/members/daniel
Answer:



Borland has gone a long way helping us to create web applications. As of today, however, there is no real support for writing ISAPI Filters.

Note: ISAPI Filters are quite different from ISAPI/NSAPI Extensions!

INTRODUCTION
============

I have had no chance, so far, to look into Delphi 6 and figure how it supports ISAPI Filters, a first look revealed no new facts, anyway. ISAPI Filters are not called by referencing them in the URI of the request like
  http://www.yourserver.com/cgi/isapi.dll?params=54,4568,54.8
rather they are installed with the IIS-Console and invoked on EVERY call made to your web site. Therefore, ISAPI Filters have to be very fast in processing requests.

THE LIBRARY BASICS
==================

Every ISAPI Dll has to export two (or three) functions. These functions are called by thi IIS to initialize the filter, to process every single request and to destroy the filter.

Attn.: These names are case-sensitive!

(1) GetFilterVersion is called once, while the filter is running. All
    preliminary work is to be done here. The filter has to return on what kind
    of events it is supposed to process data.

(2) HttpFilterProc is called for every object requested by the client,
    regardless of whether it is an image, a html file or an ASP script.

(3) TerminateFilter is called when the web server is shuting down.
    Use this function to free resources reservered, etc. This function must
    return the value 1 - as off IIS 4 (NT) and IIS 5 (W2K).

THE EVENTS PASSED TO HTTPFILTERPROC
===================================

The following basic events are defined:

(1) SF_NOTIFY_READ_RAW_DATA - The filter wants to process all incoming data
    (like form data)
(2) SF_NOTIFY_PREPROC_HEADERS - The filter wants to process all header
    information sent by the client (browser type, uri, cookies, ...)
(3) SF_NOTIFY_AUTHENTICATION - The filter is used to check the user
    authentication sent by the client
(4) SF_NOTIFY_URL_MAP - The filter is used to map incoming requests to specific
    folders and files on the hard drive
(5) SF_NOTIFY_ACCESS_DENIED - The filter wants to process responses when
    authentication has failed (for logging, ...)
(6) SF_NOTIFY_SEND_RAW_DATA - The filter wants to process all outgoing data
    (like link checker, cookie munchers, ...)
(7) SF_NOTIFY_LOG - The filter is used to change the data sent to the IIS log
    files
(8) SF_NOTIFY_END_OF_NET_SESSION - The filter has to free resources reserved
    for specific users

Note: The samples named are just a short list of possible uses for ISAPI filters.

Because a filter is invoked on every request, you have to register the filter for every event you want to handle. Events, the filter does not register for, are not sent to it, thus increasing the speed of the filter.

THE SUBDOMAIN <--> URL MAPPER
=============================

In this article I show you one simple, but useful application of such an ISAPI filter. This filter does not respect some aspects of good programming, like loading setup information, but rather has them written directly into the code - this one is left for you. I am just showing you the basics of ISAPI Filter programming.

The filter to be installed on the "Properties" dialog with your IIS-Console for the specific "Web Site."
Attn: You can install the filter on multiple "Web Sites," it is, however, loaded once only for all web sites using it. Therefore, you have to take care of this fact within your code.

Further: I have not made this sample aware of the multi-threading part an ISAPI Filter has to take care of.

WHAT DOES THIS SAMPLE DO
========================

Incoming request like
http://username.yourdomain.com/guestbook.asp
are mapped as they were entered like
http://www.yourdomain.com/members/username/guestbook.asp
"Members" can be defined by you. This filter maps the subdomain only, if the subfolder corresponding with the subdomain exists.

MORE ON ISAPI FILTERS
=====================

In a future article I will publish a complete unit with all definitions for ISAPI Filters. At present I am still working on them. You can read more on ISAPI filters on the msdn.microsoft.com home page.

Here are the ISAPI header conversions: ISAPI Filter Header (D3K)

THE SOURCE CODE FOR THE ISAPI FILTER LIBRARY
============================================

library DomainMapper;

uses
  Windows, SysUtils, Classes, FileCtrl;

{$R *.RES}

// these constants must be changed to match your environment
const
  // as found on the hard drive
  FAbsBaseFolder = 'C:\INetPub\WWWRoot\Members\';
  // as entered in the URL
  FRelBaseFolder = '/members/';

const
  SF_MAX_FILTER_DESC_LEN = (256 + 1);

  SF_NOTIFY_SECURE_PORT = $00000001;
  SF_NOTIFY_NONSECURE_PORT = $00000002;
  SF_NOTIFY_READ_RAW_DATA = $00008000;
  SF_NOTIFY_PREPROC_HEADERS = $00004000;
  SF_NOTIFY_AUTHENTICATION = $00002000;
  SF_NOTIFY_URL_MAP = $00001000;
  SF_NOTIFY_ACCESS_DENIED = $00000800;
  SF_NOTIFY_SEND_RAW_DATA = $00000400;
  SF_NOTIFY_LOG = $00000200;
  SF_NOTIFY_END_OF_NET_SESSION = $00000100;

  SF_NOTIFY_ORDER_HIGH = $00080000;
  SF_NOTIFY_ORDER_MEDIUM = $00040000;
  SF_NOTIFY_ORDER_LOW = $00020000;
  SF_NOTIFY_ORDER_DEFAULT  = SF_NOTIFY_ORDER_LOW;
  SF_NOTIFY_ORDER_MASK = SF_NOTIFY_ORDER_HIGH or SF_NOTIFY_ORDER_MEDIUM or
    SF_NOTIFY_ORDER_LOW;

  SF_STATUS_REQ_FINISHED = $8000000;
  SF_STATUS_REQ_FINISHED_KEEP_CONN = $8000001;
  SF_STATUS_REQ_NEXT_NOTIFICATION = $8000002;
  SF_STATUS_REQ_HANDLED_NOTIFICATION = $8000003;
  SF_STATUS_REQ_ERROR = $8000004;
  SF_STATUS_REQ_READ_NEXT = $8000005;

type
  PHTTP_FILTER_VERSION = ^HTTP_FILTER_VERSION;
  HTTP_FILTER_VERSION = record
    dwServerFilterVersion: DWORD;
    dwFilterVersion: DWORD;
    lpszFilterDesc: array[0..SF_MAX_FILTER_DESC_LEN - 1] of Char;
    dwFlags: DWORD;
  end;
  THTTP_FILTER_VERSION = HTTP_FILTER_VERSION;
  LPHTTP_FILTER_VERSION = PHTTP_FILTER_VERSION;

  LPVOID = POINTER;

  TFilterGetServerVariableProc = function(
    var pfc{: THTTP_FILTER_CONTEXT}; VariableName: PChar; Buffer: Pointer;
    var Size: DWORD
  ): BOOL; stdcall;

  TFilterAddResponseHeadersProc = function(
    var pfc{: THTTP_FILTER_CONTEXT}; lpszHeaders: PChar; dwReserved: DWORD
  ): BOOL; stdcall;

  TFilterWriteClientProc = function(
    var pfc{: THTTP_FILTER_CONTEXT}; Buffer: Pointer; var Bytes: DWORD;
    dwReserved: DWORD
  ): BOOL; stdcall;

  TFilterAllocMemProc = function(
    var pfc{: THTTP_FILTER_CONTEXT}; cbSize: DWORD; dwReserved: DWORD
  ): Pointer; stdcall;

  TFilterServerSupportFunctionProc = function(
    var pfc{: THTTP_FILTER_CONTEXT}; sfReq: DWORD; pData: Pointer;
    ul1, ul2: DWORD
  ): BOOL; stdcall;

  PHTTP_FILTER_CONTEXT = ^THTTP_FILTER_CONTEXT;
  THTTP_FILTER_CONTEXT = record
    cbSize: DWORD;
    Revision: DWORD;
    ServerContext: Pointer;
    ulReserved: DWORD;
    fIsSecurePort: BOOL;
    pFilterContext: Pointer;
    GetServerVariable: TFilterGetServerVariableProc;
    AddResponseHeaders: TFilterAddResponseHeadersProc;
    WriteClient: TFilterWriteClientProc;
    AllocMem: TFilterAllocMemProc;
    ServerSupportFunction: TFilterServerSupportFunctionProc;
  end;
  HTTP_FILTER_CONTEXT = THTTP_FILTER_CONTEXT;

  PCardinal = ^Cardinal;
  TGetServerVariable = function(
    var pfc:      THTTP_FILTER_CONTEXT;
    VariableName: PChar;
    Buffer:       LPVOID;
    BuffSize:     PCardinal
  ): BOOL; StdCall;

  TGetHeaderProc = function (var pfc: THTTP_FILTER_CONTEXT; lpszName: PChar;
    var lpvBuffer; var lpdwSize: DWORD): BOOL stdcall;
  TSetHeaderProc = function (var pfc: THTTP_FILTER_CONTEXT; lpszName,
    lpszValue: PChar): BOOL stdcall;
  TAddHeaderProc = function (var pfc: THTTP_FILTER_CONTEXT; lpszName,
    lpszValue: PChar): BOOL stdcall;

  PHTTP_FILTER_PREPROC_HEADERS = ^THTTP_FILTER_PREPROC_HEADERS;
  THTTP_FILTER_PREPROC_HEADERS = record
    GetHeader: TGetHeaderProc;
    SetHeader: TSetHeaderProc;
    AddHeader: TAddHeaderProc;
    dwReserved: DWORD;
  end;

{ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  Exported Functions
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * }

function GetFilterVersion(var pVer: HTTP_FILTER_VERSION): BOOL; stdcall; export;
begin
  with pVer do
  begin
    // version
    dwFilterVersion :=
      MakeLong(0 {minor}, 1 {major});
    // description
    StrPCopy(lpszFilterDesc, 'A Simple Domain Mapper');
    // notification flags
    dwFlags :=
      SF_NOTIFY_ORDER_DEFAULT or
      SF_NOTIFY_PREPROC_HEADERS;
  end;
  Result := True;
end;

function HttpFilterProc(var FilterContext: HTTP_FILTER_CONTEXT;
  NotificationType: DWORD; pvNotification: LPVOID): DWORD; stdcall; export;
var
  Buffer: array[0..4096] of Char;
  Size: Cardinal;
  P: Integer;
  DestFolder, Domain, SubDomain, URL: String;
  Data: THTTP_FILTER_PREPROC_HEADERS;
begin
  try
    Result := SF_STATUS_REQ_NEXT_NOTIFICATION;
    if NotificationType = SF_NOTIFY_PREPROC_HEADERS then
    begin
      // we can check whether to map the current sub-domain into a directory
      Data := THTTP_FILTER_PREPROC_HEADERS(pvNotification^);
      // get the domain requested by the user
      Size := SizeOf(Buffer);
      FillChar(Buffer, Size, 0);
      TGetServerVariable(FilterContext.GetServerVariable)
        (FilterContext, 'SERVER_NAME', @Buffer[0], @Size);
      Domain := StrPas(@Buffer[0]);
      // get the sub-domain requested
      P := Pos('.', Domain);
      if P = 0 then
        Exit;
      SubDomain := Copy(Domain, 1, P - 1);
      // create the destination folder
      DestFolder := FAbsBaseFolder + SubDomain;
      if DirectoryExists(ExtractFilePath(DestFolder)) then
      begin
        // the sub-domain my be routed - a corresponding folder does exist
        // get the uri of the document requested
        Size := SizeOf(Buffer);
        FillChar(Buffer, Size, 0);
        TGetHeaderProc(Data.GetHeader)(FilterContext, 'url', Buffer[0], Size);
        URL := StrPas(Buffer);
        // add the virtual base folder to the uri
        if URL = '' then
          URL := FRelBaseFolder + SubDomain
        else
          URL := FRelBaseFolder + SubDomain + URL;
        // send new uri to IIS
        StrPCopy(@Buffer[0], URL);
        TSetHeaderProc(Data.SetHeader)(FilterContext, 'url', @Buffer[0]);
      end;
    end;
  except
    // on error return request to process next ISAPI message
    Result := SF_STATUS_REQ_NEXT_NOTIFICATION;
  end;
end;

function TerminateFilter(Flags: DWORD): DWORD; stdcall; export;
begin
  // must return 1 (as of IIS 4 and IIS 5)
  Result := 1;
end;

exports
  GetFilterVersion,
  HttpFilterProc,
  TerminateFilter;

begin
end.





Please rate this article!
Skill level:
BeginnerExpert

Useful:
No!Very!

Overall rating:
PoorExcellent



Comments to this article
Write a new comment
ISAPI Filter Delphi Component
    Suavi Demir (Dec 30 2001 4:43PM)

There is a Delphi Component that makes it easy to write ISAPI Filters with Delphi. It is distributed as source code. It is an excellent starting point for beginners as well as a time saving tool for advanced users.

TbcISAPIFilter component is available at: http://www.bestcode.com/html/isapi_filter.html

Regards,
S. Demir
Respond

RE: ISAPI Filter Delphi Component
support (Aug 12 2005 2:41AM)

for easy click, the component url is
http://www.bestcode.com/html/isapi_filter.html


Respond

RE: RE: ISAPI Filter Delphi Component
support (Aug 12 2005 2:44AM)

In case this what you need, there is also an ISAPI Authentication Filter at:
http://www.bestcode.com/html/bcauthenticate.html

It authenticates web site visitors based on an ODBC database of choice.
Respond

RE: ISAPI Filter Delphi Component
Steven (Sep 8 2005 5:40PM)

I recently released mod_rewrite for IIS free and as open source and I'm searching for people that can help me make the filter known. The source code is in Delphi 7.

Check it out at http://www.iismods.com and let other people know about it
Respond














 
Sign up to consume product discounts for Bronze memberships !

read more


  Visit our Sponsor

 

  Community Ad of
S. Carter
 
   














 







     
  Copyright © 2000 - 2007 delphi3000.com - All rights reserved. Terms of use. || Privacy
delphi3000.com is a service by bluestep.com IT-Services GmbH (Vienna)