ServerSupportFunction - general purpose callback for ISAPI handlers.
/* cb is either an extension control block or a filter context; see isapi(7) */ HCONN connid = (extension) ? cb->ConnID : cb; DWORD request; /* at least 18 possible values, which control the meanings of ... */ LPVOID buffer; LPDWORD size, type;
if ( cb->ServerSupportFunction( connid, request, buffer, size, type )) { /* Success: use results */ } else { /* handle error */ }
An ISAPI-handled request, when passed down to a handler library, is
described by a `control block' or `filter context' data structure (the
pointer to which is above illustratively given as variable `cb') which
provides various routines by which the handler can communicate with the
client and server. One of these is the ServerSupportFunction, which
provides a variety of support functionality which the handler may need. See
isapi(7)
or the appropriate Http*Proc(3) for details.
ServerSupportFunction is a generic routine providing a wide range of services. Some of these are available for filters, some for extensions and some for both.
First argument identifies the connection being serviced; it is obtained from the same control block or filter context as provided ServerSupportFunction; for an extension it is the ConnID field of the control block; for a filter, it is the filter context itself.
Second argument (request) is a DWORD specifying what to do; this dictates the meaning of the remaining three arguments (buffer, size and type). These last are all pointers (and may be ignored for some requests); the DWORD pointed to by size generally describes the size of the array indicated by buffer, the DWORD pointed to by type generally provides ancillary data; and buffer is generally the main channel of information. However the details of their meanings and roles depend on the request code.
The following request values are recognized. Those whose names begin HSE_ are only available to extensions, those beginning SF_ are only available to filters; where a request value is valid for both types, both names are listed.
This sends an HTTP header (without its trailing blank line); it should only be called once during any given invocation of an Http*Proc. Its buffer parameter, if non-NULL, is interpreted as a string giving the HTTP status line, e.g. ``200 OK''. The meaning of the other two parameters varies between filters and extensions.
For an extension, using HSE_REQ_SEND_RESPONSE_HEADER, size is interpreted as a pointer to an integer giving the number of bytes of text pointed to by type, which is interpreted as a string containing further headers.
For a filter, using SF_REQ_SEND_RESPONSE_HEADER, size is interpreted as a string providing further headers; type is ignored.
Emits logging information.
Sets up for asynchronous reading from the client. Requires last argument, type, to be HSE_IO_ASYNC.
Ignores size and type; buffer may optionally point to a DWORD (i.e. 32-bit int) which contains an HSE_STATUS code, notably the value HSE_STATUS_SUCCESS_WITH_KEEP_CONN.
This explicitly requests that the connection be closed.
Enquires whether the connection has keep-alive enabled. Pass the address of a BOOL variable as buffer; it will be set to TRUE or FALSE as appropriate. Note, later request processing may alter the state of the keep-alive status of this connection, so this callback is not very useful, but is included for compatibility with IIS.
Third parameter, buffer, should point to the start of a character array; fourth parameter, size, should point to a DWORD. In buffer, store an URL-namespace path (terminated with a '\\0'), in size store the size of the buffer (this may usefully be greater than the length of the URL path); then call ServerSupportFunction. (Ignores last parameter, type - but see HSE_REQ_MAP_URL_TO_PATH_EX, below.) On successful return, buffer shall contain the local file-system's path corresponding to the given URL; this path's length will be stored in size.
This callback is currently unimplemented.
Point buffer at a '\\0'-terminated string specifying an URL, point size at a DWORD containing the length of this string (type is ignored). The client will be sent an HTTP 302 response (URL Redirect) redirecting it to the given URL. A handler using this should tidy up any resources allocated to the request and return control to the ISAPI runner, since the client will be redirected, so will not see any further response from the handler.
Point buffer at a '\\0'-terminated string giving an URL, point size at a DWORD containing the length of this string (type is ignored). The client will receive the response it would have received if the client had requested this URL (but it will appear to have come from the URL the client requested). A handler using this should tidy up and return as for a redirect.
Provides a very high-performance mechanism for sending a file (or a portion of a file) to the client, with an optional header or footer. HSE_REQ_TRANSMIT_FILE will send the file directly from the webserver's internal cache, and is the recommended way of sending content back to the client for scenarios requiring high-performance.
The buffer variable should point to a HSE_TF_INFO object. size and type parameters are ignored. See the EXAMPLES section below for sample usage.
HSE_TF_INFO.pHead and HSE_TF_INFO.pTail, if provided, should point to memory that is valid for the lifetime of the
connection, e.g. it should either be static, or point into memory returned
from the AllocMem()
call. It
should not point to temporarily allocated memory, such as off the stack, since this
memory is used to asynchonrously write the data to the client in the
background after the ISAPI extension has completed, the web server does not
take a copy of it for performance reasons.
Registers some headers for the web server to deliver if processing of the request leads to access denial. These headers will be ignored if the request is responded to successfully.
Suppresses some notifications.
Returns the connection ID associated with the request being processed. This is the ConnID field of the EXTENSION_CONTROL_BLOCK an extension would see: it is of use (for example) in enabling filters and extensions to coordinate shared data.
Requests normalization of a URL.
Sets the block-size in which buffered data is to be read: only of use to filters which return SF_STATUS_REQ_READ_NEXT while handling one of the raw data notifications.
Indicates that the request came from a proxy.
The following request values are extensions added by the Zeus Web Server.
Allows in-process ISAPI extensions or filters to get hold of the raw file-descriptor that the web server is using to talk to the client.
buffer should point to a memory location containing a DWORD. size should contain the size of the buffer, which should be at least a DWORD in size. Upon successful return buffer will be filled in with the file-descriptor.
Allows an ISAPI extension to use the per-request memory pool facility provided by the web server. Allocations from this memory pool are very fast, and any memory allocated is actually freed upon completion of the request, making memory management much easier and memory leaks much less likely.
On entry, size should point to a DWORD containing the amount of memory to allocate. On successful return, buffer will point the allocated memory block.
An extension of the functionality for HSE_REQ_TRANSMIT_FILE. Allows the
ISAPI extension (in-process only), to provide multiple chunks to write back
to the client, similar to the writev()
system call. Each chunk
has a flag associated with it which provides the web server with
information about the 'lifetime' of the chunk. Each chunk can live in one
of three states:
1. from the file denoted by hFile
2. from memory that will be stable/persistent for at least the lifetime of the transaction. The web server need not take a copy of it.
3. from memory that is not stable/persistent for at least the lifetime of the transaction. The web server will take a copy of the data presented to it in this call, and use that copy to send asynchronously to the client.
On entry, buffer should point to a HSE_TFV_INFO structure.
Currently, at most one chunk can be provided by hFile.
Available to in-process extensions only. Allows the ISAPI extension to retrieve the address of a memory location that is updated with the current time once-per-second. This allows the ISAPI extension to get hold of the current time without having to use expensive OS calls.
On entry, buffer should point to an LPDWORD, and size should point to a DWORD containing the size of the memory pointed to be buffer, which should be >= sizeof(
LPDWORD ). Upon successful
return, buffer will now point to a memory location which will always contain the current
time.
Available to in-process filters only. Allows the ISAPI filter to specify
which mime-type/class it is interested in dealing with when using the
SF_NOTIFY_SEND_RAW_DATA hook. Generally, most ISAPI filters using
SF_NOTIFY_SEND_RAW_DATA are only interested in rewriting a particular kind
of response (e.g. those of the mime-type text/html
), and the overhead of using SF_NOTIFY_SEND_RAW_DATA is quite high. By
using this support function, the filter can tell the web server to only
call it to rewrite output of certain mime-types, which can provide a huge
performance increase.
Furthermore, setting the mime-type it is interested in to an unused/invalid
mime-type, (e.g. /
), allows the ISAPI filter to notify the web server it is not interested in
this rewriting this connection at all.
Obviously this must be called before any data is sent to the client, so SF_NOTIFY_PREPROC_HEADERS is a good time.
On entry, buffer should point to a zero-terminated string containing the mime-type, or
mime-class that the filter is interested in receiving
SF_NOTIFY_SEND_RAW_DATA events for. An example mime-type would be
text/html
. An example mime-class would be text/
, which would signify the filter is interested in any mime-types beginning
'text/'.
Available to in-process ISAPI filters only, SF_REQ_BYTES_WRITTEN allows a filter to retrieve the number of bytes that have been written to the client, primarily useful on the SF_NOTIFY_LOG notification event.
On entry, buffer should point to a DWORD, and size should point to a DWORD containing the size of buffer, which should be at
least sizeof(
DWORD ). On successful return, buffer willl contain the number of bytes written to the client, including HTTP
headers.
Available to in-process ISAPI filters only, SF_REQ_GET_INHEADER and SF_REQ_GET_OUTHEADER are primarily useful on the SF_NOTIFY_LOG notification event. They allow the ISAPI filter the query the HTTP headers that were sent back to the client, and the HTTP headers in the client's request.
On entry, buffer should point to a zero-terminated string containing the header line to
query, e.g. 'Content-Length'
. size should point to a memory location where the result should be placed. type should point to a DWORD which contains the size of the buffer pointed to be size. On successful return, the memory pointed to by size will be filled with a zero-terminated string.
The following Microsoft-specific request values are supported by IIS but not by ZWS, generally because they relate to functionality needed in Windows but having no natural equivalent under Unix.
Third argument, buffer, should be the address of a HANDLE, which will be made to represent a user context, needed if the ISAPI handler is to perform Windows-specific `impersonation' actions.
Registers a completion-callback for asynchronous I/O operations. Requires buffer to be the address of a callback function, of type PFN_HSE_IO_COMPLETION, with its associated Context value as the final argument, type. The latter will be passed as the second argument to the former whenever the former is called.
Selects Windows' ruder but more efficient TCP socket close option, there is no equivalent under Unix.
Access to the contents of an SF_PROPERTY_IIS structure.
Third argument, buffer, should be a CtxtHandle; fifth, type, should be a CredHandle. Only available for in-process extensions.
Buffer should be a pointer to a CERT_CONTEXT_EX structure, within which the embedded buffer of CERT_CONTEXT is allocated; the first certificate in the client's certificate chain will be copied into this.
Sets an SSPI security context and impersonation token derived from a client certificate.
A fuller URL-decoding interface, extending HSE_REQ_MAP_URL_TO_PATH: this requires the last parameter, type, to point to an HSE_URL_MAPEX_INFO structure into which the URL will be decoded.
This callback is currently unimplemented.
Force ISAPI runner to re-read the ACL of the handler: buffer points to a string containing the name of the shared library implementing the handler.
As HSE_REQ_SEND_URL but `with support for specifying the verb to use in the redirect'.
This extends HSE_REQ_SEND_RESPONSE_HEADER by taking a pointer to a
HSE_SEND_HEADER_EX_INFO(5)
structure as its buffer argument:
ignores the other two arguments.
Returns TRUE on success; FALSE otherwise.
HSE_REQ_TRANSMIT_FILE
For most efficient operation:
Use HSE_IO_SEND_HEADERS to send the headers in the same call as the HSE_REQ_TRANSMIT_FILE call.
If you are providing the entire response to this query, and are not going
to be doing subsequent calls to WriteClient(),
set the
HSE_IO_DISCONNECT_AFTER_SEND flag.
This flag notifies the webserver that is has enough information to generate the entire response, and when coupled with the HSE_IO_SEND_HEADERS flag, it will cause the webserver to automatically insert a 'Content-Length' header in the response and negotiate a HTTP/1.1 keep-alive response with the client.
Sample usage:
/* Sample extension that demonstrates use of HSE_REQ_TRANSMIT_FILE */
#include <string.h> #include <stdio.h>
#include "httpext.h"
#define Success 0 #define Failure -1
static int run( LPEXTENSION_CONTROL_BLOCK );
// ----------------------------------------------------------
BOOL WINAPI GetExtensionVersion( HSE_VERSION_INFO *pVer ) { pVer->dwExtensionVersion = 1; strncpy( pVer->lpszExtensionDesc, "Transmitfile test", HSE_MAX_EXT_DLL_NAME_LEN ); return 1; }
// ----------------------------------------------------------
DWORD WINAPI HttpExtensionProc( LPEXTENSION_CONTROL_BLOCK ecb ) { if( run( ecb ) == Failure ) return HSE_STATUS_ERROR; return HSE_STATUS_SUCCESS_AND_KEEP_CONN; }
// ----------------------------------------------------------
static void WriteHeader( LPEXTENSION_CONTROL_BLOCK ecb, const char* a ) { DWORD sz = strlen( a ); ecb->ServerSupportFunction( ecb->ConnID, HSE_REQ_SEND_RESPONSE_HEADER, 0, &sz, (DWORD*)a ); }
// ----------------------------------------------------------
static void Output( LPEXTENSION_CONTROL_BLOCK ecb, const char* a ) { DWORD l = strlen( a ); ecb->WriteClient( ecb->ConnID, (void*)a, &l, 0 ); }
// ----------------------------------------------------------
static int run( LPEXTENSION_CONTROL_BLOCK ecb ) { static int headerlen = 0; static int trailerlen = 0; static const char* header = "This is my header\n"; static const char* trailer = "This is my trailer\n";
const char* filename = "/etc/passwd"; HSE_TF_INFO tf;
// one-time initalisation if( headerlen == 0 ) headerlen = strlen( header ); if( trailerlen == 0 ) trailerlen = strlen( trailer );
tf.pfnHseIO = 0; /* these must be 0 for Zeus */ tf.pContext = 0; tf.hFile = (HANDLE)filename; tf.pszStatusCode = "200 OK\n" "Content-Type: text/plain\nFoo: bar"; /* write all of file - could specify a portion */ /* of the file to send here. */ tf.BytesToWrite = 0; tf.Offset = 0; tf.pHead = (PVOID)header; tf.HeadLength = headerlen; tf.pTail = (PVOID)trailer; tf.TailLength = trailerlen;
// Because we are not going to be sending any more // data after this, we set // HSE_IO_DISCONNECT_AFTER_SEND to let the webserver // know, and because we are also generating headers, // we can use this information to insert a // Content-Length & hence use HTTP KeepAlive for // better performance.
tf.dwFlags = HSE_IO_SEND_HEADERS | HSE_IO_DISCONNECT_AFTER_SEND | HSE_IO_HANDLE_IS_FILENAME;
if( ecb->ServerSupportFunction( ecb->ConnID, HSE_REQ_TRANSMIT_FILE, &tf, 0, 0 ) == TRUE ) return Success;
// Failed for some reason! // Drop back to less efficent code WriteHeader( ecb, "Content-Type: text/html" ); Output( ecb, "Transmitfile failed" ); return Success; }
isapi(7),
HttpExtensionProc(3),
HttpFilterProc(3),
EXTENSION_CONTROL_BLOCK(5),
HTTP_FILTER_CONTEXT(5),
HSE_SEND_HEADER_EX_INFO(5).
$ZEUSHOME/web/include/httpext.h $ZEUSHOME/web/include/httpfilt.h $ZEUSHOME/web/include/wintypes.h $ZEUSHOME/webadmin/docroot/docs/modules/isapi/*.html
Note that the type name for a pointer to a HSE_TF_VEC structure, as passed when requesting HSE_REQ_TRANSMIT_FILEV, has been changed from LPHSE_TV_VEC to LPHSE_TF_VEC, the intended spelling. The old name is deprecated but supported by a #define; extensions using it should replace the old name with the new.
Copyright (C) 2000-2001 Zeus Technology Limited. All rights reserved.