Open Source

Simplify CGI with HTML::Mason

Mason, a server-side development environment for Apache and mod_perl, is written in Perl and targeted toward Perl developers building HTML templates. We'll walk you through getting Mason set up.


By James Scheinblum

Managing one or two custom CGI scripts is usually not a problem, but as that number grows, you face a management headache. Keeping the scripts' design consistent across the site may become taxing. And if you code HTML output into your scripts, every site change requires you to update all affected scripts. You may also encounter errors more frequently as your scripts become more complex.

HTML::Mason (Mason for short) solves this sort of problem. Mason, a server-side development environment for Apache and mod_perl, is written in Perl and targeted toward Perl developers. Mason lets you break your site down into small components for faster development time, easier site modification, and more-organized code. The only catch is that you have to play by Mason's rules and rewrite your existing scripts under the Mason environment. It isn't for the novice Webmaster; you should have at least a working knowledge of Perl and a good understanding of Apache. But, as you'll see, Mason's features can be worth the time you invest in getting started. In this column, we'll look at the basics of this powerful development environment.

Install and configure Mason
Mason can run without Apache and mod_perl, but much of its power and flexibility depend on this server environment, so we will assume that you already have Apache installed with mod_perl. Swing by Mason headquarters to pick up the newest release of the software, read the complete documentation, and see how others are using Mason. If you don't already have them, you should also visit a Perl archive such as CPAN to get the two packages required by Mason: MLDBM and Data::Dumper.

Mason installs like any other Perl package. Run perl Makefile.PL and if everything goes correctly, run make and make install. This sequence should put the Mason package in the Perl search path.

Once the libraries are in place, you must install an Apache handler. Mason ships with a sample file, called handler.pl, in the eg directory. You can copy this file into your Apache configuration directory, and you will need to make two edits. First, Mason's speed comes partly from caching, so it requires a data directory. This directory should be outside of Apache's Web root but readable and writable by the Apache user. In handler.pl, replace <data directory> with your data directory path. Mason also has a component directory where you'll do all of your development. It too can be outside of your Apache Web root and needs read permission only for Apache. Replace <component root> with your component directory path.

Next, we have to make Apache and Mason talk to each other. You'll need to decide which files Apache should hand off to Mason. Mason works by reading and parsing template files, but you probably don't want it to process images and other binary files, and you may want to keep some text content (such as PHP scripts or server-side includes) unparsed. So your best course, at least at first, is to create a virtual path in Apache for Mason requests. For simplicity, we'll call it /mason in our examples.

Add these lines to your Apache configuration:
PerlRequire /path/to/handler.pl
 
Alias /mason /path/to/masoncomponents
<Location /mason>
   SetHandler perl-script
   PerlHandler HTML::Mason
</Location>

The first line instructs mod_perl to load Mason's handler.pl script. The next tells Apache to map requests from our Mason component root to the virtual path /mason. This path must be the same as the one that we set in handler.pl. Lastly, we tell mod_perl and Apache to map requests from the /mason directory to the HTML::Mason package.

Now that we have everything set up, it's time to start Apache and create Mason components.

A basic Mason component
Mason lets you create components easily; they are just text files in the component directory. Let's start by looking at a simple example, a Hello World component, which we'll save as HelloWorld.html in the Mason component root.
<HTML>
   <HEAD>
   <TITLE>My <% $component_count %> Mason Component</TITLE>
   </HEAD>
   <BODY bgcolor="#FFFFFF">
   Hello World<BR>
   This is my <B><% $component_count %></B> Mason component.
   </BODY>
</HTML>
<%init>
   my $component_count = "first";
</%init>
<%args>
</%args>

An HTTP request for http://masonserver/mason/Helloworld.html causes Mason to render the component into HTML:
<HTML>
   <HEAD>
   <TITLE>My first Mason Component</TITLE>
   </HEAD>
   <BODY bgcolor="#FFFFFF">
   Hello World<BR>
   This is my <B>first</B> Mason component.
   </BODY>
</HTML>

