O'Reilly logo

Embedding Perl in HTML with Mason by Ken Williams, Dave Rolsky

Stay ahead with the world's most comprehensive technology and business learning platform.

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, tutorials, and more.

Start Free Trial

No credit card required


Mason’s autohandler feature is one of its most powerful tools for managing complex web sites.

Managing duplication is a problem in any application, and web applications are no exception. For instance, if all pages on a given site should use the same (or similar) header and footer content, you immediately face a choice: should you simply duplicate all the common content in each individual page, or should you abstract it out into a central location that each page can reference? Anyone who’s worked on web sites knows that the first approach is foolhardy: as soon as you need to make even a minor change to the common content, you have to do some kind of find-and-replace across your entire site, a tedious and error-prone process.

For this reason, all decent web serving environments provide a way to include external chunks of data into the web pages they serve. A simple example of this is the Server Side Include mechanism in Apache and other web servers. A more sophisticated example is Mason’s own ability to call one component from inside another.

Although an include mechanism like this is absolutely necessary for a manageable web site, it doesn’t solve all the duplication problems you might encounter.

First, the onus of calling the correct shared elements still rests within each individual page. There is no simple way for a site manager to wave a wand over her web site and say, “Take all the pages in this directory and apply this header and this footer.” Instead, she must edit each individual page to add a reference to the proper header and footer, which sounds remarkably like the hassle we were trying to avoid in the first place. Anyone who has had to change the header and footer for one portion of a site without changing other portions of the site knows that include mechanisms aren’t the cat pajamas they’re cracked up to be.

Second, include mechanisms address only content duplication, not any other kind of shared functionality. They don’t let you share access control, content filtering, page initialization, or session management, to name just a few mechanisms that are typically shared across a site or a portion of a site.

To address these problems, Mason borrows a page from object-oriented programming. One of the central goals of object-oriented programming is to allow efficient and flexible sharing of functionality, so that a Rhododendron object can inherit from a Plant object, avoiding the need to reimplement the photosynthesize( ) method. Similarly, each component in Mason may have a parent component, so that several components may have the same parent, thereby sharing their common functionality.

To specify a component’s parent, use the inherit flag:

 inherit => 'mommy.mas'

If a component doesn’t specify a parent explicitly, Mason may assign a default parent. This is (finally) how autohandlers come into the picture:

  • The default parent for any “regular” component (one that isn’t an autohandler — but might be a dhandler) is a component named “autohandler” in the same directory. If no autohandler exists in the same directory, Mason will look for an autohandler one directory up, then one more directory up, and so on, until reaching the top of the component root. If this search doesn’t find an autohandler, then no parent is assigned at all.

  • The default parent for an autohandler is an autohandler in a higher directory. In other words, an autohandler inherits just like any other component, except that it won’t inherit from itself.

Note that these are only the defaults; any component, including an autohandler, may explicitly specify a parent by setting the inherit flag. Be careful when assigning a parent to an autohandler, though: you may end up with a circular inheritance chain if the autohandler’s parent inherits (perhaps by default) from the autohandler.

Just like dhandlers, you can change the component name used for the autohandler mechanism from autohandler to something else, by setting the Mason interpreter’s autohandler_name parameter.

We’ll use the standard object-oriented terminology when talking about the inheritance hierarchy: a component that has a parent is said to be a “child” that “inherits from” its parent (and its parent’s parent, and so on). At runtime, the hierarchy of parent and child components is often referred to in Mason as the “wrapping chain,” for reasons you are about to witness.

Example 3-1 and Example 3-2 show how to use autohandlers for our simple content-sharing scheme, adding common headers and footers to all the pages in a directory.

Example 3-1. /autohandler

% $m->call_next;
<br><a href="/">Home</a>

Example 3-2. /welcome.html

<p>Welcome to a very wonderful site.  We hope you enjoy your stay.</p>

