NAME

HTML::Mason FAQ - frequently asked questions about HTML::Mason

DESCRIPTION

HTML::Mason is a perl-based web site development and delivery engine. This document is designed to answer questions that arise when using HTML::Mason to develop new and convert existing applications.

QUESTIONS & ANSWERS

What is HTML::Mason?

HTML::Mason is a Perl-based web site development and delivery engine. In addition to supporting embedded Perl in HTML pages, HTML::Mason provides facilities for many common web development issues: templating, caching, debugging, profiling, page previewing, and more. Although it can be used with CGI or even stand-alone, HTML::Mason works best in conjunction with Apache and mod_perl.

Does HTML::Mason have an official web site?

Yes, at http://www.masonhq.com.

Where do I obtain HTML::Mason?

HTML::Mason is available from CPAN (the Comprehensive Perl Archive Network). Details about CPAN are available at http://www.perl.com/.

What else do I need to use HTML::Mason?

If you are planning on using HTML::Mason in a web environment with the Apache webserver, you'll need a working copy of Apache and mod_perl installed. Make sure that your mod_perl installation works correctly before trying to get HTML::Mason working. Also, if you are running RedHat Linux, do not use the mod_perl RPMs that ship with RedHat. They are not reliable (as of RedHat 6.1/mod_perl 1.21).

Where can I ask questions about HTML::Mason or report bugs?

You are encouraged to use the HTML::Mason mailing list; that way many people can answer questions and/or benefit from the answer. Write to mason@netizen.com.au. You may want to browse past messages in the archive first. Go to http://netizen.com.au/mailman/listinfo/mason for more information or to subscribe (although you can post without being subscribed).

If the question is more generally about mod_perl, you may wish to post additionally (or only) to the mod_perl mailing list at modperl@apache.org.

If you have a question or comment that you don't feel is appropriate for the group, write to swartz@transbay.net.

What is a component?

A component is a file that contains some combination of text (typically HTML), perl code and HTML::Mason directives.

Some components are accessed directly by web browsers. These are called top-level components. A top-level component might consist purely of static HTML.

Other components are support components, which are called by top-level components or other support components. These components are analogous to perl subroutines -- they allow you to create small packages of code that you can reuse throughout your project.

How do components communicate with each other?

Components can return values to their callers, just like subroutines.

Some components may have very simple return values. As an example, consider a component called isNetscape which returns a true value when the client's browser is Netscape and undef when it is not. The isNetscape component could then be used easily in an if() or other control statement.

Of course, components can also return strings of text, arrays, hashes or other arbitrarily complex perl data structures.

How do I use modules in components?

Technically you can just say "use module-name" at the beginning of a component. The disadvantages of this method are that:

  • the module will be used separately by every httpd child process, costing both time and memory.

  • it is difficult to keep track of all the modules being used on a site.

A more efficient method is to put the use line in the handler.pl or use the PerlModule directive. If you want components to be able to refer to symbols exported by the module, you need to use the module inside the HTML::Mason::Commands package. See the "External modules" section of the Administrator's Guide:

        http://www.masonhq.com/docs/manual/0.8/Admin.html#external_modules

Can I define subroutines in components?

First, consider using a separate component. They are functionally equivalent, and this is playing to Mason's strengths. If the subroutine is small, or limited in scope, consider using a <%def> subcomponent.

You can define named subroutines inside the <%once> section of any component. Defining the subroutine in a <%perl> or <%init> section is not reliable because such a definition would end up residing inside another subroutine, and Perl doesn't like that.

You can define anonymous subroutines anywhere:

        my $foo = sub {...};

Can I serve images through a HTML::Mason server?

If you put images in the same directories as components, you need to make sure that the images don't get handled through HTML::Mason. The reason is that HTML::Mason will try to parse the images and may inadvertently find HTML::Mason syntax (e.g. "<%"). Most images will probably pass through successfully but a few will cause HTML::Mason errors.

The simplest remedy is to have HTML::Mason decline image and other non-HTML requests, thus letting Apache serve them in the normal way. The following line, placed in the handler() subroutine of your handler.pl,

        return -1 if defined($r->content_type) && $r->content_type !~ m|^text/|io;

declines all requests with a content type not starting with "text/". This allows text/html and text/plain to pass through but not much else. It is included in the default handler.pl.

Another solution is to put all images in a separate directory; it is then easier to tell Apache to serve them in the normal way. See the next question.

For performance reasons you should consider serving images from a completely separate (non-HTML::Mason) server. This will save a lot of memory as most requests will go to a thin image server instead of a large mod_perl server. See Vivek Khera's performance FAQ for a more detailed explanation.