This example demonstrates two important concepts. First, Mason parses the component file for specific tags. Everything outside of those tags goes straight to the client. Second, Mason components have <%args> and <%init> sections that are separate from the HTML source. In this case, we used only the <%init> section to initialize a Perl variable, but this is where you place any code that needs to run before parsing the HTML body. The <%args> section is used to pass variables between components.

In the <%init> section of HelloWorld.html, we initialize the Perl scalar variable $component_count and later insert it into the HTML source with the string <% $component_count %>. Mason evaluates any Perl string between the <% and %> tags, in this case returning the scalar value. But any expression that returns a string is valid here.

Combined components
The HelloWorld.html example shows how a single Mason component can produce a complete HTML document, but suppose your site has a common header and footer that every document uses? In that case, we can create standard components for both of them and pass the document title as a variable so that the header component can show a title from the component that calls it.

Here is the header component, saved in the component root as Header:
<HTML>
   <HEAD>
   <TITLE><% $document_title %></TITLE>
   </HEAD>
   <BODY BGCOLOR="#FFFFFF">
   <!— This generated from the header component —>
<%init>
</%init>
<%args>
   $document_title=>"This is the default document title"
</%args

This is the footer component, saved as Footer:
   <!— This generated from the footer component —>
   </BODY>
</HTML

And finally, here is a component for an HTML document that uses both the Header and Footer components:
<& Header,document_title=>"My sample component" &>
      This is a sample document<br>
<& Footer &>
<%init>
</%init>
<%args>
</%args

Requesting this component generates the following output:
<HTML>
   <HEAD>
      <TITLE>My sample component</TITLE>
   </HEAD>
   <BODY BGCOLOR="#FFFFFF">
   <!— This generated from the header component —>
      This is a sample document<br>
   <!— This generated from the footer component —>
   </BODY>
</HTML

In Header we use the <%args> section to initialize the $document_title scalar, with a default value to use if the calling component doesn't provide one. Arguments must be explicitly defined in <%args>, and any value without a default value should be mapped to undef.

Our sample component calls Header within the <& and &> tags. Component names are relative to the component root, so we could call <& /Header &> with the same result. To keep your site organized, you can place components in subdirectories. In this case, we might put Header and Footer in a directory named Elements, then call the components with <& /Elements/Header &> and <& /Elements/Footer &>.

When we call the Header component, we pass the argument document_title. This way, arguments come from other components. They can also come from the Web server itself.

Dynamic CGI components
You can create interactive Mason components that receive arguments from the client. Mason will map the CGI arguments from a GET or POST request into the variables declared in the <%args> section. This next example is a simple CGI component that accepts form values, then outputs them.
<& Header,document_title=>"This is a form component" &>
% if (!($name) && !($email)) {
   Enter your info:<br><br>
   <FORM action="/mason/Form.html" method="GET">
      Name: <INPUT type="text" size="10" name="name"><br>
      Email: <INPUT type="text" size="10" name="email"><br>
      <INPUT type="submit">
   </FORM>
% } else {
   This is what you entered:<br>
 
   Name: <% $name %><br>
   Email: <% $email %><br>
% }
<& Footer &>
<%init>
</%init>
<%args>
   $name=>undef
   $email=>undef
</%args>

If the component has no values for $name or $email, it outputs a form with name and email inputs and the component's own URL as the action path. When the form is submitted, Mason maps the form values to $name and $email, so the component prints them instead. Passing CGI arguments this way is functionally the same as calling from another component. In this example, the URL http://masonserver/mason/Form.html?name=First%20Name&email=Email%20Address

would produce the same output as the component call
<& /Form.html,name=>"First Name",email=>"Email Address" &>

Note that Mason interprets any line beginning with the character % as Perl code. This is how you create conditional and iterative blocks such as the if...else conditional shown here.

We've shown how simple Mason components can help keep your site organized and manageable. But this is only the beginning. In the next column, we'll look at some more powerful features that really set Mason apart. Built-in caching speeds up your request handling, and directory handlers let you completely separate content from code. Finally, we'll look at some advanced site designs that show how Mason can enhance your Web site.

Editor's Picks