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 9 - Perl API Reference Guide / The Apache Request Object
Server Response Methods

This section covers the API methods used to build and query the outgoing server response message. These methods allow you to set the type and length of the outgoing document, set HTTP cookies, assign the document a language or compression method, and set up authorization and authentication schemes.

Most of the methods in this section are concerned with setting the values of the outgoing HTTP response header fields. We give a list of all of the fields you are likely to use in Table 9-2. For a comprehensive list, see the HTTP/1.0 and HTTP/1.1 specifications found at http://www.w3.org/Protocols.

Table 9-2. Response Header Fields

Field
Description
Allowed
The methods allowed by this URI, such as POST
Content-encoding
The compression method of this data
Content-language
The language in which this document is written
Content-length
Length, in bytes, of data to follow
Content-type
MIME type of this data
Date
The current date in GMT (Greenwich Mean Time)
Expires
The date the document expires
Last-modified
The date the document was last modified
Link
The URL of this document's "parent," if any
Location
The location of the document in redirection responses
ETag
The opaque ID for this version of the document
Message-id
The ID of this document, if any
MIME-version
The version of MIME used (currently 1.0)
Pragma
Hints to the browser, such as "no-cache"
Public
The requests that this URL responds to (rarely used)
Server
The name and version of the server software
Set-cookie
The client-side cookie to give to a browser
WWW-authenticate
Used in the various authorization schemes
Vary
Criteria that can be used to select this document

bytes_sent()

This method will retrieve the number of bytes of information sent by the server to the client, excluding the length of the HTTP headers. It is only useful after the send_http_ header() method (described later) has been called. This method is normally used by log handlers to record and summarize network usage. See Chapter 7 for examples.

my $bytes_sent = $r->bytes_sent;

cgi_header_out()

This method is similar to the header_out() function. Given a key/value pair, it sets the corresponding outgoing HTTP response header field to the indicated value, replacing whatever was there before. However, unlike header_out(), which blindly sets the field to whatever you tell it, cgi_header_out() recognizes certain special keys and takes the appropriate action. This is used to emulate the magic fields recognized by Apache's own mod_ cgi CGI-handling routines.

Table 9-3 lists the headers that trigger special actions by cgi_header_out().

Table 9-3. Special Actions Triggered by cgi_header_out()

Header
Actions
Content-type
Sets $r->content_type to the given value
Status
Sets $r->status to the integer value in the string
Sets $r->status_line to the given value
Location
Sets Location in the headers_out table to the given value and performs an internal redirect if URI is relative
Content-length
Sets Content-length in the headers_out table to the given value
Transfer-encoding
Sets Transfer-encoding in the headers_out table to the given value
Last-modified
Parses the string date, feeding the time value to ap_update_mtime() and invoking ap_set_last_modified()
Set-cookie
Calls ap_table_add() to support multiple Set-cookie headers
Other
Calls ap_table_merge() with given key and value

You generally can use the Apache::Table or header_out() methods to achieve the results you want. cgi_header_out() is provided for those who wish to create a CGI emulation layer, such as Apache::Registry. Those who are designing such a system should also look at send_cgi_header(), described in "Sending Data to the Client" later in this chapter.

content_encoding()

This method gets or sets the document encoding. Content encoding fields are strings like gzip or compress, and indicate that the document has been compressed or otherwise encoded. Browsers that handle the particular encoding scheme can decode or decompress the document on the fly.

Getting or setting content_encoding() is equivalent to using headers_out() or header_out() to change the value of the Content-encoding header. Chapters 4 and 7 give examples of querying and manipulating the content encoding field.

my $enc = $r->content_encoding;
if($r->filename =~ /\.gz$/) {
  $r->content_encoding("gzip");
}

content_languages()

The content_languages() method gets or sets the Content-language HTTP header field. Called without arguments, it returns an array reference consisting of two-letter language identifiers, for example, "en" for English and "no" for Norwegian. You can also pass it an array reference to set the list of languages to a new value. This method can be used to implement support for multilanguage documents. See the Apache::MIME module in Chapter 7 for an example.

content_languages() is a convenient interface to the lower-level header_out() and headers_out() methods.

my $languages = $r->content_languages;
$r->content_languages(['en']);

content_type()

This method corresponds to the Content-type header field, which tells the browser the MIME type of the returned document. Common MIME types include text/plain, text/ html, and image/gif. content_type() can be used either to get or set the current value of this field. It is important to use content_type() to set the content type rather than calling headers_out() or header_out() to change the outgoing HTTP header directly. This is because a copy of the content type is kept in the request record, and other modules and core protocol components will consult this value rather than the outgoing headers table.

my $ct = $r->content_type;
$r->content_type('text/plain');

custom_response()

When a handler returns a code other than OK, DECLINED, or DONE, Apache aborts processing and throws an error. When an error is thrown, application programs can catch it and replace Apache's default processing with their own custom error handling routines by using the ErrorDocument configuration directive. The arguments to ErrorDocument are the status code to catch and a custom string, static document, or CGI script to invoke when the error occurs.

The module-level interface to Apache's error handling system is custom_response(). Like the directive, the method call takes two arguments. The first argument is a valid response code from Table 3.1. The second is either a string to return in response to the error, or a URI to invoke to handle the request. This URI can be a static document, a CGI script, or even a content handler in an Apache module. Chapters 4 and 6 have more extensive coverage of the error handling system.

use Apache::Constants qw(:common);
$r->custom_response(AUTH_REQUIRED, "sorry, I don't know you.");
$r->custom_response(SERVER_ERROR, "/perl/server_error_handler.pl");

err_headers_out()

