Home » Tutorials » Netzwerk und Internet » ISAPI

ISAPI

Grundlagen

„ISAPI-Anwendungen“ bestehen meiner Kenntnis nach immer aus DLLs. Diese DLLs müssen mindestens folgende zwei mit der STDCALL Konvention deklarierte Funktionsexporte bereitstellen:

function GetExtensionVersion(var pVer: THSE_VERSION_INFO): BOOL; stdcall;
function HttpExtensionProc(var pECB: TEXTENSION_CONTROL_BLOCK): DWORD;
  stdcall;

Die benötigten Typen sind in folgenden Dateien oder späteren Versionen dieser Dateien deklariert: ISAPI.PAS und ISAPI2.PAS. Weitere benutzte Win32-API-Funktionen sind z.B.: lstrlen(), lstrcmpi(), wvsprintf(), LoadLibrary(), FormatMessage(), CreateFile(), CreateFileMapping(), MapViewOfFile(), UnMapViewOfFIle(), CloseHandle(), WriteFile(), GetLocalTime().
Da wir eine ISAPI-Extension schreiben, brauchen wir ein paar HTTP-Grundlagen. Es gibt zwei grundlegende HTTP-Methoden, die von einer Extension bearbeitet werden können: POST und GET. GET benutzt man (der Browser ;), um ein Dokument (sei es HTML oder ZIP) per HTTP anzufordern. POST wird meist benutzt, um Daten eines Formulars an eine Web-Anwendung, wie z.B. CGI oder ISAPI zu „posten“. Wir werden uns auf Letzteres konzentrieren, wobei sich das Problem wie folgt definiert: Eine ISAPI-Extension schreiben, die in der Lage ist, Daten eines Formulars zu empfangen, abzuspeichern und eine weitere Seite anzuzeigen.

Grundgerüst

function GetExtensionVersion(var pVer: THSE_VERSION_INFO): BOOL;
  stdcall;
begin
  pVer.dwExtensionVersion:=MAKELONG(HSE_VERSION_MINOR, HSE_VERSION_MAJOR);
  pVer.lpszExtensionDesc :=description + #0;
  result := true;
end;

function HttpExtensionProc(var pECB: TEXTENSION_CONTROL_BLOCK): DWORD;
  stdcall;
begin
  SetString(queryString, PChar(pECB.lpbData), pECB.cbTotalBytes);

//Bearbeitung hier

  page := 'Content-Type: text/html' + #13#10#13#10 + page;
  dwLen := lStrLen(@page[1]);
  lstrcpy(Response, '200 OK');
  if pECB.ServerSupportFunction(pECB.ConnID,
  HSE_REQ_SEND_RESPONSE_HEADER, @Response, @dwlen, @page[1]) then
    result := HSE_STATUS_SUCCESS else result := HSE_STATUS_ERROR;
end;

Die Variablendeklarationen wurden hier explizit herausgelassen und sind zum Funktionieren sebstverständlich unabdingbar. Sie werden kurz erläutert.
Die Funktion GetExtensionVersion() gibt, wie ersichtlich, die unterstützte ISAPI-Version zurück und ebenfalls eine Kurzbeschreibung der Extension, die in der Variablen description versteckt ist. Das Ganze wird dann in die mit pVer übergebene Struktur geschrieben.
HttpExtensionProc() wiederum bearbeitet eine Anforderung. In diesem Falle wird noch nicht nach GET oder POST unterschieden. Als erstes wird die Variable querystring mit dem (geposteten) Datenanteil der Anforderung initialisiert. Danach sollte man sinnvollerweise die Parameter einzeln aus dem String auslesen (Bearbeitung 😉 und dann verarbeiten. Zum Schluss werden Daten zurückgegeben (in der Variablen page) und mit Hilfe der Callback-Funktion des Servers pECB.ServerSupportFunction() zurückgeschrieben. Das ist dann auch, was beim Clientbrowser ankommt. Es gibt dafür auch andere Möglichkeiten als diese (z.B. WriteClient()), aber hier werde ich nur diese besprechen, da es ein simples Beispiel bleiben soll.

Tipp: Die obigen Funktionen werden in C so definiert, dass Pointer auf eine Struktur übergeben werden. In OPASCAL kann man sich das Gewurschtel mit dem Pointer aber sparen, indem Parameter als procedure procname(var name:type); übergeben werden. Dies ist äquivalent zu procedure procname(name:^type); (syntaktisch nicht ganz korrekt, also Pointer auf einen Typen), aber einfacher.