As a part of the core Library, the error object is intended to pass information about errors and messages occuring in the Library back to the application. Each error is kept as an object so multiple errors can be nested together using the well-known HTList object. Nested error management can be used to build complicated error messages which an arbitrary level of details, for example:
This URL could not be retrieved: http://www.foo.com Reason: The host name could not be resolved Reason: DNS service is not availableThe principle behind the error manager is exactly like any other registration module in the Library in that it creates an object and binds it to a list that the caller provides. Often, errors are related to a specific request object and each request object will therefore keep its own list of errors. However, errors can also be maintained as separate lists which are not directly related to a request, for example, the application can keep its own list of errors independent of any Library errors.
Errors are roughly categorized into two classes: system errors and other errors. System errors include all errors that occur while interacting with the operating system. Often these errors occurs as a result of insufficient availability or authentication to a system resource. In many operating systems, the system provides a set of error messages which is associated with an error code made available to the application via the errno variable or equivalent. All other errors are registered with an error message belonging to the Library Error manager. Note, that there are no difference in how system errors and other errors are treated, they are the same data objects and can be registered together with no exception.
extern BOOL HTError_add (HTList * list, HTSeverity severity, BOOL ignore, int element, void * parameter, unsigned int length, char * where);The first argument is a list object and as always, we need to create a list object using the
HTList_new
method. The next element is an indication of how serious the error is in
the situation where it occured. Classification of errors are known from many operating systems, for
example VMS, and it gives the application the opportunity to decide whether the current operation
should be continued or aborted. The Library provides four severity categories:
typedef enum _HTSeverity { ERR_FATAL, ERR_NON_FATAL, ERR_WARN, ERR_INFO } HTSeverity;It is not always that an error is an error immediately when it occurs. In some situations it might first become an error later in the process depending on the outcome of other factors - or it might be circumvented so that no special action is required. The ignore flag provides this functionality in that an error can be registered at any time with the notion: "Register this error but ignore it for now".
The element
argument is an index into a table of all error messages. This table is
maintained in the HTError Module and contains an error
message together with a URl that might be included in an error message presented to the user. The
values of the element
argument itself is given by the HTErrorElement
enumeration definition in the HTEvent Module.
The next two arguments are used to register any parameters associated with the error. This can for example be the file name of a file which could not be opened, a URL which could not be accessed etc. By letting the parameter be a void pointer together with a length indication, the parameter can be an arbitrary data object. The last argument is a location description to indicate where the error occured. Often this is the name of the function or a module.
One thing, we didn't mention when describing the request object was that the Request Object provides a similar function for directly associating an error object with a request object. These functions uses request objects and not a list as the basic data object and hence the caller does not have to worry about creating or assigning the list to the request object; this is done automatically. The request version of how to register an error looks very much like its more generic companion, and it should not be necessary to explain the arguments any further.
extern BOOL HTRequest_addError (HTRequest * request, HTSeverity severity, BOOL ignore, int element, void * par, unsigned int length, char * where);System errors can be registered in very much the same way as described above, but the set of parameters is a bit smaller and hopefully a bit easier to handle. The registration function is defined as:
extern BOOL HTError_addSystem (HTList * list, HTSeverity severity, int errornumber, BOOL ignore, char * syscall);The only difference is the
errornumber
argument which, as described above, in many
situations is provided by the operating system, for example as a errno variable. The
syscall
is simply the name of the function. Also this function has a mirror function in
the HTRequest object, and again they look very much
alike:
extern BOOL HTRequest_addSystemError (HTRequest * request, HTSeverity severity, int errornumber, BOOL ignore, char * syscall);Let's take a look at two examples of registering errors. The first example registers an informational error message explaining that the HTTP module received a redirection notification from the remote HTTP server. The first example uses the Request versions of the error registration functions, and the second example uses the generic versions:
BOOL HTTPRedirect (HTRequest * request, int status, char * location) { if (location) { if (status == 301) { HTRequest_addError(request, ERR_INFO, NO, HTERR_MOVED, location, strlen(location), "HTTPRedirect"); } else if (status == 302) { HTRequest_addError(request, ERR_INFO, NO, HTERR_FOUND, location, strlen(location), "HTTPRedirect"); } return YES; } else { HTRequest_addError(request, ERR_FATAL, NO, HTERR_BAD_REPLY, NULL, 0, "HTTPRedirect"); return NO; } }The second example shows how to register a system error:
BOOL HTReadDir (HTRequest * request, const * directory) { DIR *dp; if ((dp = opendir(directory))) { STRUCT_DIRENT * dirbuf; while ((dirbuf = readdir(dp))) { /* Read Directory */ } closedir(dp); return YES; } else { HTError_addSystem(errorlist, ERR_FATAL, errno, NO, "opendir"); return NO; } }
typedef enum _HTErrorShow { HT_ERR_SHOW_FATAL, /* Show only fatal errors */ HT_ERR_SHOW_NON_FATAL, /* Show non fatal and fatal errors */ HT_ERR_SHOW_WARNING, /* Show warnings, non fatal, and fatal errors */ HT_ERR_SHOW_INFO, /* Show all of errors */ HT_ERR_SHOW_PARS, /* Show any parameters (if any) */ HT_ERR_SHOW_LOCATION, /* Show the location where the error occured */ HT_ERR_SHOW_IGNORE, /* Show errors even if they are ignored */ HT_ERR_SHOW_FIRST, /* Show only the first registered error */ HT_ERR_SHOW_LINKS /* Show any HTML links (if any) */ HT_ERR_SHOW_DEFAULT, /* Default level of details * HT_ERR_SHOW_DETAILED, /* Somewhat detailed level */ HT_ERR_SHOW_DEBUG, /* Very detailed */ } HTErrorShow;The last three entries in the enumeration list are only for the convenience of the application. They provide some useful default values for how error messages can be presented to the user. The setup can be modified using the following functions:
extern HTErrorShow HTError_show (void); extern BOOL HTError_setShow (HTErrorShow mask);The actual generation of error messages often involves a platform dependent interface including special windows etc. In order to keep the error manager itself completely platform independent, the error presentation functionality is part of the Messaging Module which is described in detail later in this guide.
extern BOOL HTError_doShow (HTError * info); extern BOOL HTError_ignoreLast (HTList * list); extern BOOL HTError_setIgnore (HTError * info); extern int HTError_index (HTError * info); extern HTSeverity HTError_severity (HTError * info); extern int HTError_parameter (HTError * info, void *parameter); extern const char * HTError_location (HTError * info);
HTError_add
and
HTError_addSystem
), the cleanup is done exactly like for all other list based
registration mechanisms in the Library. In case you are using the request specific version, the
request manager both handles creating and deletion of error lists, so you do not have to do
anything. The generic interface for cleaning up looks like:
extern BOOL HTError_deleteAll (HTList * list); extern BOOL HTError_deleteLast (HTList * list);In the next section, we will see how to display errors in the application along with other user information such as progress reports etc.