Home > Articles > Web Development > Perl

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

This chapter is from the book

Using Subrequests

You want to find out the result of a request to an internal resource, such as the resulting filename or MIME type.

Technique

Use lookup_uri() or lookup_file() methods from the Apache class to create an Apache::SubRequest object, then check the result of the subrequest using an appropriate method.

my $sub = $r->lookup_uri("/fleet/trireme.html");

# Find the absolute path to the resource.
my $filename = $sub->filename;

Comments

Because both Apache and mod_perl allow you to be creative in how URIs actually map to files (or avoid physical files all together), the ability to simulate server behavior for a given URI can be a powerful tool. For instance, it may seem obvious that trireme.html in the preceding example is an HTML file, but names can be deceiving, especially if the following RewriteRule is in place:

RewriteRule ^/fleet/(.*)\.html /images/$1.gif [PT]

Of course, most of the time the URI will not be a hard-coded filename within the code but instead be determined dynamically at request time, making any conjecture on the programmer's part pointless. For this reason, mod_perl provides the lookup_uri() method, along with the similar but less often used lookup_file(), which allows you to run parts of the request cycle on either a URI or an absolute filename and test the results of the request against various criteria.

lookup_uri() and lookup_file() actually initiate what is known as a subrequest. A subrequest is an Apache request that is not directly associated with a request from a client browser. Subrequests can be initiated by Apache internally, such as with error responses trapped with an ErrorDocument configuration setting, or generated programmatically using the lookup_uri() and lookup_file() methods. Both lookup_uri() and lookup_file() run a request through part of the Apache request cycle and return an Apache::SubRequest object.

The Apache::SubRequest class is a complete subclass of the Apache class, and therefore the Apache::SubRequest object has access to all of the methods normally associated with the Apache request object. The Apache::SubRequest class also extends the Apache class by adding a single new method, run().

The lookup_uri() and lookup_file() methods function differently only in the respect that lookup_uri() will attempt to map the URI to a physical file using the translation phase of the request cycle, whereas lookup_file() will not. Both methods will then proceed through the access, authentication, and authorization phases, as well as the MIME type checking and fixup phases, but will stop short of actual content generation.

Generating a subrequest within your code allows for some interesting functionality—you can simulate a request and see what results, or you can transfer control from one request to another, eliminating slow client-side redirects in your scripts. In the preceding sample code, we used a subrequest to determine the physical filename of a URI the end-user might request. We could just as easily have used the resulting Apache::SubRequest object to determine the MIME type of the file, or just about any other attribute of the request.

After you have performed any necessary tests on your subrequest, you can optionally run the content generation phase for that resource using Apache::SubRequest's run() method. Here is an example that sends content to the browser only if the subrequest turns out to be a plain file and is accessible.

my $sub = $r->lookup_uri($url);

# Send the file if it exists and the user has permission to see it.
# Unauthorized requests might return AUTH_REQUIRED or FORBIDDEN.
if (-f $sub->finfo && $sub->status == HTTP_OK) {
$r->send_http_header($sub->content_type);
 return $sub->run;
}

# Otherwise, do something else...

The run() method added by the Apache::SubRequest class actually runs the content generation phase for the subrequest, sends the data to the client, and returns the exit status of the content handler, not the content generated by the subrequest. This status can be compared to any of the Apache::Constants HTTP return codes to determine whether the subrequest was successful, such as HTTP_OK or FORBIDDEN.

By default, headers set by subrequests are not allowed to pass through to the client. If you are using a subrequest to send content directly to the browser using run() you are required to send the server response headers yourself from the main request. This default behavior can, however, be altered by passing run() a single true argument, which will toggle whether the subrequest will be responsible for generating and sending its own headers.

# Forget about sending headers yourself,
# let the Apache the subrequest do it.
return $sub->run(1);
  • + Share This
  • 🔖 Save To Your Account