W3C libwww HTEvent module for more information on the arguments. Likewise if you are on for example a Windows NT platform then use the following functions:

extern int HTEvent_RegisterTTY	(SOCKET sockfd, HTRequest * request, SockOps ops,
				 HTEventCallBack *cbf, HTPriority priority);
extern int HTEvent_UnRegisterTTY(SOCKET sockfd, SockOps ops);

The return code from an event handler is simple but very important. There are two allowed values:

HT_OK
If the handler could handle the event
HT_ERROR
If an internal error occured, for example a NULL argument was passed etc. This code will result in that the event loop is exit'ed and the application is ready to be terminated.

It helps understanding event handlers if you think of the Library as a coke machine (the ones with a coin slot only - the ones which also has a bill slot work differently!) Event handlers are the coin slot on top where you can request a service from the library. You are guaranteed that the machine never returns any coins to you the same way - they always come out at the bottom of the machine. This means that the Library always returns "Thanks, I have received your request - please look for the response at the bottom" on any request started from within an event handler. In the library case the result is always returned in the request termination handler that is the "bottom" of the Library machine.

Register a request termination handler

The application can register a callback function that is called whenever a request has terminated, regardless. The callback function can furthermore be registered to be called regardless of the status code or on upon a specific codes. The set of status codes is:

HT_LOADED
The request was successful
HT_INTERRUPTED
The request was interrupted
HT_ERROR
An error occured
HT_NO_DATA
The request resulted in an object with no data, for example a telnet session
HT_RETRY
The service was unavailable but the request can be repeated at at later time. This later time can be obtained using the function
extern time_t HTRequest_retryTime (HTRequest * request);

Return codes are not used from termination handlers.

Register an "Unknown Header" Handler

If you have additional headers that you want to experiment with you can register a header parser to handle all unknown headers. This handler is called whenever an unknown header is encountered when parsing the object header. If the returns YES then the MIME parser stores the metainformation in the anchor object if self so that it can be found at a later point in time. If the handler returns NO, then the header is discarded.

The header passed to the call back function will be in normal NULL terminated C string without any CRLF. The line will also be unwrapped so that it is easier to parse for the call back function.

typedef int HTMIMEHandler	(HTRequest * request, char * header);

extern int HTMIME_register	(HTMIMEHandler * cbf);
extern int HTMIME_unRegister	(void);

Register a Select Timeout Function

You can register a call back function together with a timeout that is used in the select call of the event loop. When the select() call times out, the call back function is called. The registration can either be so that the call back always is called when that the select call times out or only when Library sockets are in use.

typedef int HTEventTimeout (HTRequest *);

extern BOOL HTEvent_registerTimeout (struct timeval *tp, HTRequest * request, HTEventTimeout *tcbf, BOOL always);

Issue Requests to the Library

The Access module has a set of functions that works as a user interface to the request manager. You can call the request manager directly but often it is simpler to use the Access module. As mentioned, the request manager returns immediately and the result of the request is handled back to the application using the termination handlers.

What and When to Escape Strings

The Library's represents internally location strings as URLs which means that they always are escaped. Only when it is required to access a resource are they unescaped, for example via FTP. All location strings passed to the Library are also treated as URLs which means that they must be escaped already. Hence in the case of the request methods mentioned aboce, all URL arguments must be escaped if the resource is to be found.

Most often this is only a problem when people type in location strings directly, for example using "goto location" etc. In the Escape module the Library provides two functions for escaping location strings into URLs and unescaping URLs into location strings:

typedef enum _HTURIEncoding {
    URL_XALPHAS         = 0x1,
    URL_XPALPHAS        = 0x2,
    URL_PATH            = 0x4
} HTURIEncoding;

extern char * HTEscape (const char * str, HTURIEncoding mask);
extern char * HTUnEscape (char * str);

Multiple Simultaneous Requests

Multiple simultaneous requests can be started at any time from within an event handler. It is simply a question of calling one of the load functions in the Access module. The Library keeps a request queue where all active requests are kept. The application can define the maximum number of open sockets that can be open at any one time. This number is by default 6 but can be changed using the following functions:

extern BOOL HTNet_setMaxSocket (int newmax);
extern int  HTNet_maxSocket (void);

If there are no free sockets available the request is put into a pending queue and started as soon as possible.

Putting a request into a Context

When multiple requests can be initiated simultaneously it is in general not possible to predict the order that the results return to the application. This is a function of the size of the individual data objects, net work speed etc. In order to keep track of ordering of the requests, for example in the history list, it is necessary to put them into some kind of context. The Library provides the hooks for maintaining a context together with the Request object by the following methods:

typedef int HTRequestCallback (HTRequest * request, void *param);

extern void HTRequest_setCallback (HTRequest *request, HTRequestCallback *cb);
extern HTRequestCallback *HTRequest_callback (HTRequest *request);

The callback function can be passed an arbitrary pointer (the void part) which can describe the context of the current request structure. If such context information is desired then it can be set using the following methods:

extern void HTRequest_setContext (HTRequest *request, void *context);
extern void *HTRequest_context (HTRequest *request);

There is no limit to the definition of a context data object and the memory management if entirely up to the application. The Request object simply carries the information around.

Interrupt a request

Any request can be interrupted from an event handler by calling either of the functions (the first kills a specific request, the second is more radical and kills them all):

extern BOOL HTRequest_kill	(HTRequest * request);
extern BOOL HTNet_killAll	(void);

Logging and History Management

The library has a set of modules that are not called from within the library at all but can be used by the application. Two examples are a History manager and a Log manager that provides functionality for keeping a history list of visited objects and to provide logging of the results. The application is free to use there modules but does not have to.

User Messages

The library has a basic User Messages and Prompts module which is intended for the Line Mode Browser. In case you are building a GUI client you would probably want to write your own version using windows etc. This can be done by overriding the module in the Library with your own that has the same set of functions as described in the User's Guide.

When to free Objects

This is a short set of recommendation on when to free objects in memory.

Anchors
Anchors are normally not freed before the application terminates as they have important information about the part of the Web that the user has been in tough with. However, anchors can be freed at any time if they are not used by an ongoing request
Requests
Request objects are only intended to live as long as a request is being executed. A request object is a "information binder" that binds various data objects together as long as the request is running. As the Library uses asynchronous network I/O many requests can be handled "in parallel" but each request object only knows about one request. Therefore a request object can be free whenever a it has terminated which is the case when the request termination handler is called.