
WebSite API 1.1 SDK
Server Function Descriptions
15-September-97
Index
Syntax
BOOL later_than(char *t1, char *t2)
- t1
- HTTP-compliant date/time to test
- t2
- HTTP-compliant date/time to test against
Returns TRUE only if t1 is later than t2
Description
Compare times in HTTP-compliant string format. This function is exposed so that you can do your own "If Modified Since" support. You can use http_timestr() or http_nt_timestr() to get properly formatted string(s).
Example
struct stat fi;
char *cp;
FILE *myfp;
...
fstat(fileno(myfp), &fi);
strcpy(tp->last_modified, http_timestr(fi.st_mtime));
if(tp->if_modified_since[0] != '\0' &&
!later_than(cp, tp->if_modified_since))
die(USE_LOCAL_COPY, NULL, tp);
Syntax
void MD5Init(MD5Context *ctx);
- ctx
- Address of an MD5 context block
Description
Call this function to set up an MD5 digest. The structure definition and typedef for MD5Context is in wsapi.h. See also MD5Update() and MD5Final(). See RFC 1321: The MD5 Message-Digest Algorithm for more information on MD5 itself.
Example
See the example in MD5Update().
Syntax
void MD5Update(MD5Context *ctx, BYTE *buf, DWORD len);
- ctx
- Address of an (at least) initialized MD5 context block
- buf
- Buffer containing data to be added to the digest
- len
- Length in bytes of the data in the buffer to be added to the digest
Description
Use this function to add data to the digest. You may call this fucntion as many times as you want, with buffers of any size. The MD5Context structure must be initialized using MD5Init() before calling this function for the first time.
See Also MD5Init() and MD5Final(). See RFC 1321: The MD5 Message-Digest Algorithm for more information on MD5 itself.
Example
//
// Determine the MD5 digest of a string. Returns 16 bytes
// (digest is a 128 bit number). No regard for byte-ordering
// here, as Intel is a little-endian machine. You may need
// the bytes ordered differently!
//
void MDString(char *str, BYTE digest[16]) {
MD5Context ctx;
MD5Init(&ctx);
MD5Update(&ctx, str, strlen(str));
MD5Final(digest, &ctx);
}
Syntax
void MD5Final(BYTE digest[16}, MD5Context *ctx);
- digest
- A 16-byte array into which the digest is put
- ctx
- Address of the MD5 context block used to accumulate the digest
Description
Once you have accumulated all the data you want into the digest, call this function to complete the digest and fill it into the specified 16-byte buffer. Once the digest has been copied, this function zeroes the context block to remove any traces of the operation.
See Also MD5Init() and MD5Update(). See RFC 1321: The MD5 Message-Digest Algorithm for more information on MD5 itself.
Example
See the example in MD5Update().
Syntax
void nflush(TCTX *tp)
- tp
- transaction context pointer
Description
Flush the network output buffer. Call this when you want to force all remaining data out to the network (and to the client). Useful mostly in server-push applications. The function will fail via an exception (using the ABORT macro) on a variety of network I/O problems. In general, you need to be concerned about these only if you have allocated memory that needs to be freed. In this case, you should guard the call with a try/finally or a try/except block as appropriate to your application. Do not dismiss these exceptions under any circumstances. They are used for proper completion of the transaction.
Example
nflush(tp); // Force remaining data to browser
Syntax
void ngets(char *buf, int max, TCTX *tp)
- buf
- Address of buffer to receive next line of data from client
- max
- Maximum length of line (safety stop)
- tp
- transaction context pointer
Description
Get the next "line" of data from the browser. A line is a string ending in a linefeed character (0x0A). If the line length exceeds max, the function generates an exception via the ABORT macro and does not return. It also generates exceptions on a variety of network I/O problems. In general, you need to be concerned about these only if you have allocated memory that needs to be freed. In this case, you should guard the call with a try/finally or a try/except block as appropriate to your application. Do not dismiss these exceptions under any circumstances. They are used for proper completion of the transaction. If you call this when there is no complete line available for input, the call will hang for the Read Timeout (as set in the server's property sheet) then fail via an exception.
Example
char buf[MED_STRING_LEN];
...
ngets(buf, MED_STRING_LEN, tp);
Syntax
BOOL normalize_url(char *path)
- path
- URL path (only, no scheme/host/port)
Return TRUE if any modifications were made to the URL
Description
Remove redundant or unsafe syntax from a URL. Remove multiple /s, change ./ to /, remove things like foo/../ and trailing /. This function is useful when comparing a URL to a reference. If the URL has spurious syntax, the match will fail, however the URL may still translate into a usable file path.
The return value, if TRUE, can be used to generate a redirect response to the cliet with the cleaned-up path. The server does this automatically on simple GET URLs.
Example
char buf[MAX_STRING_LEN];
BOOL bMod;
...
strcpy(buf, "/foo/../bar/././//./xyz.html");
bMod = normalize_url(buf); // Results in /bar/xyz.html, returns TRUE
Syntax
void nputs(char *str, TCTX *tp)
- str
- Address of string to send to the client
- tp
- transaction context pointer
Description
Buffered write of a string to the client. The string may be any length. Line terminators are not significant. The data will be actually sent to the client only when the internal WebSite net buffer is full, or when you call nflush(). The function will fail via an exception (using the ABORT macro) on a variety of network I/O problems. In general, you need to be concerned about these only if you have allocated memory that needs to be freed. In this case, you should guard the call with a try/finally or a try/except block as appropriate to your application. Do not dismiss these exceptions under any circumstances. They are used for proper completion of the transaction.
Example
nputs("X-Special-Header: Fun-n-games\015\012", tp);1 // HTTP headers CRLF terminated
Syntax
void nread(char *buf, long nreq, TCTX *tp)
- buf
- address of buffer to receive data
- nreq
- number of bytes to read
- tp
- transaction context pointer
Description
Read specified number of bytes from the client. The function generates exceptions on a variety of network I/O problems. In general, you need to be concerned about these only if you have allocated memory that needs to be freed. In this case, you should guard the call with a try/finally or a try/except block as appropriate to your application. Do not dismiss these exceptions under any circumstances. They are used for proper completion of the transaction. If you call this when there fewer than nreq bytes available for input, the call will hang for the Read Timeout (as set in the server's property sheet) then fail via an exception.
Example
char buf[MAX_STRING_LEN];
...
if(tp->content_length > (MAX_STRING_LEN - 1))
die(SERVER_ERROR, "Content exceeded internal buffer size.", tp);
nread(buf, tp->content_length, tp);
Syntax
void nreadf(HANDLE hFile, long nreq, TCTX *tp)
- hFile
- Win32 open file handle
- nreq
- number of bytes to read
- tp
- transaction context pointer
Description
Efficient read of specified number of bytes from the client directly into an open file. The file must be open for write. The function generates exceptions on file and network I/O problems. In general, you need to be concerned about these only if you have allocated memory that needs to be freed or handle(s) that need to be closed. In this case, you should guard the call with a try/finally or a try/except block as appropriate to your application. Do not dismiss these exceptions under any circumstances. They are used for proper completion of the transaction. If you call this when there fewer than nreq bytes available for input, the call will hang for the Read Timeout (as set in the server's property sheet) then fail via an exception.
Example
HANDLE hFile;
...
hFile = CreateFile(...
...
__try
{
nreadf(hFile, tp->content_length, tp);
}
__finally
{
CloseHandle(hFile); // Avoid file handle leaks
}
Syntax
void nwrite(char *buf, int nreq, TCB *tp)
- buf
- Buffer containing bytes to write to client
- nreq
- Number of bytes to write from buffer
- tp
- transaction context pointer
Description
Buffered write to the client. The buffer may be any length. The data will be actually sent to the client only when the internal WebSite net buffer is full, or when you call nflush(). The function will fail via an exception (using the ABORT macro) on a variety of network I/O problems. In general, you need to be concerned about these only if you have allocated memory that needs to be freed. In this case, you should guard the call with a try/finally or a try/except block as appropriate to your application. Do not dismiss these exceptions under any circumstances. They are used for proper completion of the transaction.
Example
nwrite(buf, 1200, tp);1
Syntax
void nwritef(HANDLE hFile, DWORD dwStartPos, DWORD dwCount, TCB *tp)
- hFile
- Win32 open file handle
- dwStartPos
- Starting byte position in file (0-based)
- dwCount
- Number of bytes to send
- tp
- transaction context pointer
Description
Efficient direct (unbuffered) write from open file (from given offset to end-of-file) to client. This function first calls nflush() to empty the WebSite internal network output buffer, then transmits the file using memory-mapped I/O. The function will fail via an exception (using the ABORT macro) on a variety of network I/O problems. In general, you need to be concerned about these in order to close the file handle and/or if you have allocated memory that needs to be freed. In this case, you should guard the call with a try/finally or a try/except block as appropriate to your application. Do not dismiss these exceptions under any circumstances. They are used for proper completion of the transaction.
Example
char *fn = "c:\\foo\\bar.html";
HANDLE hFile;
BY_HANDLE_FILE_INFORMATION finfo;
SYSTEMTIME stLastModGMT;
...
hFile = CreateFile(fn, ...);
set_content_type(fn, tp);
GetFileInformationByHandle(hFile, &finfo); // Get file info
tp->content_length = finfo.nFileSizeLow; // File must be < 2GB!
//
// Set up HTTP Last-Modified. The SYSTEMTIME is assumed to be in GMT!
//
FileTimeToSystemTime(&(finfo.ftLastWriteTime), &stLastModGMT);
http_nt_timestr(&stLastModGMT, tp->last_modified, sizeof(tp->last_modified));
//
// Add an "extra header" field to the HTTP header
//
if(tp->num_rsp_xhdr < MAX_EXT_HEADERS)
{
tp->rsp_xhdr[tp->num_rsp_xhdr].key = wsapi_strdup("X-Special", tp);
tp->rsp_xhdr[tp->num_rsp_xhdr++].value = wsapi_strdup("Some info", tp);
// NOTE! --------------^^
}
//
// Send the HTTP header, then the file itself.
//
send_http_header(tp, TRUE);
__try
{
nwritef(hFile, tp); // This may generate an exception...
}
__finally
{
CloseHandle(hFile); // This prevents file handle leaks
}
Syntax
FORM_CTX open_form_decoder(BYTE *data, DWORD len, TCTX *tp)
- data
- Pointer to the form data in memory, plus a terminating null character.
- len
- The length in bytes of the form data in memory.
- tp
- transaction context pointer
Returns an opaque context handle (FORM_CTX as defined in wsapi.h), which is used in subsequent calls to decode_next_field(), and eventually, close_form_decoder().
Description
Initializes the WSAPI form decoder for subsequent enumeration of the fields in the form via calls to decode_next_field(). The decoder engine is optimized to do in-memory scanning and conversion, rather than relying on slower streaming techniques. This means that the whole of the posted form data must reside in a read/write memory block. This may conveniently be created by allocating tp->content-length + 1 bytes using wsapi_malloc(), then reading tp->content-length bytes into the block with a single call to nread().
The WSAPI form decoder transparently handles both form data encoding types (application/x-www-form-urlencoded and multipart/form-data). This means that WSAPI generators that use the decoder with forms need not be concerned with the encoding used in a form. It also means that the new forms-based file uploading feature of some browsers is supported by the decoder.
Example:
FRM_CTX ctx;
FIELD *fp;
BYTE *pdata;
DWORD dlen;
...
dlen = tp->content_length;
pdata=wsapi_malloc((dlen+ 1), tp); // Allocate space for form data & null
pdata[dlen] = '\0'; // Terminating null, required!
//
// Guard the rest against network errors, etc.
//
__try
{
nread(pdata, dlen, tp); // Read all form data
ctx = open_form_decoder(pdata, dlen, tp); // Initialize the decoder
while((fp = decode_next_field(ctx, tp)) != NULL)
{
... do what you like with the field data
... accessible via fp->
}
}
__finally // Assure proper memory cleanup!
{
close_form_decoder(ctx, tp);
wsapi_free(pdata);
}
Syntax
HKEY OpenRegKey(char *key)
- key
- String containing the key name, relative to HKEY_LOCAL_MACHINE
Description
Open a registry key. If the key does not exist, this function generates an exception via the ABORT macro. You can trap these with a try/except block for cleanup purposes.
Example
HKEY hKey;
...
hKey = OpenRegKey("SOFTWARE\\Denny\\WebServer\\CurrentVersion");
Syntax
void plus_to_space(char *str)
- str
- String containing plus-separated components
Description
Convert plus characters in a string to space characters. The inverse of space_to_plus(). Generally used together with unescape_url(). The conversion is done in place, therefore the buffer containing the string must be writeable.
Example
char buf[SML_STRING_LEN];
...
strcpy(buf, "This+is+a+test");
plus_to_space(buf); // Results in "This is a test"
Syntax
void process_get(char *meth, char *url, char *args, TCTX *tp)
- meth
- method, GET or HEAD (only!)
- url
- URL path only (absolute, must start with /)
- args
- URL arguments (query string), must not be NULL
- tp
- transaction context pointer
Description
High-level interface to the server's GET handler. Use this to cause the server to act as though the client issued a GET for the specified URL and arguments. When the function returns, the target document will have been sent to the client.
The function will fail via an exception (using the ABORT macro) on a variety of network I/O problems. In general, you need to be concerned about these only if you have allocated memory that needs to be freed or handles that need to be closed. In this case, you should guard the call with a try/finally or a try/except block as appropriate to your application. Do not dismiss these exceptions under any circumstances. They are used for proper completion of the transaction
Example
process_get("GET", "/", "", tp);1 // Return home page