auf ein Listing von freak gestoßen. Da ich das für eine echte Perle halte und dort keine Resonanz war,
will ich das Thema hier noch einmal aufgreifen.
Zunächst einmal 10.000 Dank an freak !
ISAP ist etwas vereinfacht gesagt wie FastCGI eine Möglichkeit auf dem
Webserver sprachenunabhängig compilierte "Skripte" die permanent
im Speicher bleiben laufen zu lassen.
ISAP kann aber auch als Filter arbeiten und dadurch etwas mehr.
Mit FastCGI in PureBasic beschäftige ich mich auch gerade aber da bin ich noch nicht so weit.
Da es bei mir mit der Methode POST zu Serverabstürzen kam habe ich mich mal etwas im Internet umgesehen.
Unter http://people.freenet.de/j-hummel/progr ... /index.htm habe ich einiges gefunden.
Ich habe zwar noch nie etwas mit Pascal gemacht, aber die Erklärungen dort sind auch so verständlich.
Ich denke die Abstürze kamen durch
Code: Alles auswählen
PeekS(*ECB\cbTotalBytes)
Code: Alles auswählen
PeekS(*ECB\cbAvailable)
Auch an ihn : Vielen Dank !
>>> Über Feedback ob das sonst noch jemanden interessiert bzw
>>> ob vielleicht jemand etwas zum Thema ISAPI-Filter
>>> oder FastCGI beitragen kann würde ich mich sehr freuen.
Code: Alles auswählen
;- ISAPI Constants
#HSE_VERSION_MAJOR = 4 ;/* major version of this spec */
#HSE_VERSION_MINOR = 0 ;/* minor version of this spec */
#HSE_LOG_BUFFER_LEN = 80
#HSE_MAX_EXT_DLL_NAME_LEN = 256
#HSE_VERSION = #HSE_VERSION_MINOR + #HSE_VERSION_MAJOR << 16
#HSE_STATUS_SUCCESS = 1
#HSE_STATUS_SUCCESS_AND_KEEP_CONN = 2
#HSE_STATUS_PENDING = 3
#HSE_STATUS_ERROR = 4
#HSE_REQ_BASE = 0
#HSE_REQ_SEND_URL_REDIRECT_RESP = #HSE_REQ_BASE + 1
#HSE_REQ_SEND_URL = #HSE_REQ_BASE + 2
#HSE_REQ_SEND_RESPONSE_HEADER = #HSE_REQ_BASE + 3
#HSE_REQ_DONE_WITH_SESSION = #HSE_REQ_BASE + 4
#HSE_REQ_END_RESERVED = 1000
#HSE_REQ_MAP_URL_TO_PATH = #HSE_REQ_END_RESERVED + 1
#HSE_REQ_GET_SSPI_INFO = #HSE_REQ_END_RESERVED + 2
#HSE_APPEND_LOG_PARAMETER = #HSE_REQ_END_RESERVED + 3
#HSE_REQ_SEND_URL_EX = #HSE_REQ_END_RESERVED + 4
#HSE_REQ_IO_COMPLETION = #HSE_REQ_END_RESERVED + 5
#HSE_REQ_TRANSMIT_FILE = #HSE_REQ_END_RESERVED + 6
#HSE_REQ_REFRESH_ISAPI_ACL = #HSE_REQ_END_RESERVED + 7
#HSE_REQ_IS_KEEP_CONN = #HSE_REQ_END_RESERVED + 8
#HSE_REQ_ASYNC_READ_CLIENT = #HSE_REQ_END_RESERVED + 10
#HSE_REQ_GET_IMPERSONATION_TOKEN = #HSE_REQ_END_RESERVED + 11
#HSE_REQ_MAP_URL_TO_PATH_EX = #HSE_REQ_END_RESERVED + 12
#HSE_REQ_ABORTIVE_CLOSE = #HSE_REQ_END_RESERVED + 14
#HSE_REQ_GET_CERT_INFO_EX = #HSE_REQ_END_RESERVED + 15
#HSE_REQ_SEND_RESPONSE_HEADER_EX = #HSE_REQ_END_RESERVED + 16
#HSE_TERM_ADVISORY_UNLOAD = $00000001
#HSE_TERM_MUST_UNLOAD = $00000002
#HSE_IO_SYNC = $00000001 ;/* For WriteClient */
#HSE_IO_ASYNC = $00000002 ;/* For WriteClient/TF*/
#HSE_IO_DISCONNECT_AFTER_SEND = $00000004 ;/* For TF */
#HSE_IO_SEND_HEADERS = $00000008 ;/* For TF
;- ISAPI Structures
Structure HSE_VERSION_INFO
dwExtensionVersion.l ; store #HSE_VERSION here
lpszExtensionDesc.b[#HSE_MAX_EXT_DLL_NAME_LEN] ; store a description string of your dll here
EndStructure
Structure EXTENSION_CONTROL_BLOCK
cbSize.l ; Size of this structure.
dwVersion.l ; Version info of this specification.
ConnID.l ; Context number not to be modified!
dwHttpStatusCode.l ; HTTP Status code.
lpszLogData.b[#HSE_LOG_BUFFER_LEN]; Null-terminated log info.
lpszMethod.l ; REQUEST_METHOD
lpszQueryString.l ; QUERY_STRING
lpszPathInfo.l ; PATH_INFO
lpszPathTranslated.l ; PATH_TRANSLATED
cbTotalBytes.l ; Total bytes indicated from client.
cbAvailable.l ; Available number of bytes.
lpbData.l ; Pointer to cbAvailable bytes.
lpszContentType.l ; Content type of client data.
GetServerVariable.l ; Pointers to the Server callback functions
WriteClient.l
ReadClient.l
ServerSupportFunction.l
EndStructure
; The *ECB pointer is passed by the Server to the main dll function. We make it
; global for the callback wrappers to access.
;
Global *ECB.EXTENSION_CONTROL_BLOCK
; A mutex needed to synchronize any threaded acces
;
Global AccessMutex
;
; Wrappers to the Server callbacks for easier access
;
Procedure.s GetServerVariable(Name$)
; BOOL WINAPI GetServerVariable(HCONN hConn, LPSTR lpszVariableName,LPVOID lpvBuffer,LPDWORD lpdwSizeofBuffer);
ResultBuffer$ = Space(1000)
BufferLength = 1000
CallFunctionFast(*ECB\GetServerVariable, *ECB\ConnID, @Name$, @ResultBuffer$, @BufferLength)
ProcedureReturn ResultBuffer$
EndProcedure
Procedure ReadClient(*Buffer, *BufferSize)
; BOOL ReadClient(HCONN hConn, LPVOID lpvBuffer, LPDWORD lpdwSize);
ProcedureReturn CallFunctionFast(*ECB\ReadClient, *ECB\ConnID, *Buffer, *BufferSize)
EndProcedure
Procedure WriteClient(*Buffer, *BufferSize)
; BOOL WriteClient(HCONN ConnID, LPVOID Buffer, LPDWORD lpdwBytes, DWORD dwSync);
ProcedureReturn CallFunctionFast(*ECB\WriteClient, *ECB\ConnID, *Buffer, *BufferSize, #HSE_IO_SYNC)
EndProcedure
Procedure ServerSupportFunction(RequestID, *Buffer, *BufferSize, *DataType)
; BOOL ServerSupportFunction(HCONN ConnID, DWORD dwHSERRequest, LPVOID lpvBuffer, LPDWORD lpdwSize, LPDWORD lpdwDataType);
ProcedureReturn CallFunctionFast(*ECB\ServerSupportFunction, *ECB\ConnID, RequestID, *Buffer, *BufferSize, *DataType)
EndProcedure
;
;- Some helper functions to make live even easier. they are just the same callback functions
; called with strings as parameter
;
Procedure.s ReceiveString(MaxLength)
ResultBuffer$ = Space(MaxLength)
CallFunctionFast(*ECB\ReadClient, *ECB\ConnID, @ResultBuffer$, @MaxLength)
ProcedureReturn PeekS(@ResultBuffer$, MaxLength) ; cut the string shorter if MaxLength was changed
EndProcedure
Procedure SendString(String$)
Length = Len(String$)
ProcedureReturn CallFunctionFast(*ECB\WriteClient, *ECB\ConnID, @String$, @Length, #HSE_IO_SYNC)
EndProcedure
Procedure SendHeader(Header$)
Length = Len(Header$)
ProcedureReturn CallFunctionFast(*ECB\ServerSupportFunction, *ECB\ConnID, #HSE_REQ_SEND_RESPONSE_HEADER, "200 OK", @Length, @Header$)
EndProcedure
;
;- Required DLL Functions
;
; This function is called once the dll is loaded
; you must return #TRUE to tell that the dll can be used
; you must also fill in the HSE_VERSION_INFO structure
ProcedureDLL GetExtensionVersion(*pVer.HSE_VERSION_INFO)
PokeS(@*pVer\lpszExtensionDesc[0], "pure-isapi-001.dll")
*pVer\dwExtensionVersion = #HSE_VERSION
; also initialize the mutex to syncronize the threads
;
AccessMutex = CreateMutex_(0, 0, 0)
ProcedureReturn #True
EndProcedure
; this is the main function called for each request
; the EXTENSION_CONTROL_BLOCK provides the needed info
ProcedureDLL HttpExtensionProc(*lpECB.EXTENSION_CONTROL_BLOCK)
If WaitForSingleObject_(AccessMutex, 5000) = 0
; wait succeeded, so anything can be done here now without worrying
; about threads
; make the control structure pointer global for better access
*ECB = *lpECB
PokeS(@*ECB\lpszLogData[0],"PureBasic-DLL")
PokeW(@*ECB\dwHttpStatusCode,200)
; ok, we can now process the request...
; lets simply output the input stuff + some more information
;
; send the header first
;
Output$ + "<html><body><br><h1><u>PureBasic ISAPI extension example</u></h1><br><br>"
;********
Output$ + "ReceiveString:<br>" + ReceiveString(4096) + "<br><br>"
;********
Output$ + "<b>Information in the extension control block structure:</b><table><br><br>"
Output$ + "<tr><td><i>LogData:</i></td><td>" + PeekS(@*ECB\lpszLogData[0]) + "</td></tr>"
Output$ + "<tr><td><i>REQUEST_METHOD</i></td><td>" + PeekS(*ECB\lpszMethod) + "</td></tr>"
Output$ + "<tr><td><i>QUERY_STRING</i></td><td>" + PeekS(*ECB\lpszQueryString) + "</td></tr>"
Output$ + "<tr><td><i>PATH_INFO</i></td><td>" + PeekS(*ECB\lpszPathInfo) + "</td></tr>"
Output$ + "<tr><td><i>PATH_TRANSLATED</i></td><td>" + PeekS(*ECB\lpszPathTranslated) + "</td></tr>"
If PeekS(*ECB\lpszMethod) = "GET" Or PeekS(*ECB\lpszMethod) = "Get" Or PeekS(*ECB\lpszMethod) = "get"
Output$ + "<tr><td><i>Total bytes by client</i></td><td>" + PeekS(*ECB\cbTotalBytes) + "</td></tr>"
Output$ + "<tr><td><i>available bytes</td></i><td>" + PeekS(*ECB\cbAvailable) + "</td></tr>"
; sind bei GET leer :
Output$ + "<tr><td><i>Contenttype of data</i></td><td>" + PeekS(*ECB\lpszContentType) + "</td></tr>"
Output$ + "<tr><td><i>lpbData</i></td><td>" + PeekS(*ECB\lpbData) + "</td></tr>"
Else
; vermutlich 4 Byte aber ohne Vorzeichen - max 4 GB -> warten auf PB Version 4.x
; Output$ + "<tr><td><i>Total bytes by client</i></td><td>" + PeekS(*ECB\cbTotalBytes) + "</td></tr>"
; Output$ + "<tr><td><i>available bytes</td></i><td>" + PeekS(*ECB\cbAvailable) + "</td></tr>"
Output$ + "<tr><td><i>Contenttype of data</i></td><td>" + PeekS(*ECB\lpszContentType) + "</td></tr>"
Output$ + "<tr><td><i>lpbData</i></td><td>" + PeekS(*ECB\lpbData) + "</td></tr>"
EndIf
Output$ + "</table><br><br>"
Output$ + "<b>Output of the available data</b><table><br><br>"
Output$ + "<tr><td><i>AUTH_TYPE:</i></td><td>" + GetServerVariable("AUTH_TYPE") + "</td></tr>"
Output$ + "<tr><td><i>CONTENT_LENGTH:</i></td><td>" + GetServerVariable("CONTENT_LENGTH") + "</td></tr>"
Output$ + "<tr><td><i>CONTENT_TYPE:</i></td><td>" + GetServerVariable("CONTENT_TYPE") + "</td></tr>"
Output$ + "<tr><td><i>PATH_INFO:</i></td><td>" + GetServerVariable("PATH_INFO") + "</td></tr>"
Output$ + "<tr><td><i>PATH_TRANSLATED:</i></td><td>" + GetServerVariable("PATH_TRANSLATED") + "</td></tr>"
Output$ + "<tr><td><i>QUERY_STRING:</i></td><td>" + GetServerVariable("QUERY_STRING") + "</td></tr>"
Output$ + "<tr><td><i>REMOTE_ADDR:</i></td><td>" + GetServerVariable("REMOTE_ADDR") + "</td></tr>"
Output$ + "<tr><td><i>REMOTE_HOST:</i></td><td>" + GetServerVariable("REMOTE_HOST") + "</td></tr>"
Output$ + "<tr><td><i>REMOTE_USER:</i></td><td>" + GetServerVariable("REMOTE_USER") + "</td></tr>"
Output$ + "<tr><td><i>UNMAPPED_REMOTE_USER:</i></td><td>" + GetServerVariable("UNMAPPED_REMOTE_USER") + "</td></tr>"
Output$ + "<tr><td><i>REQUEST_METHOD:</i></td><td>" + GetServerVariable("REQUEST_METHOD") + "</td></tr>"
Output$ + "<tr><td><i>SCRIPT_NAME:</i></td><td>" + GetServerVariable("SCRIPT_NAME") + "</td></tr>"
Output$ + "<tr><td><i>SERVER_NAME:</i></td><td>" + GetServerVariable("SERVER_NAME") + "</td></tr>"
Output$ + "<tr><td><i>SERVER_PORT:</i></td><td>" + GetServerVariable("SERVER_PORT") + "</td></tr>"
Output$ + "<tr><td><i>SERVER_PORT_SECURE:</i></td><td>" + GetServerVariable("SERVER_PORT_SECURE") + "</td></tr>"
Output$ + "<tr><td><i>SERVER_PROTOCOL:</i></td><td>" + GetServerVariable("SERVER_PROTOCOL") + "</td></tr>"
Output$ + "<tr><td><i>SERVER_SOFTWARE:</i></td><td>" + GetServerVariable("SERVER_SOFTWARE") + "</td></tr>"
Output$ + "<tr><td><i>ALL_HTTP:</i></td><td>" + GetServerVariable("ALL_HTTP") + "</td></tr>"
Output$ + "<tr><td><i>HTTP_ACCEPT:</i></td><td>" + GetServerVariable("HTTP_ACCEPT") + "</td></tr>"
Output$ + "<tr><td><i>URL:</i></td><td>" + GetServerVariable("URL") + "</td></tr>"
Output$ + "</table><br><br>"
Output$ + "</body></html>"
SendHeader("Content-Type: text/html"+Chr(13)+Chr(10)+"Content-Length: "+Str(Len(Output$))+Chr(13)+Chr(10)+Chr(13)+Chr(10))
SendString(Output$)
; make sure the mutex gets released
ReleaseMutex_(AccessMutex)
ProcedureReturn #HSE_STATUS_SUCCESS
Else
; wait somehow failed..
ProcedureReturn #HSE_STATUS_ERROR
EndIf
EndProcedure
; this function will be called just before unloading the dll, so lets free
; the mutex again.
ProcedureDLL TerminateExtension(dwFlags)
CloseHandle_(AccessMutex)
EndProcedure
; Ausschnitte von http://people.freenet.de/j-hummel/programmierung/isapi/index.htm :
; ***********************
;Strukturelement Beschreibung
;
;cbSize(IN) Die Größe der Record-Struktur ECB.
;
;dwVersion(IN) Die Versionsnummer dieser Struktur: Versionsinformation des
; ISAPI-Standards, auf die der entsprechende ECB aufbaut;
; das HIWORD repräsentiert die major Versionsnummer,
; das LOWORD die minor Versionsnummer, die unterstützt wird.
;
;ConnID(IN) Eine eindeutige Identifikations-Nummer für die aktuelle Anforderung,
; die vom HTTP Server zugewiesen wird. Sie darf nicht verändert werden.
;
;dwHttpStatusCode(OUT) Der Status der aktuellen Transaktion, wenn die Anforderung fertig ist.
;
;lpszLogData(OUT) Puffer der Größe HSE_LOG_BUFFER_LEN (derzeit 80 Zeichen).
; Er wird mit einem null-terminierten Log-Informations-String der aktuellen
; Transaktion gefüllt. Diese Log-Information wird im HTTP-Server-Log
; eingetragen. Das ist ein gemeinsames Log-File, das HTTP-Server und
; ISAPI-Anwendungen zu administrativen Zwecken dient.
;
;lpszMethod(IN) Die Methode, mit der die Anforderung getätigt wurde.
;
;lpszQueryString(IN) Ein null-terminierter String, der die Abfrage-Information des Klient enthält.
;
;lpszPathInfo(IN) Ein null-terminierter String, der zusätzliche Pfadinformationen enthält,
; die vom Klient gekommen sind.
;
;lpszPathTranslated(IN) Ein null-terminierter String, der den übersetzten Pfad enthält.
;
;cbTotalBytes(IN) Die Anzahl der Bytes, die vom Klient gesendet wurden. Einen Sonderfall
; stellt der Wert 0xffffffff dar: Es liegen dann mehr als 4 GigaByte Daten vor.
; In diesem Fall ist die Funktion ReadClient so oft aufzurufen, bis keine
; Daten mehr anstehen.
;
;cbAvailable(IN) Die Anzahl der verfügbaren Bytes, die sich im Puffer befinden;
; Auf diesen Puffer zeigt der Zeiger lpbData. Ist der Wert von cbTotalbytes
; gleich dem Wert cbAvailable, dann zeigt der Zeiger lpbData auf einen Puffer,
; der die gesamten gesendeten Daten enthält. Ansonsten enthält cbTotalbytes die
; Anzahl der gesendeten Bytes. Die ISAPI-Anwendung benötigt die
; Callback-Funktion ReadClient, um den Rest der Daten zu lesen
; (beginnend bei einem Offset von cbAvailable).
;
;lpbData(IN) Zeiger auf den Puffer der Größe cbAvailable, welcher die gesendeten Daten
; des Klient enthält. Es werden maximal die ersten 48 KBytes geliefert.
;
;pszContenttype(IN) Ein null-terminierter String, der den Content-Typ der Daten enthält,
; die der Klient gesendet hat.
; ***********************
;Servervariable Beschreibung
;
;AUTH_TYPE Beinhaltet den zur Beglaubigung verwendeten Typ.
; Bei elementarer Beglaubigung wird der Wert "basic" sein.
; Für NT-Anforderungen kann das "NTLM" sein.
; Bei leerem Rückgabewert wird keine Beglaubigung verwendet.
;
;CONTENT_LENGTH Anzahl der Bytes, die das Programm als Eingabedaten vom Klient erhalten hat.
:
;CONTENT_TYPE Der Content-Typ der Informationen, die aus einem Formular
; bei Verwendung der Methode "POST" empfangen wurden.
;
;PATH_INFO Zusätzliche Pfad-Informationen, die der Klient übermittelt.
; Sie besteht aus einen Zusatzteil der URL nach dem DLL-Namen
; bis zum QueryString, sofern ein solcher existiert.
;
;PATH_TRANSLATED Eine Pfadangabe zum virtuellen Scriptverzeichnis,
; jedoch als real übersetztes Verzeichnis auf dem Server-Computer.
;
;QUERY_STRING Die Information, die dem "?" in der URL beim Aufruf des Programmes folgt.
;
;REMOTE_ADDR Die IP-Adresse des Klient. Falls der Klient hinter einer Firewall oder
; über einen Agenten arbeitet beinhaltet REMOTE_ADDR nur deren Adressen oder
; ist leer.
;
;REMOTE_HOST Der Hostname des Klient oder dessen Agenten, von dem die Anfrage eintrifft.
;
;REMOTE_USER Beinhaltet den Nutzernamen, wie er vom Klient eingespeist wird.
; Allerdings nur bei Beglaubigung durch den Server.
; Anderenfalls zählt der Nutzer als anonym und es ist ein leerer String.
;
;UNMAPPED_REMOTE_USER Benutzername, bevor etwa vorhandene ISAPI-Filter den Nutzer kartiert haben.
;
;REQUEST_METHOD Die HTTP-Anforderungs-Methode.
;
;SCRIPT_NAME Der Name des Programmes, das gerade ausgeführt wird.
;
;SERVER_NAME Der Hostname des Servers oder notfalls dessen IP-Adresse.
;
;SERVER_PORT Der TCP/IP-Port, über den die Anfrage eingetroffen ist.
;
;SERVER_PORT_SECURE Ein String mit dem Wert 0 oder 1.
; Wenn die Anfrage über einen geschützten Port eintrifft, dann 1.
; Anderenfalls 0.
;
;SERVER_PROTOCOL Der Standard und die Version des Abruf-Protokolls der Anfrage.
; Üblicherweise ist das HTTP/1.0.
;
;SERVER_SOFTWARE Name und Version des Webservers,
; auf dem die ISAPI-DLL als Servererweiterung läuft.
;
;ALL_HTTP Alle HTTP-Angaben, die bisher noch nicht in einer der vorherigen Variablen
; übergeben wurden. Alle diese Angaben haben die Form HTTP_<FeldName>.
; Es ist ein null-terminierter String.
; Die Einzelteile sind durch Zeilenvorschübe voneinander getrennt.
;
;HTTP_ACCEPT Spezieller HTTP-Kopf mit Werten der vom Klient akzeptierten Datentypen.
; Die einzelnen Angaben sind durch Komma getrennt.
;
;URL (ab V.2.0) Liefert den Basis-Teil der URL.
;**********************************************************************************************
; ReadClient
; Mit ServerSupportFunction kann das Programm jede Serverfunktion ausführen
; ... Server zu veranlassen mit Hilfe des Extension Control Blocks eine response zu erzeugen
; HttpExtensionProc erfolgreich war, so wird das dem Server mit dem Ausgabewert SUCCESS mitgeteilt.
; PENDING ERROR
; TerminateExtension
edit :
ISAPI-Programme müssen als DLL compiliert und in den Webserver
eingebunden werden. Ich denke sie stellen eine echte Alternative zu
einem selbstgeschriebenen Server da.