Link to home
Start Free TrialLog in
Avatar of Smilly
Smilly

asked on

Indy HTTPServer and isapi?

Hi there

I've made a HTTPServer with indy. Is there a way to run external isapi module, from this server?

If so, HOW?

Smilly
Avatar of AvonWyss
AvonWyss
Flag of Switzerland image

ISPI extensions are nothing but DLL's with a couple of entry functions. So what you have to do is to load the DLL's (using LoadLibrary()), to retrieve its entry points (GetProcAddress()), call them as needed, and finally (when you shutdown the application) unload the library.

In the file ISAPI.PAS (which ships with Delphi) you'll find all the needed ISAPI definitions. I have prepared a base class which will do the basic stuff for you, you only need to fill in the things specific to your self-made web server:

// uses Windows,ISAPI;

type
      TYourWebRequest=class
            Method,                // GET, HEAD, POST, ...
            QueryString,           // the string behind the ? of the URI
            PathInfo,              // the string before the ? in the URI (without host name)
            PathTranslated,        // the physical path on the web server of that request
            ContentType: string;   // the content-type (from the Content-Type header)
            ContentSize,           // number of bytes indicated by client (in the Content-Length header)
            AvailableSize: Integer;// number of bytes currently waiting to be read
            AvailableData: Pointer;// pointer to the data (ReadAvailable bytes)
      end;

      TISAPIExtension=class;
      TGetExtensionVersion=function(var Ver: THSE_VERSION_INFO): BOOL; stdcall;
      THttpExtensionProc=function(var ECB: TEXTENSION_CONTROL_BLOCK): DWORD; stdcall;
      PCONN=^TCONN;
      TCONN=record
            Request: TYourWebRequest;
            Extension: TISAPIExtension;
            ECB: TEXTENSION_CONTROL_BLOCK;
      end;
      TISAPIExtension=class
      private
            FISAPIDLL: string;
            FDLLHandle: THandle;
            FExtensionVersion: THSE_VERSION_INFO;
            FHttpExtensionProc: THttpExtensionProc;
      protected
            function GetServerVariable(Request: TYourWebRequest; VariableName: string; Buffer: Pointer; var Size: Integer): Boolean;
            function WriteClient(Request: TYourWebRequest;      Buffer: Pointer; var Bytes: Integer; dwReserved: Integer): Boolean;
            function ReadClient(Request: TYourWebRequest; Buffer: Pointer;      var Size: Integer): Boolean;
            function ServerSupportFunction(Request: TYourWebRequest; HSERRequest: Integer; Buffer: Pointer; var Size: Integer; var DataType: Integer): Boolean;
      public
            constructor Create(const ISAPIDLL: string);
            procedure Invoke(Request: TYourWebRequest);
            destructor Destroy; override;
      end;

implementation

function GetServerVariableProc(ConnID: HCONN; VariableName: PChar; Buffer: Pointer; var Size: DWORD): BOOL; stdcall;
var
      Conn: PCONN absolute ConnID;
begin
      Result:=Conn.Extension.GetServerVariable(Conn.Request,VariableName,Buffer,Integer(Size));
end;

function WriteClientProc(ConnID: HCONN; Buffer: Pointer; var Bytes: DWORD; dwReserved: DWORD): BOOL; stdcall;
var
      Conn: PCONN absolute ConnID;
begin
      Result:=Conn.Extension.WriteClient(Conn.Request,Buffer,Integer(Bytes),dwReserved);
end;

function ReadClientProc(ConnID: HCONN; Buffer: Pointer;      var Size: DWORD): BOOL; stdcall;
var
      Conn: PCONN absolute ConnID;
begin
      Result:=Conn.Extension.ReadClient(Conn.Request,Buffer,Integer(Size))
end;

function ServerSupportFunctionProc(ConnID: HCONN; HSERRequest: DWORD; Buffer: Pointer; var Size: DWORD; var DataType: DWORD): BOOL; stdcall;
var
      Conn: PCONN absolute ConnID;
begin
      Result:=Conn.Extension.ServerSupportFunction(Conn.Request,HSERRequest,Buffer,Integer(Size),Integer(DataType));
end;

{ TISAPIExtension }

constructor TISAPIExtension.Create(const ISAPIDLL: string);
var
      GetVersion: TGetExtensionVersion;
begin
      FDLLHandle:=LoadLibrary(PChar(ISAPIDLL));
      if FDLLHandle=null then
            raise Exception.Create('Cannot load ISAPI DLL '+ISAPIDLL);
      FISAPIDLL:=ISAPIDLL;
      GetVersion:=TGetExtensionVersion(GetProcAddress(FDLLHandle,'GetExtensionVersion'));
      FHttpExtensionProc:=THttpExtensionProc(GetProcAddress(FDLLHandle,'FHttpExtensionProc'));
      GetVersion(FExtensionVersion);