How can I prevent a particular subdirectory from being handled by HTML::Mason?

Suppose you have a directory under your document root, "/plain", and you would like to serve these files normally instead of using the HTML::Mason handler. One solution is to use a Location directive like:

        <Location /plain>
                SetHandler default-handler
        </Location>

Apparently these will work as well:

        SetHandler text/html
        SetHandler */*

Another solution is to put a line like this at the top of the handler() subroutine of your handler.pl:

        return -1 if $r->uri() =~ m|^/plain|;

Is Mason fast?

It is typically more than fast enough. 50-100 requests per second for a simple component is typical for a reasonably modern Linux system. Some simple benchmarking indicates that a Mason component is typically about two to three times slower than an equivalent, hand-coded mod_perl module.

Beware of "Hello World!" and other simple benchmarks. While these benchmarks do a good job of measuring the setup and initialization time for a package, they are typically not good measures of how a package will perform in a complex, real-world application. As with any program, the only way to know if it meets your requirements is to test it yourself.

In general, however, if your application is fast enough in pure mod_perl, it will most likely be fast enough under HTML::Mason as well.

How can I make my Mason application run faster?

The first thing you can do to optimize Mason performance is to optimize your mod_perl installation. Consider implementing some of the tuning tips recommended in mod_perl_tuning, which ships with every copy of mod_perl.

If your application still needs to run faster, consider using Mason's caching methods ($m->cache and $m->cache_self) to avoid regenerating dynamic content unnecessarily.

Does Mason leak memory?

The last known Mason-specific leak was fixed in 0.5. We are not aware of any current leaks in Mason itself. If you are using RedHat's mod_perl RPM, or another DSO mod_perl installation, you will leak memory and should switch to a statically compiled mod_perl.

Of course it is always possible for your own component code to leak, e.g. by creating and not cleaning up global variables.

Can I run HTML::Mason outside a web server?

Yes, in fact HTML::Mason can be useful for generating a set of web pages offline or as a general templating tool. See the "Standalone Mode" section of the Interpreter manual:

        http://www.masonhq.com/docs/manual/0.8/Interp.html#standalone_mode

Can I run HTML::Mason via CGI?

Yes. Masonite Ilmari Karonen uses HTML::Mason under CGI. He has kindly posted the necessary steps to do this on the HTML::Mason mailing list. His message can be viewed at http://forum.swarthmore.edu/epigone/mason/gimpswumfrex/Pine.SOL.3.96.990917144751.17640B-100000@simpukka

Please note that running HTML::Mason under CGI (or other non-persistent environments) will entail a substantial performance hit, since the perl interpreter will have to load, load up HTML::Mason and its supporting modules for every CGI execution. Using mod_perl or similar persistent environments (SpeedyCGI, FastCGI, etc.) avoids this performance bottleneck.

What platforms does HTML::Mason run on?

We are aware of successful installations on Solaris, Linux, FreeBSD, HPUX and Windows NT.

Because HTML::Mason consists of only Perl code (no C), it should work anywhere Perl runs. If it doesn't work on your operating system, let us know.

Why am I getting 404 errors for pages that clearly exist?

The filename that Apache has resolved to may not fall underneath the component root you specified when you created the interpreter in handler.pl. HTML::Mason requires the file to fall under the component root so that it can call it as a top-level component. (For various reasons, such as object file creation, HTML::Mason cannot treat files outside the component root as a component.)

If you believe the file is in fact inside the component root and HTML::Mason is in error, it may be because you're referring to the Apache document root or the HTML::Mason component root through a symbolic link. The symbolic link may confuse HTML::Mason into thinking that two directories are different when they are in fact the same. This is a known "bug", but there is no obvious fix at this time. For now, you must refrain from using symbolic links in either of these configuration items.

How do I exit from all components including the ones that called me?

Use $m->abort, documented in the Request manual:

        http://www.masonhq.com/docs/manual/0.8/Request.html#item_abort_return_value_

How do I access GET or POST arguments?

GET and POST arguments are automatically parsed and placed into named component arguments just as if you had called the component with <& &> or $m->comp. So you can get at GET/POST data by pre-declaring argument names and/or using the %ARGS hash which is always available.

Should I use CGI.pm to read GET/POST arguments?

No! HTML::Mason automatically parses GET/POST arguments and places them in declared component arguments and %ARGS (see previous question). If you create a CGI object in the usual way for a POST request, it will hang the process trying to read $r->content a second time.

Can I use CGI.pm to output HTML constructs?

Yes. To get a new CGI object, use

        my $query = new CGI('');

You have to give the empty string argument or CGI will try to read GET/POST arguments.

To print HTML constructs returned by CGI functions, just enclose them in <%%>, e.g.

        <% $query->radio_group(...) %>

How do I modify the outgoing HTTP headers?

Use the usual Apache.pm functions, such as $r->header_out. See the "Sending HTTP Headers" section in the Component Developer's Guide:

        http://www.masonhq.com/docs/manual/0.8/Devel.html#sending_http_headers

How do I do an external redirect?

Here's how to redirect to $url:

        <%init>
        # The next two lines are necessary to stop Apache from re-reading
        # POSTed data.
        $r->method('GET');
        $r->headers_in->unset('Content-length');

        $r->content_type('text/html');
        $r->header_out(Location=>$url);
        $m->abort(302);
        </%init>

Some of my pages are being served with content type xxx instead of text/html. How do I get HTML::Mason to properly set the content type?

HTML::Mason doesn't actually touch the content type -- it relies on Apache to set it correctly. You can affect how Apache sets your content type in the configuration files (e.g. srm.conf). The most common change you'll want to make is to add the line

        DefaultType text/html

This indicates that files with no extension and files with an unknown extension should be treated as text/html. By default, Apache would treat them as text/plain.

I have a line in my handler.pl to stop HTML::Mason from processing anything but text files, but I want to generate a dynamic image using HTML::Mason. How can I get HTML::Mason to set the correct MIME type?

Use mod_perl's $r->content_type function to set the appropriate MIME type. This will allow you to output, for example, a GIF file, even if your component is called dynamicImage.html.

How do I put comments in components?

  • Put general comments in the <%doc> section.

  • In the <%init> and <%cleanup> sections, and in a <%perl> block, use standard Perl comments ('#').

  • In the primary section, begin a line with %# to make it a comment

  • If you are producing HTML, you can use standard HTML comments delimited by <!-- -->.

The difference between 3 and 4 is that %# comments will not appear in the output, while <!-- --> comments will appear. Both have their advantages.

What's a good way to temporarily comment out code in a component?

For HTML, you might be tempted to surround the section with <!-- -->. But be careful! Any code inside the section will still execute. Here's a example of commenting out a call to an ad server:

        <!-- temporarily comment out
        <& FetchAd &>
        -->

The ad will still be fetched and counted, but not displayed!

A better way to block out a section is if (0):

        % if (0) {
                ...
        % }

Code blocked out in this way will neither be executed nor displayed, and multiple if (0) blocks can be nested inside each other (unlike HTML comments).

How can I capture the output of a component (and modify it, etc.) instead of having it automatically output?

Use $m->scomp, documented in the Request manual:

        http://www.masonhq.com/docs/manual/0.8/Request.html#item_scomp

Can I use globals in components?

All HTML::Mason components run in the same package (HTML::Mason::Commands), so if you set a global variable in one you'll be able to read it in all the others. You can also initialize global variables in the handler() subroutine in handler.pl as long as you explicitly put them in the HTML::Mason::Commands package.

The only problem is that Mason by default parses components with strict mode on, so you'll get a warning about the global (and Mason considers all such warnings fatal). To get around this you need to declare the global in a "use vars" statement inside the HTML::Mason::Commands package:

        package HTML::Mason::Commands;
        use vars qw(...);

or use the Parser allow_globals parameter. See the section on globals in the Administrator's Guide:

        http://www.masonhq.com/docs/manual/Admin.html#using_global_variables

Alternatively you can turn off strict entirely by passing:

        use_strict => 0

when you create the Parser object. Then you can use all the globals you want. Doing this is terribly silly, however, and is bound to get you in trouble down the road.

Can Mason support multiple component roots, with searching, ala Perl's @INC?

As of Mason 0.8, yes! Consult the "Component roots (multiple)" section in the Administrator's Guide:

        http://www.masonhq.com/docs/manual/0.8/Admin.html#component_roots_multiple_

Do data cache files expire automatically when a component or its dependencies change?

Eventually, but not right now. Unfortunately, it is difficult for Mason to check this efficiently in the current implementation. But you can use the following idiom to say "expire when my component source file changes":

        $m->cache(..., expire_if=>sub { (stat($m->source_file))[9] > $_[0] } )

Why does the order of output get mixed up when I use print or $r->print?

Since your server is most likely in batch mode, all Mason output gets buffered til the end of the request. print and $r->print circumvent the buffer and thus come out before other Mason output.

Solution: don't use print or $r->print. Use $m->out if you must output inside a Perl section. See the section on output mode in the Administrator's Guide:

        http://www.masonhq.com/docs/manual/Admin.html#out_mode

and the section on $m->out in the Request manual:

        http://www.masonhq.com/docs/manual/Request.html#item_out_string_