This demonstrates the first property of inheritance, which we call "content wrapping” — any component that inherits from the autohandler in Example 3-1, like /welcome.html in Example 3-2, will automatically be wrapped in the simple header and footer shown. Note that /welcome.html doesn’t need to explicitly insert a header and footer; that happens automatically via the autohandler mechanism.

Let’s trace through the details of the component processing. A request comes to the web server for http://example.com/welcome.html, which Mason translates into a request for the /welcome.html component. The component is found in the component path, so the dhandler mechanism is not invoked. /welcome.html doesn’t explicitly specify a parent, so Mason looks for a component named /autohandler, and it finds one. It then tries to determine a parent for /autohandler — because there are no directories above /autohandler and /autohandler doesn’t explicitly specify a parent, /autohandler remains parentless, and the construction of the inheritance hierarchy is complete.

Mason then begins processing /autohandler, the top component in the parent hierarchy. The first part of the component doesn’t contain any special Mason sections, so it simply gets output as text. Mason then sees the call to $m->call_next, which means that it should go one step down the inheritance hierarchy and start processing its child component, in this case /welcome.html. The /welcome.html component generates some output, which gets inserted into the middle of /autohandler and then finishes. Control passes back to /autohandler, which generates a little more output and then finishes, ending the server response.

Using Autohandlers for Initialization

As we mentioned earlier, the autohandler mechanism can be applied to more than just header and footer generation. For the sake of dividing this material into reasonably sized chunks for learning, we’re leaving the more advanced object-oriented stuff like methods and attributes for Chapter 5. However, several extremely common autohandler techniques are presented here.

First, most interesting sites are going to interact with a database. Generally you’ll want to open the database connection at the beginning of the response and simply make the database handle available globally for the life of the request.[11] The autohandler provides a convenient way to do this (see Example 3-3 and Example 3-4).

Example 3-3. /autohandler

% $m->call_next;
<br><a href="/">Home</a>

 $dbh = DBI->connect('DBI:mysql:mydb;mysql_read_default_file=/home/ken/my.cnf')
   or die "Can't connect to database: $DBI::errstr";

Example 3-4. /view_user.mas


% if (defined $name) {
 <p>Info for user '<% $user %>':</p>
 <b>Name:</b> <% $name %><br>
 <b>Age:</b>  <% $age  %><br>
% } else {
 <p>Sorry, no such user '<% $user %>'.</p>
% }

 my ($name, $age) = $dbh->selectrow_array
   ("SELECT name, age FROM users WHERE user=?", undef, $user);

Note that the $dbh variable was not declared with my( ) in either component, so it should be declared using the Mason allow_globals parameter (or, equivalently, the MasonAllowGlobals directive in an Apache config file). The allow_globals parameter tells the compiler to add use vars statements when compiling components, allowing you to use the global variables you specify. This is the easiest way to share variables among several components in a request, but it should be used sparingly, since having too many global variables can be difficult to manage.

We’ll give a brief trace-through of this example. First, Mason receives a request for http://example.com/view_user.max?user=ken, which it translates to a request for the /view_user.mas component. As before, the autohandler executes first, generating headers and footers, but now also connecting to the database. When the autohandler passes control to /view_user.mas, its <%init> section runs and uses the same $dbh global variable created in the autohandler. A couple of database values get fetched and used in the output, and when control passes back to the autohandler the request is finished.

Since this process is starting to get a little complicated under scrutiny, you may wonder how the user parameter is propagated through the inheritance hierarchy. The answer is that it’s supplied to the autohandler, then passed automatically to /view_user.mas through $m->call_next. In fact, $m->call_next is really just some sugar around the $m->comp method, automatically selecting the correct component (the child) and passing the autohandler’s arguments through to the child. If you like, you can supply additional arguments to the child by passing them as arguments to $m->call_next.

Using Autohandlers as Filters

Example 3-5 is another common use of autohandlers. Often the content of each page will need to be modified in some systematic way, for example, transforming relative URLs in <img src> tags into absolute URLs.

Example 3-5. /autohandler