end;

destructor TISAPIExtension.Destroy;
begin
      FreeLibrary(FDLLHandle);
      inherited;
end;

function TISAPIExtension.GetServerVariable(Request: TYourWebRequest; VariableName: string; Buffer: Pointer; var Size: Integer): Boolean;
begin
      // read a server variable in this requests context here
end;

procedure TISAPIExtension.Invoke(Request: TYourWebRequest);
var
      Connection: TCONN;
begin
      Connection.Request:=Request;
      Connection.Extension:=self;
      with Connection,ECB do begin
            FillChar(ECB,SizeOf(ECB),0);
            cbSize:=SizeOf(ECB);
            dwVersion:=HSE_VERSION_MAJOR shl 16+HSE_VERSION_MINOR;
            ConnID:=Cardinal(@Connection);
            lpszMethod:=PChar(Request.Method);
            lpszQueryString:=PChar(Request.QueryString);
            lpszPathInfo:=PChar(Request.PathInfo);
            lpszPathTranslated:=PChar(Request.PathTranslated);
            cbTotalBytes:=Integer(Request.ContentSize);
            cbAvailable:=Integer(Request.AvailableSize);
            lpbData:=Request.AvailableData;
            lpszContentType:=PChar(Request.ContentType);
            GetServerVariable:=GetServerVariableProc;
            WriteClient:=WriteClientProc;
            ReadClient:=ReadClientProc;
            ServerSupportFunction:=ServerSupportFunctionProc;
      end;
      FHttpExtensionProc(Connection.ECB);
end;

function TISAPIExtension.ReadClient(Request: TYourWebRequest; Buffer: Pointer; var Size: Integer): Boolean;
begin
      // copy data from the request in buffer to the ISAPI DLL
end;

function TISAPIExtension.ServerSupportFunction(Request: TYourWebRequest; HSERRequest: Integer; Buffer: Pointer; var Size, DataType: Integer): Boolean;
begin
      // execute the wanted support function
end;

function TISAPIExtension.WriteClient(Request: TYourWebRequest; Buffer: Pointer; var Bytes: Integer; dwReserved: Integer): Boolean;
begin
      // copy data from the ISAPI DLL to the request out buffer
end;

For further reading on the callback functions and server variables, please read here:
http://msdn.microsoft.com/library/en-us/iisref/html/psdk/asp/isre0wit.asp
Avatar of Smilly
Smilly

ASKER

Hi AvonWyss

Thanks for a greate response to my question.
How do I use it? I tried this :

*****************************************
procedure TForm1.IdHTTPServer1CommandGet(AThread: TIdPeerThread;
  RequestInfo: TIdHTTPRequestInfo; ResponseInfo: TIdHTTPResponseInfo);
var
     req : TYourWebRequest;
     MyIsapi: TISAPIExtension;
begin

      MyIsapi := TISAPIExtension.Create('C:\Inetpub\Scripts\sayhello.dll');

      req := TYourWebRequest.Create;

      req.Method := RequestInfo.Command;
      req.QueryString := RequestInfo.Params.Text;
      req.PathInfo := RequestInfo.Host;
      req.PathTranslated := 'D:\delphi\webserver\root';
      req.ContentType := ResponseInfo.ContentType;
      req.ContentSize := ResponseInfo.ContentLength;
      req.AvailableSize := 0;
      req.AvailableData := nil;

      MyIsapi.Invoke(req);

      req.Free;
      MyIsapi.Free;
end;
*****************************************************

But it didn't work.

You wrote :
  -->read
// copy data from the request in buffer to the ISAPI DLL

  -->support
// execute the wanted support function  

  -->write
// copy data from the ISAPI DLL to the request out buffer

But how?

The only thing I want is to run a simple Isapi extension from within my server. The helloworld.dll writes "hello world" in the response context, nothing else.

Please help me a little more, and I increase the point.
Hi, Smilly.

Perhaps you've overlooked these open questions, one quite old, the other without comments for which you may wish a refund.

For special handling needs, please post a zero point question in the link below and include the question QID/link(s) that it regards.
https://www.experts-exchange.com/jsp/qList.jsp?ta=commspt
 
To view your open questions, please click the following link(s) and keep them all current with updates.
https://www.experts-exchange.com/questions/Q.20044308.html
https://www.experts-exchange.com/questions/Q.20144496.html
 
Thank you everyone.
 
Moondancer
Moderator @ Experts Exchange
ASKER CERTIFIED SOLUTION
Avatar of AvonWyss
AvonWyss
Flag of Switzerland image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
And one more thing: Don't load and unload the DLL for each request! Load it (e.g. create the object) when starting your server application, use it and free it only when stopping the server. This will greaty enhance the response time of the server because the DLL does not need to be loaded and unloaded all the time!