Apache actually keeps two sets of outgoing response headers: one set to use when the transaction is successful and another to use in the case of a module returning an error code. Although maintaining a dual set of headers may seem redundant, it makes custom error handlers much easier to write, as we saw in Chapter 4. err_headers_out() is equivalent to headers_out(), but it gets and sets values in the table of HTTP header response fields that are sent in the case of an error.

Unlike ordinary header fields, error fields are sent to the browser even when the module aborts or returns an error status code. This allows modules to do such things as set cookies when errors occur or implement custom authorization schemes. Error fields also persist across internal redirects when one content handler passes the buck to another. This feature is necessary to support the ErrorDocument mechanism.

my %err_headers_out = $r->err_headers_out;
my $err_headers_out = $r->err_headers_out;
$r->err_headers_out->{'X-Odor'} = "Something's rotten in Denmark";

err_header_out()

Like the header_in() and header_out() methods, err_header_out() predates the Apache::Table class. It can be used to get or set a single field in the error headers table. As with the other header methods, the key lookups are done in a case-insensitive manner. Its syntax is identical to header_out():

my $loc = $r->err_header_out('Location');
$r->err_header_out(Location => 'http://www.modperl.com/');
$r->err_header_out(Location => undef);

headers_out()

headers_out() provides modules with the ability to get or set any of the outgoing HTTP response header fields. When called in a list context, headers_out() returns a list of key/ value pairs corresponding to the current server response headers. The capitalization of the field names is not canonicalized prior to copying them into the list.

When called in a scalar context, this method returns a hash reference tied to the Apache::Table class. This class provides an interface to the underlying headers_out data structure. Fetching a key from the tied hash will retrieve the corresponding HTTP field in a case-insensitive fashion, and assigning to the hash will change the value of the header so that it is seen by other handlers further down the line, ultimately affecting the header that is sent to the browser.

The headers that are set with headers_out() are cleared when an error occurs, and do not persist across internal redirects. To create headers that persist across errors and internal redirects, use err_headers_out(), described earlier.

my %headers_out = $r->headers_out;
my $headers_out = $r->headers_out;
$headers_out->{Set-cookie} = 'SESSION_ID=3918823';

The Content-type, Content-encoding, and Content-language response fields have special meaning to the Apache server and its modules. These fields occupy their own slots of the request record itself and should always be accessed using their dedicated methods rather than the generic headers_out() method. If you forget and use headers_out() instead, Apache and other modules may not recognize your changes, leading to confusing results. In addition, the Pragma: no-cache idiom, used to tell browsers not to cache the document, should be set indirectly using the no_cache() method.

The many features of the Apache::Table class are described in more detail in its own section.

header_out()

Before the Apache::Table class was written, header_out() was used to get or set the value of an individual HTTP field. Like the header_in() method, header_out() predates the Apache::Table class but remains for backwards compatibility and as a bit of a shortcut to using the headers_in method.

If passed a single argument, header_out() returns the value of the corresponding field from the outgoing HTTP response header. If passed a key/value pair, header_out() stably changes the value of the corresponding header field. A field can be removed entirely by passing undef as its value. The key lookups are done in a case-insensitive manner.

my $loc = $r->header_out('Location');
$r->header_out(Location => 'http://www.modperl.com/');
$r->header_out(Location => undef);

handler()

The handler method gets or sets the name of the module that is responsible for the content generation phase of the current request. For example, for requests to run CGI scripts, this will be the value cgi-script. Ordinarily this value is set in the configuration file using the SetHandler or AddHandler directives. However, your handlers can set this value during earlier phases of the transaction, typically the MIME type checking or fixup phases.

Chapter 7 gives examples of how to use handler() to create a handler that dispatches to other modules based on the document's type.

my $handler = $r->handler;
if($handler eq "cgi-script") {
  warn "shame on you.  Fixing.\n"
  $r->handler('perl-script');
}

handler() cannot be used to set handlers for anything but the response phase. Use set_handlers() or push_handlers() to change the handlers for other phases (see "mod_perl-Specific Methods" later in this chapter).

no_cache()

The no_cache() method gets or sets a boolean flag that indicates that the data being returned is volatile. Browsers that respect this flag will avoid writing the document out to the client-side cache. Setting this flag to true will cause Apache to emit an Expires field with the same date and time as the original request.

$current_flag = $r->no_cache();
$r->no_cache(1);   # set no-cache to true

request_time()

This method returns the time at which the request started, expressed as a Unix timestamp in seconds since the start of an arbitrary period called the "epoch."2 You can pass this to Perl's localtime() function to get a human-readable string or to any of the available time- and date-handling Perl modules to manipulate it in various ways. Unlike most of the other methods, this one is read-only.

my $date = scalar localtime $r->request_time;
warn "request started at $date";

status()

The status() method allows you to get or set the status code of the outgoing HTTP response. Usually you will set this value indirectly by returning the status code as the handler's function result. However, there are rare instances when you want to trick Apache into thinking that the module returned an OK status code but actually send the browser a non-OK status.

Call the method with no arguments to retrieve the current status code. Call it with a numeric value to set the status. Constants for all the standard status codes can be found in Apache::Constants.

use Apache::Constants qw(:common);
my $rc = $r->status;
$r->status(SERVER_ERROR);

status_line()

status_line() is used to get or set the error code and the human-readable status message that gets sent to the browser. Ordinarily you should use status() to set the numeric code and let Apache worry about translating this into a human readable string. However, if you want to generate an unusual response line, you can use this method to set the line. To be successful, the response line must begin with one of the valid HTTP status codes.

my $status_line = $r->status_line;
$r->status_line("200 Bottles of Beer on the Wall");

If you update the status line, you probably want to update status() accordingly as well.

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