Home > Articles > Web Development > Perl

  • Print
  • + Share This
This chapter is from the book

This chapter is from the book

Setting the Response Status

You want to tell the client the status of the request by indicating a successful response or an error response, such as a redirect or a server error.

Technique

Use constants exported by the Apache::Constants class to communicate the status of the response back to Apache.

package Cookbook::Regex;

use Apache::Constants qw(:common);
use Apache::File;
use Apache::Log;

use strict;

sub handler {
 
 my $r = shift;

 my $log = $r->server->log;

 my @change = $r->dir_config->get('RegexChange');
 my @to   = $r->dir_config->get('RegexTo');
 
 unless ($r->content_type eq 'text/html') {
  $log->info("Request is not for an html document - skipping...");
  return DECLINED; 
 }

 unless (@change && @to) {
  $log->info("Parameters not set - skipping...");
  return DECLINED; 
 }

 if (@change != @to) {
  $log->error("Number of regex terms do not match!");
  return SERVER_ERROR;
 }

 my $fh = Apache::File->new($r->filename);

 unless ($fh) {
  $log->warn("Cannot open request - skipping... $!");
  return DECLINED;
 }

 $r->send_http_header('text/html');

 while (my $output = ) {
  for (my $i=0; $i < @change; $i++) { 
   $output =~ s/$change[$i]/$to[$i]/eeg;
  }
  print $output;
 }

 return OK;
}
1; 

Comments

Built in to the HTTP/1.1 specification is a series of status codes for communicating the status of the request back to the client. Everyone is familiar with error responses like 404 Not Found and 500 Internal Server Error that appear occasionally while surfing the Web. The 200 OK responses that are the norm typically go by unnoticed, masked by the actual content displayed by the browser. In each of these cases, Apache is returning an HTTP status code through the Status-Line of the server response. Through the mod_perl API we have the ability to control the status of the request by returning the appropriate status as the return value from our handler. Thinking of handlers as functions, not procedures, helps— the return code of the handler defines the status of the request. The Apache::Constants module provides the complete set of response codes as symbolic, human-readable names. These codes are based on the standard HTTP response codes, with the addition of some Apache–specific codes.

It is easiest to begin with the HTTP specific codes. Internally, Apache stores the HTTP status of the request in the status slot of the Apache request record. At the start of each request, the status is set to the constant HTTP_OK, which corresponds to a 200 OK HTTP response. As the different Apache modules step into the request, each has the ability to set the response status to something other than HTTP_OK by returning an HTTP return code. For instance, mod_dir returns HTTP_MOVED_PERMANENTLY whenever a URI is received for a directory but does not contain a trailing slash, such as http://www.example.com/sails. Apache then propagates that response back to the end user in the form of a 301 Moved Permanently response, the browser redirects to the target URI http://www.example.com/sails/, and things continue as normal.

The mechanism is the same for your Perl handlers. Sending a response back to the client with a status other than 200 OK only requires that you return the appropriate HTTP status code back from your handler. These status codes are made available to your code through the Apache::Constants class, which allows you to import each constant by name or use a set of import tags. For instance, we used the :common import tag in the preceding sample handler.

Table 3.8 shows a few of the more common HTTP return codes, along with their Apache::Constants names, suitable for importing into your code. A larger list can be found in Appendix B, whereas the authoritative source is section 10 of RFC 2616.

Table 3.8 Some Apache::Constants Server Response Constants

Apache::Constants Constant

HTTP Response Code

AUTH_REQUIRED

401 Unauthorized

FORBIDDEN

403 Forbidden

NOT_FOUND

404 Not Found

REDIRECT

302 Found

SERVER_ERROR

500 Internal Server Error


Aside from these HTTP return codes, Apache maintains three constants that are meant to help facilitate the interaction between Apache and the various request handlers: OK, DECLINED, and DONE. All of these are also available through the Apache::Constants class. The reason for these Apache-specific codes will become clear in Part III, where we examine the Apache request cycle in detail. For the moment, we can just focus on some mechanics and save the details for later.

The most common return code is OK, which indicates success. Remember that Apache has already set the response to 200 OK, so it generally is not appropriate to return HTTP_OK from your handler—OK is the proper value in nearly all cases. DECLINED tells Apache that you have declined to process the request. This does not necessarily mean that you have not altered the request, only that you have chosen not to inform Apache about it. The final Apache-specific return code is DONE, which indicates that all content has been sent to the client and Apache should immediately skip to the logging phase of the request. DONE is rarely used, but is useful in certain circumstances. Recipe 11.6 shows an interesting application of the DONE return code.

For the most part, all of your handlers will return OK or one of the HTTP-specific error codes, such as REDIRECT or SERVER_ERROR. In reality, Apache treats any return code other than OK, DECLINED, or DONE as an error. While this may sound strange, all it really means is that Apache will start its error response cycle, which allows you to capture responses other than HTTP_OK with an ErrorDocument or the custom response mechanism discussed in Recipe 8.6. Reasons to choose DECLINED over OK as a return code are more fully discussed in later chapters, where each phase of the request cycle has its own peculiarities.

As we have mentioned a few times, Apache::Registry is really a mod_perl handler that wraps your Perl CGI code within a handler() subroutine. One of the side effects of the Apache::Registry design, however, is that any return value from Registry scripts is ignored by Apache::Registry::handler(). This means that the model we have described here does not apply, even though Apache::Registry scripts have access to the entire mod_perl API.

The way around this is to set the status of the request directly using the status() method from the Apache class. For instance, a typical idiom for Registry scripts that use the mod_perl API is:

$r->headers_out(Location => "/pirate_map.html");
$r->status(REDIRECT);
return REDIRECT;

The interesting thing to note here is that, in the case of Registry scripts, the return value actually just serves as a way to exit the script gracefully without any further processing—$r->status(REDIRECT) is the actual mechanism that is telling Apache to return 302 Found back to the client. Actually, it is a bit trickier than that. Apache::Registry returns the status you set with $r->status() back to Apache, then sets $r->status() back to HTTP_OK, because handlers typically do not alter $r->status() directly.

For our example and discussion we have only used a few of the constants available through the Apache::Constants class: Apache::Constants contains over 90 different constants used for the many different aspects of mod_perl, from the server-response codes we have discussed so far to constants only useful when dealing with the internal Apache API. Importing all those constants into your script wastes precious memory and is excessive for all but the most demanding Web application. To make life easier, Apache::Constants defines several import tags that group constants of similar purpose together, such as the :common tag used in the example code. Other convenient tags are listed in the Apache::Constants manpage.

Because every constant you import into your code increases your process size (albeit slightly), you can slim down this list by importing only those constants you actually use:

use Apache::Constants qw(OK REDIRECT SERVER_ERROR);

Not only does this keep unneeded symbols out of your process, as discussed in Chapter 9, but it also increases readability of your code. For the most part, our examples will make use of this more explicit syntax.

  • + Share This
  • 🔖 Save To Your Account