home | O'Reilly's CD bookshelfs | FreeBSD | Linux | Cisco | Cisco Exam    

Writing Apache Modules with Perl and C
By:   Lincoln Stein and Doug MacEachern
Published:   O'Reilly & Associates, Inc.  - March 1999

Copyright © 1999 by O'Reilly & Associates, Inc.


   Show Contents   Previous Page   Next Page

Chapter 10 - C API Reference Guide, Part I
Server Core Routines

In this section...

The Subrequest API and Internal Redirects
The Cleanup API
Custom Response Handlers
Error Logging
The Piped Log API
Authorization and Authentication Routines


   Show Contents   Go to Top   Previous Page   Next Page

We now turn to less frequently used calls that are part of the Apache C-language API. These calls allow you to create custom error handlers, to create and manipulate subrequests, and to write formatted error messages to the log file.

The Subrequest API and Internal Redirects

   Show Contents   Go to Top   Previous Page   Next Page

The subrequest API can be used to ask Apache "what if" questions. A subrequest acts just like an ordinary request, except that the response phase is never actually run. The earlier phases, including the URI translation handler and the MIME type checker, are run as usual, and you can use their output to do such things as translating URIs into filenames.

A special case of a subrequest is an internal redirect, in which the current content handler discontinues processing the currently requested URI and tells Apache to return a different local URI instead. The content handler that eventually gets run is not necessarily the same as the one that invoked the internal redirect, although you can arrange for this to happen with ap_internal_redirect_handler().

These routines are declared in the header file http_request.h.

int ap_is_initial_req (request_rec *r)

This function returns a true value if the current request is the initial one. It will return false for handlers invoked as the result of subrequests or internal redirects.