% $m->call_next;

 # Images are on images.mysite.com
 (my $host = $r->hostname) =~ s/^.*?(\w+\.\w+)$/images.$1/;
 # Remove final filename from path to get directory
 (my $path = $r->uri)      =~ s,/[^/]+$,,;

 # Matches site-relative paths
 s{(<img[^>]+src=\")/}        {$1http://$host/}ig;
 # Matches directory-relative paths
 s{(<img[^>]+src=\")(?!\w+:)} {$1http://$host$path/}ig;

This particular autohandler doesn’t add a header and footer to the page, but there’s no reason it couldn’t. Any additional content in the autohandler would function just as in our previous example and also get filtered just like the content from call_next( ).

We make two substitution passes through the page. The first pass transforms URLs like <img src="/img/picture.gif"> into <img src="http://images.mysite.com/img/picture.gif">. The second pass transforms URLs like <img src="picture.gif"> into <img src="http://images.mysite.com/current_dir/picture.gif">.

Filter sections like this can be very handy for changing image paths, altering navigation bars to match the state of the current page, or making other simple transformations. It’s not a great idea to use filters for very sophisticated processing, though, because parsing HTML can give you a stomach ache very quickly. In Chapter 5 you’ll see how to use inheritance to gain finer control over the production of the HTML in the first place, so that often no filtering is necessary.

Inspecting the Wrapping Chain

When Mason processes a request, it builds the wrapping chain and then executes each component in the chain, starting with the topmost parent component and working its way toward the bottommost child. Inside one of these components you may find it necessary to access individual components from the chain, and several Mason methods exist for this purpose.

For orientation purposes, let’s define a little more terminology. The term " requested component” refers to the component originally requested by a URL or to a dhandler if that component doesn’t exist. The term " current component” refers to the component currently executing at any given time. The term “base component” refers to the bottommost child of the current component. The base component starts out as the requested component, but as components call one another during a request, the base component will take on several different values. Note that the requested component is determined only once per request, but the current component and the base component will typically change several times as the request is handled

An example scenario is illustrated in Figure 3-1. If /subdir/first.html is called as the requested component, its parent will be /subdir/autohandler and its grandparent will be /autohandler. These three components make up the initial inheritance chain, and while /subdir/first.html is executing, it will be designated as the base component. Its content gets wrapped by its parents’ content, so the component execution starts with /autohandler, which calls /subdir/autohandler via $m->call_next, which in turn calls /subdir/first.html by the same mechanism. While any of these components is executing, it temporarily becomes the current component, though the base component stays fixed as /subdir/first.html.

The wrapping chain

Figure 3-1. The wrapping chain

If /subdir/first.html calls <& called.mas &> during the request, /subdir/called.mas temporarily becomes both the current component and the base component. Note that its parents do not go through the content wrapping phase again; this happens only for the requested component. When /subdir/called.mas finishes, control passes back to /subdir/first.html, which becomes the base component and current component again. It remains the base component for the duration of the request as its parents become the current components so they can finish their content wrapping.

To access the base component, current component, or requested component in your code, you can use the $m->base_comp, $m->current_comp, or $m->request_comp request methods. Each of these methods returns an object representing the component itself. These objects inherit from the HTML::Mason::Component class, and they can be used in several ways.

First, a component object can be used as the first argument of $m->comp( ) or <& &> in place of the component name. Second, you can access a component’s parent by calling its parent( ) method, which returns another component object. Third, you can access methods or attributes that a component or its parents define in <%method> or <%attr> blocks. Finally, the HTML::Mason::Component class and its subclasses define several methods that let you query properties of the component itself, such as its creation time, what arguments it declares in its <%args> section, where its compiled form is cached on disk, and so on. See Chapter 4 for more information on the HTML::Mason::Component family of classes.

[11] This strategy can be used in conjunction with the Apache::DBI module, which allows for database connections that persist over many requests.

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, interactive tutorials, and more.

Start Free Trial

No credit card required