# WebSite API 1.1 SDK Server Function Descriptions

15-September-97

## later_than

### 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);

## MD5Init

### 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().

## 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.

### 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;);
}

## MD5Final

### 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.

### Example

See the example in MD5Update().

## nflush

### 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

## ngets

### Syntax

void ngets(char *buf, int max, TCTX *tp)
buf
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);

## normalize_url

### Syntax

BOOL normalize_url(/wsdocs/wsapi/char_path/index.html)
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(/wsdocs/wsapi/buf/index.html); // Results in /bar/xyz.html, returns TRUE

## nputs

### 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.

### Syntax

void nread(char *buf, long nreq, TCTX *tp)
buf
nreq
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);

### Syntax

void nreadf(HANDLE hFile, long nreq, TCTX *tp)
hFile
Win32 open file handle
nreq
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
{
}
__finally
{
CloseHandle(hFile); // Avoid file handle leaks
}

## nwrite

### 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

## nwritef

### 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));
//
//
{
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.
//
__try
{
nwritef(hFile, tp);        // This may generate an exception...
}
__finally
{
CloseHandle(hFile);        // This prevents file handle leaks
}

## open_form_decoder

### 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
{
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);
}

## OpenRegKey

### 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");

## plus_to_space

### 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(/wsdocs/wsapi/buf/index.html); // Results in "This is a test"

## process_get

### Syntax

void process_get(char *meth, char *url, char *args, TCTX *tp)
meth
url
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