if(!ap_is_initial_req(r)) {
   return DECLINED;

The Perl API provides a method called is_main() which returns true for initial requests and for requests triggered by internal redirects but not for subrequests. Although there is no direct equivalent in the C API, you can get the same information by examining the main field of the request record. If it is NULL, then the current request is the main one.

if (r->main != NULL) {
   return DECLINED; /* don't handle subrequests */

You might wish to declare a macro like the following:

#define is_main(r) (r->main == NULL)

The Perl API also defines a method called last() which returns the last request in a subrequest chain. This can be useful in logging handlers for recovering the status code of the last subrequest. A corresponding call is not defined in the C API but can be easily reproduced by the following function:

static request_rec *last(request_rec *r)
  request_rec *last;
  for(last=r; last->next != NULL; last=last->next) {
  return last;

request_rec *ap_sub_req_lookup_uri (const char *uri, const request_rec *r)

The ap_sub_req_lookup_uri() function creates a subrequest from the given URI, returning the resulting request record as the function result. You can then examine the request record to retrieve the URI's filename, MIME type, or other information. The following example shows how you can use a subrequest to translate a URI into a physical pathname:

request_rec *subr = ap_sub_req_lookup_uri(uri, r);
char *filename = subr->filename;

request_rec *ap_sub_req_lookup_file (const char *file, const request_rec *r)

This call behaves similarly to ap_sub_req_lookup_uri(), except that the first argument is a filename rather than a URI and that Apache skips the URI translation phase while processing the subrequest. This example uses a subrequest to fetch the MIME type of the file given in filename:

request_rec *subr = ap_sub_req_lookup_file(filename, r);
char *mime_type   = subr->content_type;

It isn't necessary that the specified file actually exist in order to get useful information with ap_sub_req_lookup_file(). For example, the default MIME type lookup operation depends only on the filename suffix, not on the contents of the file.

void ap_destroy_sub_req (request_rec *r)

When you are through with a subrequest, you should release the memory occupied by its data structures by passing the subrequest record to ap_destroy_sub_req(). If you forget to do this, the subrequest will be deallocated anyway when the main transaction is complete.


int ap_run_sub_req (request_rec *r)

If you have already created a subrequest using ap_sub_req_lookup_uri() or ap_sub_req_ lookup_file(), you can run its content handler by calling ap_run_sub_req(). This is sometimes used by modules that implement server-side include systems in order to incorporate a CGI script's output into the HTML page. The function will return the status code of the subrequest's content handler.

Here's the definition of a utility function called include_virtual(), which creates a subrequest, runs it, then destroys it:

static int include_virtual(request_rec *r, char *uri)
   int status = OK;
   request_rec *subr = ap_sub_req_lookup_uri(uri, r);
   status = ap_run_sub_req(subr);
   return status;

And here's how include_virtual() might be used:

int status = include_virtual("/footers/standard_footer.html", r);

void ap_internal_redirect (const char *new_uri, request_rec *r)

The ap_internal_redirect() method will cause Apache to create a new request from the indicated URI and then run it. The effect is for Apache to send the client a different URI than the one originally requested. Unlike a formal redirect (in which Apache sends the browser a 301 or 302 redirect status code), the browser is not informed that this substitution has taken place.

The content handler for the new URI is not necessarily the same as the content handler that generated the redirect. Apache will determine which content handler to run by examining the new URI's MIME type and applicable configuration directives, just as if the browser had requested the URI directly.

ap_internal_redirect("/new/place", r);

After recalling this function, your handler should return without further processing the request.

void ap_internal_redirect_handler (const char *new_uri, request_rec *r)

If you wish to redirect to a new URI but continue to use the current content handler, call ap_internal_redirect_handler() instead of the previous function.

ap_internal_redirect_handler("/new/place", r);

The Cleanup API

   Show Contents   Go to Top   Previous Page   Next Page

As explained in Chapter 3, cleanup handlers are code subroutines that Apache invokes after the transaction is finished. These are usually used by modules to clean up data structures that could not be allocated from resource pools, such as device drivers and database handles, but can also be used for other tasks, such as deferring logging until after the transaction is completed (see Chapter 7 for a discussion of this technique).

Cleanup handlers use a different calling convention than that used by phase handlers. A cleanup handler takes a single void* argument and returns no function result. Its function prototype looks like this:

void cleanup_handler (void *data)

The data argument is provided for your convenience as a way to pass runtime information to the cleanup handler. It can be a pointer to any data structure of your choosing, or NULL if you don't care to pass any information. As we discuss later, the data argument is specified when you install the cleanup handler using ap_register_cleanup().

One common trick is to pass a pointer to the current request record so that the cleanup handler has access to information about the transaction. In the examples that follow, we use a cleanup handler that simply prints a message to standard error indicating that it's been called:

static void my_cleanup(void *data)
   request_rec *r = (request_rec *)data;
   fprintf(stderr, "process %d all done with %s\n", (int)getpid(), r->uri);

Apache can accommodate an unlimited number of cleanup handlers, although few modules will need more than one. All cleanup functions are declared in the header file alloc.h.

void ap_register_cleanup (pool *p, void *data, void (*plain_cleanup) (void *),
void (*child_cleanup) (void *))

To install a cleanup handler, call ap_register_cleanup(). It takes four arguments: a pool pointer (usually the one stored in the request record), a block of module-specific data to pass to the routine, and two function pointers to cleanup handlers. The first function pointer is the one you will usually use. It points to the cleanup handler to be called when the transaction is terminated. The second function pointer is only used when your module forks a child process and you need a routine to perform cleanup before the child terminates, for example, closing an open file inherited from the parent process. Since it is highly unusual for a module to fork, you will ordinarily pass the "do nothing" routine ap_null_cleanup for this argument. Always be sure to use ap_null_cleanup rather than NULL.

In the following example, we install my_cleanup() as the cleanup handler and arrange for it to be passed a copy of the current request record when it runs:

ap_register_cleanup(r->pool, (void *)r, my_cleanup, ap_null_cleanup);

void ap_kill_cleanup (pool *p, void *data, void (*cleanup)(void *))

Should you need to unregister a cleanup function before it runs, pass the address of the routine and its data block to ap_kill_cleanup(). Both the routine and the data block must match the values passed to ap_register_cleanup() in order for the removal to take effect.

ap_kill_cleanup(r->pool, (void *)r, my_cleanup);

void ap_run_cleanup (pool *p, void *data, void (*cleanup)(void *))

If you need to run a cleanup immediately, you can do so by calling this routine. The cleanup will be unregistered after it is run so that it is not run again during the ordinary cleanup period. It is unlikely that you will need to use this function, since it is easy enough to invoke the cleanup function directly.

   Show Contents   Go to Top   Previous Page   Next Page
Copyright © 1999 by O'Reilly & Associates, Inc.