
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
O'Reilly Tech Support <support@ora.com>