developing ISAPI dlls in PB?
Posted: Fri Mar 17, 2006 12:35 am
Hello
Did anybody coded any ISAPI dll with PB?
Any code, help, etc?
Thanks in advance
Did anybody coded any ISAPI dll with PB?
Any code, help, etc?
Thanks in advance
http://www.purebasic.com
https://www.purebasic.fr/english/
Code: Select all
removed copyrighted code
Excellent!! I will be waiting!!freak wrote:I did this quite a while ago in PB, but it was quite some work due to stuff like the unsafety of threads.
It should be fairly easy though with PB4 now.
I will see if i can find some of these old codes and port it to PB4.
Code: Select all
;- ISAPI Constants
#HSE_VERSION_MAJOR = 6 ;/* 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
#HSE_URL_FLAGS_READ = $00000001 ;// Allow For Read
#HSE_URL_FLAGS_WRITE = $00000002 ;// Allow For Write
#HSE_URL_FLAGS_EXECUTE = $00000004 ;// Allow For Execute
#HSE_URL_FLAGS_SSL = $00000008 ;// Require SSL
#HSE_URL_FLAGS_DONT_CACHE = $00000010 ;// Don't cache (vroot only)
#HSE_URL_FLAGS_NEGO_CERT = $00000020 ;// Allow client SSL certs
#HSE_URL_FLAGS_REQUIRE_CERT = $00000040 ;// Require client SSL certs
#HSE_URL_FLAGS_MAP_CERT = $00000080 ;// Map SSL cert To NT account
#HSE_URL_FLAGS_SSL128 = $00000100 ;// Require 128 bit SSL
#HSE_URL_FLAGS_SCRIPT = $00000200 ;// Allow For Script execution
#HSE_URL_FLAGS_MASK = $000003ff
#HSE_EXEC_URL_NO_HEADERS = $02
#HSE_EXEC_URL_IGNORE_CURRENT_INTERCEPTOR = $04
#HSE_EXEC_URL_IGNORE_VALIDATION_AND_RANGE = $10
#HSE_EXEC_URL_DISABLE_CUSTOM_ERROR = $20
#HSE_EXEC_URL_SSI_CMD = $40
#HSE_VECTOR_ELEMENT_TYPE_MEMORY_BUFFER = 0
#HSE_VECTOR_ELEMENT_TYPE_FILE_HANDLE = 1
#HSE_APP_FLAG_IN_PROCESS = 0
#HSE_APP_FLAG_ISOLATED_OOP = 1
#HSE_APP_FLAG_POOLED_OOP = 2
;- ISAPI Structures
; Prototypes for the EXTENSION_CONTROL_BLOCK structure
;
Prototype GetServerVariable(ConnID, lpszVariableName.s, *lpvBuffer, *lpdwSizeofBuffer.LONG)
Prototype WriteClient(ConnID, *Buffer, *lpdwSizeofBuffer.LONG, dwSync)
Prototype ReadClient(ConnID, *lpvBuffer, *lpdwSize.LONG)
Prototype ServerSupportFunction(ConnID, dwServerSupportFunction, *lpvBuffer, *lpdwSizeofBuffer.LONG, *lpdwDataType.LONG)
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.s{#HSE_LOG_BUFFER_LEN}; Null-terminated log info. (why call it lpsz when it is not a pointer !?)
lpszMethod.s ; REQUEST_METHOD
lpszQueryString.s ; QUERY_STRING
lpszPathInfo.s ; PATH_INFO
lpszPathTranslated.s ; PATH_TRANSLATED
cbTotalBytes.l ; Total bytes indicated from client.
cbAvailable.l ; Available number of bytes.
lpbData.l ; Pointer to cbAvailable bytes.
lpszContentType.s ; Content type of client data.
GetServerVariable.GetServerVariable ; Server callback functions
WriteClient.WriteClient
ReadClient.ReadClient
ServerSupportFunction.ServerSupportFunction
EndStructure
Structure HSE_VERSION_INFO
dwExtensionVersion.l
lpszExtensionDescription.s{#HSE_MAX_EXT_DLL_NAME_LEN}
EndStructure
Structure HSE_URL_MAPEX_INFO
lpszPath.s{#MAX_PATH}; // Physical path root mapped to
dwFlags.l; // Flags associated with this URL path
cchMatchingPath.l; // Number of matching characters in physical path
cchMatchingURL.l; // Number of matching characters in URL
dwReserved1.l;
dwReserved2.l;
EndStructure
Structure HSE_UNICODE_URL_MAPEX_INFO
lpszPath.w[#MAX_PATH]; // Physical path root mapped to (unicode version)
dwFlags.l; // Flags associated with this URL path
cchMatchingPath.l; // Number of matching characters in physical path
cchMatchingURL.l; // Number of matching characters in URL
EndStructure
Prototype PFN_HSE_IO_COMPLETION(*lpECP.EXTENSION_CONTROL_BLOCK, *pContect, cbIO, dwError)
Structure HSE_TF_INFO
pfnHseIO.PFN_HSE_IO_COMPLETION
pContext.l
hFile.l
pszStatusCode.s; // HTTP Status Code eg: "200 OK"
BytesToWrite.l; // special value of "0" means write entire file.
Offset.l; // offset value within the file to start from
pHead.l; // Head buffer to be sent before file data
HeadLength.l; // header length
pTail.l; // Tail buffer to be sent after file data
TailLength.l; // tail length
dwFlags.l; // includes HSE_IO_DISCONNECT_AFTER_SEND, ...
EndStructure
Structure HSE_SEND_HEADER_EX_INFO
pszStatus.s; // HTTP status code eg: "200 OK"
pszHeader.s; // HTTP header
cchStatus.l; // number of characters in status code
cchHeader.l; // number of characters in header
fKeepConn.l; // keep client connection alive?
EndStructure
Structure HSE_EXEC_URL_USER_INFO
hImpersonationToken.l
pszCustomUserName.s
pszCustomAuthType.s
EndStructure
Structure HSE_EXEC_URL_ENTITY_INFO
cbAvailable.l
lpbData.l
EndStructure
Structure HSE_EXEC_URL_STATUS
uHttpStatusCode.w
uHttpSubStatus.w
dwWin32Error.l
EndStructure
Structure HSE_EXEC_URL_INFO
pszUrl.s; // URL to execute
pszMethod.s; // Method
pszChildHeaders.s; // Request headers for child
*pUserInfo.HSE_EXEC_URL_USER_INFO; // User for new request
*pEntity.HSE_EXEC_URL_ENTITY_INFO; // Entity body for new request
dwExecUrlFlags.l; // Flags
EndStructure
Structure HSE_EXEC_UNICODE_URL_USER_INFO
hImpersonationToken.l
pszCustomUserName.s
pszCustomAuthType.s
EndStructure
Structure HSE_EXEC_UNICODE_URL_INFO
pszUrl.s; // URL to execute
pszMethod.s; // Method
pszChildHeaders.s; // Request headers for child
*pUserInfo.HSE_EXEC_UNICODE_URL_USER_INFO; // User for new request
*pEntity.HSE_EXEC_URL_ENTITY_INFO; // Entity body for new request
dwExecUrlFlags.l; // Flags
EndStructure
Structure HSE_CUSTOM_ERROR_INFO
pszStatus.s
uHttpSubError.w
fAsync.l
EndStructure
Structure HSE_VECTOR_ELEMENT
ElementType.l; // Type of element (buffer/file/fragment etc)
pvContext.l; // The context representing the element to be sent
cbOffset.q; // Offset from the start of hFile
cbSize.q; // Number of bytes to send
EndStructure
Structure HSE_RESPONSE_VECTOR
dwFlags.l; // combination of HSE_IO_* flags
pszStatus.s; // Status line to send like "200 OK"
pszHeaders.s; // Headers to send
nElementCount.l; // Number of HSE_VECTOR_ELEMENT's
*lpElementArray.HSE_VECTOR_ELEMENT; // Pointer to those elements
EndStructure
Structure HSE_TRACE_INFO
fTraceRequest.l
TraceContextId.b[16]
dwReserved1.l
dwReserved2.l
EndStructure
Code: Select all
XIncludeFile "Isapi.pb"
; GetExtensionVersion is called when the dll is loaded
;
ProcedureDLL GetExtensionVersion(*pver.HSE_VERSION_INFO)
*pver\dwExtensionVersion = #HSE_VERSION ; set the version info (6.0)
*pver\lpszExtensionDescription = "ISAPI extension test in PureBasic" ; Its a fixed length string so we can just assign the text
ProcedureReturn #True ; return success. returning False will cause the dll to be unloaded again
EndProcedure
; This is just a small helper function to wrap the GetServerVariable call
; for easier access
;
Procedure.s ServerVariable(*pECB.EXTENSION_CONTROL_BLOCK, Name$)
*Buffer = AllocateMemory(1000)
Size = 1000
Value$ = ""
If *pECB\GetServerVariable(*pECB\ConnID, Name$, *Buffer, @Size) = #True
Value$ = PeekS(*Buffer, Size)
EndIf
FreeMemory(*Buffer)
ProcedureReturn Value$
EndProcedure
; This is the main function that is called for each client request
; *pECB contains all needed data
;
ProcedureDLL HttpExtensionProc(*pECB.EXTENSION_CONTROL_BLOCK)
; Lets build some HTML code to send back
;
Html$ = "<html><head><title>ISAPI extension test in PureBasic</title></head><body>"
Html$ + "<br><hr><center>ISAPI extension test in PureBasic</center><hr>"
Html$ + "<br><br>"
; Some information is directly provided through the structure, other stuff
; can be read with the GetServerVariable callback:
;
Html$ + "Some examples for input data:<hr>"
Html$ + "<b>REQUEST METHOD:</b> " + *pECB\lpszMethod + "<br>"
Html$ + "<b>QUERY_STRING:</b> " + *pECB\lpszQueryString + "<br>"
Html$ + "<b>PATH_INFO:</b> " + *pECB\lpszPathInfo + "<br>"
Html$ + "<b>PATH_TRANSLATED:</b> " + *pECB\lpszPathTranslated + "<br>"
Html$ + "<b>CONTENT TYPE:</b> " + *pECB\lpszContentType + "<br>"
Html$ + "<b>REMOTE_ADDR:</b> " + ServerVariable(*pECB, "REMOTE_ADDR") + "<br>"
Html$ + "<br><br>"
Html$ + "DATA sent from the client:(" + Str(*pECB\cbTotalBytes) + " Bytes)<hr>"
Html$ + "<pre>"
; An important note on POST data from the client:
;
; 'cbTotalBytes' indicates the total number of bytes available from the client.
; 'cbAvailable' indicates the number of bytes directly available in the 'lpbData'
; Buffer. These two may differ (for larger number of datas). So the correct way is
; to read anything inside 'lpbData', and then call the ReadClient() callback as shown
; below until all data is read from the client, if there is more than 'cbAvailable' bytes available
;
If *pECB\cbAvailable > 0
Html$ + PeekS(*pECB\lpbData, *pECB\cbAvailable)
EndIf
If *pECB\cbTotalBytes > *pECB\cbAvailable
BytesRead = *pECB\cbAvailable
*Buffer = AllocateMemory(1000)
If *Buffer
While BytesRead < *pECB\cbTotalBytes
Size = 1000
*pECB\ReadClient(*pECB\ConnID, *Buffer, @Size)
Html$ + PeekS(*Buffer, Size)
BytesRead + Size
Wend
FreeMemory(*Buffer)
EndIf
EndIf
Html$ + "</pre>"
Html$ + "<br><br>"
Html$ + "Test: Enter something and it will be sent to the dll via POST method.<hr>"
Html$ + "<form action="+Chr(34)+ServerVariable(*pECB, "URL")+Chr(34)+" method=POST>"
Html$ + "<textarea name="+Chr(34)+"text"+Chr(34)+" rows=10 cols=60>Enter text</textarea><br>"
Html$ + "<input type=submit>"
Html$ + "</form>"
Html$ + "</body></html>"
; Send the response header with the ServerSupportFunction() callback
;
Header.HSE_SEND_HEADER_EX_INFO
Header\pszStatus = "200 OK"
Header\pszHeader = "Content-type: text/html" + Chr(13)+Chr(10)+Chr(13)+Chr(10)
Header\cchStatus = Len(Header\pszStatus)
Header\cchHeader = Len(Header\pszHeader)
Header\fKeepConn = 0
*pECB\ServerSupportFunction(*pECB\ConnID, #HSE_REQ_SEND_RESPONSE_HEADER_EX, @Header, 0, 0)
; Send the html data with the WriteClient() callback:
;
Length = Len(Html$)
*pECB\WriteClient(*pECB\ConnID, @Html$, @Length, 0)
; return success
;
ProcedureReturn #HSE_STATUS_SUCCESS
EndProcedure
; TerminateExtension is called before unloading the dll.
;
ProcedureDLL TerminateExtension(dwFlags)
ProcedureReturn #True
EndProcedure