\*(C'\fR block as part of
your \fIhttpd.conf\fR file. The result is no different than loading a
file via the \f(CW\*(C`PerlRequire\*(C'\fR directive.
.SS "The Wrapper Code"
.IX Subsection "The Wrapper Code"
Regardless of how you load your wrapper code, it will always work the
same way. The \f(CWhandler()\fR subroutine should expect to receive the
Apache request object representing the current request. This request
object is used by the ApacheHandler module to determine what component
is being called.
.PP
Let's look at the guts of some wrapper code. Here's a first version:
.PP
.Vb 1
\& package MyApp::Mason;
\&
\& use strict;
\& use HTML::Mason::ApacheHandler;
\&
\& my $ah =
\& HTML::Mason::ApacheHandler\->new
\& ( comp_root => \*(Aq/path/to/comp/root\*(Aq,
\& data_dir => \*(Aq/path/to/data/dir\*(Aq );
\&
\& sub handler {
\& my ($r) = @_;
\&
\& return $ah\->handle_request($r);
\& }
.Ve
.PP
This wrapper is fully functional, but it doesn't actually do anything
you couldn't do more easily by configuring Mason via the \fIhttpd.conf\fR
file. However, it does serve as a good skeleton to which additional
functionality can easily be added.
.SS "External Modules Revisited"
.IX Subsection "External Modules Revisited"
Since you are loading an arbitrary piece of code to define your
wrapper, you can easily load other modules needed for your application
at the same time. For example, you might simple add these lines to
the wrapper code above:
.PP
.Vb 2
\& {
\& package HTML::Mason::Commands;
\&
\& use MIME::Base64;
\& }
.Ve
.PP
Explicitly setting the package to \f(CW\*(C`HTML::Mason::Commands\*(C'\fR makes sure
that any symbols that the loaded modules export (constants,
subroutines, etc.) get exported into the namespace under which
components run. Of course, if you've changed the component namespace,
make sure to change the package name here as well.
.PP
Alternatively, you might consider creating a separate piece of code to
load the modules you need. For example, you might create a module
called \f(CW\*(C`MyApp::MasonInit\*(C'\fR:
.PP
.Vb 2
\& {
\& package HTML::Mason::Commands;
\&
\& use Apache::Constants qw(:common);
\& use Apache::URI;
\& use File::Temp;
\& }
\&
\& 1;
.Ve
.PP
This can be loaded via a \f(CW\*(C`PerlModule\*(C'\fR directive in the \fIhttpd.conf\fR
file, or in the wrapper code itself via \f(CW\*(C`use\*(C'\fR.
.PP
\fIExample: Controlling access with component attributes\fR
.IX Subsection "Example: Controlling access with component attributes"
.PP
An example of something you can only do with wrapper code is deciding
at run-time whether a component can be accessed at the top-level based
on a complex property of the component. For example, here's a piece
of code that uses the current user and a component's \f(CW\*(C`access_level\*(C'\fR
attribute to control access:
.PP
.Vb 2
\& sub handler {
\& my ($r) = @_;
\&
\& my $req = $ah\->prepare_request($r);
\&
\& my $comp = $req\->request_comp;
\&
\& # this is done via magic hand\-waving ...
\& my $user = get_user_from_cookie();
\&
\& # remember, attributes are inherited so this could come from a
\& # component higher up the inheritance chain
\& my $required_access = $comp\->attr(\*(Aqaccess_level\*(Aq);
\&
\& return NOT_FOUND
\& if $user\->access_level < $required_access;
\&
\& return $req\->exec;
\& }
.Ve
.SS "Wrappers with Virtual Hosts"
.IX Subsection "Wrappers with Virtual Hosts"
If you had several virtual hosts, each of which had a separate
component root, you'd need to create a separate ApacheHandler object
for each host, one for each host. Here's some sample code for that:
.PP
.Vb 7
\& my %ah;
\& foreach my $site ( qw( site1 site2 site3 ) ) {
\& $ah{$site} =
\& HTML::Mason::ApacheHandler\->new
\& ( comp_root => "/usr/local/www/$site",
\& data_dir => "/usr/local/mason/$site" );
\& }
\&
\& sub handler {
\& my ($r) = @_;
\&
\& my $site = $r\->dir_config(\*(AqSiteName\*(Aq);
\&
\& return DECLINED unless exists $ah{$site};
\&
\& return $ah{$site}\->handle_request($r);
\& }
.Ve
.PP
This code assumes that you set the \f(CW\*(C`SiteName\*(C'\fR variable via a
\&\f(CW\*(C`PerlSetVar\*(C'\fR directive in each \f(CW\*(C`VirtualHost\*(C'\fR block, like this:
.PP
.Vb 2
\&
\& PerlSetVar SiteName site1
\&
\&
\& SetHandler perl\-script
\& PerlHandler MyApp::Mason
\&
\&
.Ve
.PP
\fICreating apachehandler objects on the fly\fR
.IX Subsection "Creating apachehandler objects on the fly"
.PP
You might also consider creating ApacheHandler objects on the fly,
like this:
.PP
.Vb 4
\& my %ah;
\& sub handler {
\& my ($r) = @_;
\& my $site = $r\->dir_config(\*(AqSiteName\*(Aq);
\&
\& return DECLINED unless $site;
\&
\& unless exists($ah{$site}) {
\& $ah{$site} = HTML::Mason::ApacheHandler\->new( ... );
\& }
\&
\& $ah{$site}\->handle_request($r);
\& }
.Ve
.PP
This is more flexible but you lose the memory savings of creating all
your objects during server startup.
.PP
\fIOther uses for a wrapper\fR
.IX Subsection "Other uses for a wrapper"
.PP
If you have some code which must \fIalways\fR run after a request, then
the only way to guarantee that this happens is to wrap the \f(CW\*(C`$ah\->handle_request()\*(C'\fR
call in an \f(CW\*(C`eval {}\*(C'\fR block, and then run the
needed code after the request returns. You can then handle errors
however you like.
.SS "Mixing httpd.conf Configuration with a Wrapper"
.IX Subsection "Mixing httpd.conf Configuration with a Wrapper"
You can take advantage of Mason's \fIhttpd.conf\fR configuration system
while at the same time providing your own wrapper code. The key to
doing this is \fInot\fR creating your own ApacheHandler object. Instead,
you call the \f(CW\*(C`HTML::Mason::ApacheHandler\->handler()\*(C'\fR class method
from your \f(CWhandler()\fR subroutine. Here's a complete wrapper that
does this:
.PP
.Vb 1
\& package MyApp::Mason;
\&
\& use strict;
\& use HTML::Mason::ApacheHandler;
\&
\& sub handler {
\& my ($r) = @_;
\&
\& return HTML::Mason::ApacheHandler\->handler($r);
\& }
.Ve
.PP
The \f(CW\*(C`HTML::Mason::ApacheHandler\->handler\*(C'\fR method will create an
ApacheHandler object based on the configuration directives it finds in
your \fIhttpd.conf\fR file. Obviously, this wrapper is again a skeleton,
but you could mix and match this wrapper code with any of the code
shown above.
.PP
Alternately you could subclass the \f(CW\*(C`HTML::Mason::ApacheHandler\*(C'\fR
class, and override the \f(CWhandler()\fR method it provides. See the
Subclassing documentation for more
details. Of course, you could even create a subclass \fIand\fR write a
wrapper that called it.
.SH DEVELOPMENT
.IX Header "DEVELOPMENT"
This section describes how to set up common developer features.
.SS "Global Variables"
.IX Subsection "Global Variables"
Global variables can make programs harder to read, maintain, and
debug, and this is no less true for Mason components. Due to the
persistent mod_perl environment, globals require extra initialization
and cleanup care.
.PP
That said, there are times when it is very useful to make a value
available to all Mason components: a DBI database handle, a hash of
user session information, the server root for forming absolute URLs.
.PP
Because Mason by default parses components in \f(CW\*(C`strict\*(C'\fR mode, you'll
need to declare a global if you don't want to access it with an
explicit package name. The easiest way to declare a global is with
the allow_globals parameter.
.PP
Since all components run in the same package, you'll be able to set
the global in one component and access it in all the others.
.PP
Autohandlers are common places to assign values to globals. Use the
\&\f(CW\*(C`<%once>\*(C'\fR section if the global only needs to be
initialized at load time, or the \f(CW\*(C`<%init>\*(C'\fR section if it
needs to be initialized every request.
.SS Sessions
.IX Subsection "Sessions"
Mason does not have a built-in session mechanism, but you can use the
\&\f(CW\*(C`MasonX::Request::WithApacheSession\*(C'\fR module, available from CPAN, to
add a session to every request. It can also automatically set and
read cookies containing the session id.
.SS "Data Caching"
.IX Subsection "Data Caching"
Data caching is implemented with DeWitt Clinton's \f(CW\*(C`Cache::Cache\*(C'\fR
module. For full understanding of this section you should read the
documentation for \f(CW\*(C`Cache::Cache\*(C'\fR as well as for relevant subclasses
(e.g. \f(CW\*(C`Cache::FileCache\*(C'\fR).
.IP "Cache files" 4
.IX Item "Cache files"
By default, \f(CW\*(C`Cache::FileCache\*(C'\fR is the subclass used for data caching,
although this may be overridden by the developer. \f(CW\*(C`Cache::FileCache\*(C'\fR
creates a separate subdirectory for every component that uses caching,
and one file some number of levels underneath that subdirectory for
each cached item. The root of the cache tree is
data_dir/\f(CW\*(C`cache\*(C'\fR. The name of the cache subdirectory for a component
is determined by the function \f(CW\*(C`HTML::Mason::Utils::data_cache_namespace\*(C'\fR.
.IP "Default constructor options" 4
.IX Item "Default constructor options"
Ordinarily, when \f(CW\*(C`$m\->cache\*(C'\fR is called, Mason passes to the cache
constructor the \f(CW\*(C`namespace\*(C'\fR, and \f(CW\*(C`cache_root\*(C'\fR options, along with
any other options given in the \f(CW\*(C`$m\->cache\*(C'\fR method.
.Sp
You may specify other default constructor options with the
data_cache_defaults parameter. For example,
.Sp
.Vb 3
\& PerlSetVar MasonDataCacheDefaults "cache_class => SizeAwareFileCache"
\& PerlAddVar MasonDataCacheDefaults "cache_depth => 2"
\& PerlAddVar MasonDataCacheDefaults "default_expires_in => 1 hour"
.Ve
.Sp
Any options passed to individual \f(CW\*(C`$m\->cache\*(C'\fR calls override these
defaults.
.IP "Disabling data caching" 4
.IX Item "Disabling data caching"
If for some reason you want to disable data caching entirely, set the
default \f(CW\*(C`cache_class\*(C'\fR to "NullCache". This subclass faithfully
implements the cache API but never stores data.
.SH PERFORMANCE
.IX Header "PERFORMANCE"
This section explains Mason's various performance enhancements and how
to administer them. One of the best ways to maximize performance on
your production server is run in static_source mode; see the third
subsection below.
.SS "Code Cache"
.IX Subsection "Code Cache"
When Mason loads a component, it places it in a memory cache. By
default, the cache has no limit, but you can specify a maximum number
of components to cache with the code_cache_max_size parameter. In
this case, Mason will free up space as needed by discarding
components. The discard algorithm is least frequently used (LFU), with
a periodic decay to gradually eliminate old frequency information. In
a nutshell, the components called most often in recent history should
remain in the cache.
.PP
Previous versions of Mason attempted to estimate the size of each
component, but this proved so inaccurate as to be virtually useless
for cache policy. The max size is now specified purely in number of
components.
.PP
Mason can use certain optimizations with an unlimited cache,
especially in conjunction with static_source, so don't limit the
cache unless experience shows that your servers are growing too
large. Many dynamic sites can be served comfortably with all
components in memory.
.PP
You can prepopulate the cache with components that you know will be
accessed often; see Preloading Components.
Note that preloaded components possess no special status in the cache
and can be discarded like any others.
.PP
Naturally, a cache entry is invalidated if the corresponding component
source file changes.
.PP
To turn off code caching completely, set code_cache_max_size to 0.
.SS "Object Files"
.IX Subsection "Object Files"
The in-memory code cache is only useful on a per-process basis. Each
process must build and maintain its own cache. Shared memory caches
are conceivable in the future, but even those will not survive between
web server restarts.
.PP
As a secondary, longer-term cache mechanism, Mason stores a compiled
form of each component in an object file under data_dir/obj. Any
server process can eval the object file and save time on parsing the
component source file. The object file is recreated whenever the
source file changes.
.PP
The object file pathname is formed from three parts:
.IP \(bu 4
the compiler \f(CW\*(C`object_id\*(C'\fR \-
this prevents different versions of Mason or compilers from using the same
object file, such as after an upgrade
.IP \(bu 4
the component path
.IP \(bu 4
object_file_extension, by default ".obj"
.PP
Besides improving performance, object files can be useful for
debugging. If you feel the need to see what your source has been
translated into, you can peek inside an object file to see exactly how
Mason converted a given component to a Perl object. This was crucial
for pre\-1.10 Mason, in which error line numbers were based on the
object file rather than the source file.
.PP
If for some reason you don't want Mason to create object files, set
use_object_files to 0.
.SS "Static Source Mode"
.IX Subsection "Static Source Mode"
In static_source mode, Mason assumes that the component hierarchy
is unchanging and thus does not check source timestamps when using an
in-memory cached component or object file. This significantly reduces
filesystem stats and other overhead. We've seen speedups by a factor
of two or three as a result of this mode, though of course YMMV.
.PP
When in static_source mode, you must remove object files and call
\&\f(CW$interp\fR\->flush_code_cache in order for the server to recognize
component changes. The easiest way to arrange this is to point
static_source_touch_file to a file that can be touched whenever
components change.
.PP
We highly recommend running in this mode in production if you can
manage it. Many of Mason's future optimizations will be designed for
this mode. On development servers, of course, it makes sense to keep
this off so that components are reloaded automatically.
.SS "Disabling Autoflush"
.IX Subsection "Disabling Autoflush"
To support the dynamic autoflush feature, Mason has to check for
autoflush mode after printing every piece of text. If you can commit
to not using autoflush, setting enable_autoflush to 0 will allow
Mason to compile components more efficiently. Consider whether a few
well-placed \f(CW\*(C`$m\->flush_buffer\*(C'\fR calls would be just as good as
autoflush.
.SS "Write a handler subroutine"
.IX Subsection "Write a handler subroutine"
Writing your own \f(CWhandler()\fR subroutine which uses an ApacheHandler
object (or objects) created during server startup is slightly faster
(around 5% or so) than configuring mason via your \fIhttpd.conf\fR file
and letting Mason create its own ApacheHandler objects internally.
.SS "Preloading Components"
.IX Subsection "Preloading Components"
You can tell Mason to preload a set of components in the parent
process, rather than loading them on demand, using the preloads
parameter. Each child server will start with those components loaded
in the memory cache. The trade-offs are:
.IP time 4
.IX Item "time"
a small one-time startup cost, but children save time by not
having to load the components
.IP memory 4
.IX Item "memory"
a fatter initial server, but the memory for preloaded components are
shared by all children. This is similar to the advantage of using
modules only in the parent process.
.PP
Try to preload components that are used frequently and do not change
often. (If a preloaded component changes, all the children will have
to reload it from scratch.)
.SS "Preallocating the Output Buffer"
.IX Subsection "Preallocating the Output Buffer"
You can set buffer_preallocate_size to set the size of the
preallocated output buffer for each request. This can reduce the
number of reallocations Perl performs as components output text.
.SH "ERROR REPORTING AND EXCEPTIONS"
.IX Header "ERROR REPORTING AND EXCEPTIONS"
When an error occurs, Mason can respond by:
.IP \(bu 4
showing a detailed error message in the browser in HTML.
.IP \(bu 4
die'ing, which sends a 500 status to the browser and lets the error
message go to the error logs.
.PP
The first behavior is ideal for development, where you want immediate
feedback on the error. The second behavior is usually desired for
production so that users are not exposed to messy error messages. You
choose the behavior by setting error_mode to "output" or "fatal"
respectively.
.PP
Error formatting is controlled by the error_format parameter. When
showing errors in the browser, Mason defaults to the "html" format.
When the error_mode is set to "fatal", the default format is
"line", which puts the entire error message on one line in a format
suitable for web server error logs. Mason also offers other formats,
which are covered in the Request class
documentation.
.PP
Finally, you can use Apache's \f(CW\*(C`ErrorDocument\*(C'\fR directive to specify a
custom error handler for 500 errors. In this case, you'd set the
error_mode to "fatal". The URL specified by the \f(CW\*(C`ErrorDocument\*(C'\fR
directive could point to a Mason component.
.SS "Exceptions Under the Hood"
.IX Subsection "Exceptions Under the Hood"
The way that Mason really reports errors is through the use of
exception objects, which are implemented with the \f(CW\*(C`Exception::Class\*(C'\fR
module from CPAN, and some custom code in the
HTML::Mason::Exceptions module.
.PP
If, during the execution of a component, execution stops because some
code calls \f(CWdie()\fR, then Mason will catch this exception. If the
exception being thrown is just a string, then it will be converted to
an \f(CW\*(C`HTML::Mason::Exception\*(C'\fR object. If the exception being thrown is
an object with a \f(CWrethrow()\fR method, then this method will be called.
Otherwise, Mason simply leaves the exception untouched and calls
\&\f(CWdie()\fR again.
.PP
\fICalling a Component to Handle Errors\fR
.IX Subsection "Calling a Component to Handle Errors"
.PP
Returning to the topic of wrapper code that we covered earlier, what
if you wanted to handle all request errors by calling an error
handling component? There is no way to do this without wrapper code.
Here's an example \f(CWhandler()\fR subroutine that does this:
.PP
.Vb 2
\& sub handler {
\& my ($r) = @_;
\&
\& my $return = eval { $ah\->handle_request($r) };
\&
\& if ( my $err = $@ )
\& {
\& $r\->pnotes( error => $err );
\& $r\->filename( $r\->document_root . \*(Aq/error/500.html\*(Aq );
\&
\& return $ah\->handle_request($r);
\& }
\&
\& return $return;
\& }
.Ve
.PP
First, we wrap our call to \f(CW\*(C`$ah\->handle_request()\*(C'\fR in an
\&\f(CW\*(C`eval{}\*(C'\fR block. If an error occurs, we store it in the request
object using the \f(CW\*(C`$r\->pnotes()\*(C'\fR method. Then we change the
filename property of the Apache request object to point to our
error-handling component and call the \f(CW\*(C`$ah\->handle_request()\*(C'\fR
method again, passing it the altered request object. We could have
put the exception in \f(CW\*(C`$r\->args\*(C'\fR, but we want to leave this
untouched so that the error-handling component can see the original
arguments.
.PP
Here's what that component error-handling component might look like:
.PP
.Vb 4
\&
\&
\& Error
\&
\&
\&
\&
\&
\& Looks like our application broke. Whatever you did, don\*(Aqt do it again!
\&
\&
\&
\& If you have further questions, please feel free to contact us at support@example.com.
\&
\&
\& Click here to continue.
\&
\&
\&
\&
\& <%init>
\& my $error = $r\->pnotes(\*(Aqerror\*(Aq);
\&
\& my $error_text = "Page is " . $r\->parsed_uri\->unparse . "\en\en";
\&
\& $error_text .= UNIVERSAL::can( $error, \*(Aqas_text\*(Aq ) ? $error\->as_text : $error;
\&
\& $r\->log_error($error_text);
\&
\& my $mail =
\& MIME::Lite\->new
\& ( From => \*(Aqerror\-handler@example.com\*(Aq,
\& To => \*(Aqrt@example.com\*(Aq,
\& Subject => \*(AqApplication error\*(Aq,
\& Data => $error_text,
\& );
\&
\& $r\->register_cleanup( sub { $mail\->send } );
\& %init>
\&
\& <%flags>
\& inherit => undef
\& %flags>
.Ve
.PP
This component does several things. First of all, it logs the
complete error to the Apache error logs, along with the complete URL,
including query string, that was requested. The \f(CW\*(C`$r\->parsed_uri()\*(C'\fR
method that we use above is only available if the \f(CW\*(C`Apache::URI\*(C'\fR
module has been loaded.
.PP
The component also sends an email containing the error, in this case
to an RT installation, so that the error is logged in a bug tracking
system. Finally, it displays a less technical error message to the
user.
.PP
For this to work properly, you must set error_mode to "fatal", so
that Mason doesn't just display its own HTML error page.
.SH "RUNNING OUTSIDE OF MOD_PERL"
.IX Header "RUNNING OUTSIDE OF MOD_PERL"
Although Mason is most commonly used in conjunction with mod_perl, the
APIs are flexible enough to use in any environment. Below we describe
the two most common alternative environments, CGI and standalone
scripts.
.SS "Using Mason from a CGI Script"
.IX Subsection "Using Mason from a CGI Script"
The easiest way to use Mason via a CGI script is with the CGIHandler
module module.
.PP
Here is a skeleton CGI script that calls a component and sends the
output to the browser.
.PP
.Vb 2
\& #!/usr/bin/perl
\& use HTML::Mason::CGIHandler;
\&
\& my $h = HTML::Mason::CGIHandler\->new
\& (
\& data_dir => \*(Aq/home/jethro/code/mason_data\*(Aq,
\& );
\&
\& $h\->handle_request;
.Ve
.PP
The relevant portions of the \fIhttpd.conf\fR file look like:
.PP
.Vb 2
\& DocumentRoot /path/to/comp/root
\& ScriptAlias /cgi\-bin/ /path/to/cgi\-bin/
\&
\&
\& Action html\-mason /cgi\-bin/mason_handler.cgi
\& AddHandler html\-mason .html
\&
\&
\& RemoveHandler .html
\&
\&
\& Order allow,deny
\& Deny from all
\&
.Ve
.PP
This simply causes Apache to call the mason_handler.cgi script every
time a URL ending in ".html" under the component root is requested.
.PP
To exclude certain directories from being under Mason control, you can
use something like the following:
.PP
.Vb 3
\&
\& RemoveHandler .html
\&
.Ve
.PP
This script uses the CGIHandler class to do
most of the heavy lifting. See that class's documentation for more
details.
.SS "Using Mason from a Standalone Script"
.IX Subsection "Using Mason from a Standalone Script"
Mason can be used as a pure text templating solution \-\- like
Text::Template and its brethren, but with more power (and of course
more complexity).
.PP
Here is a bare-bones script that calls a component file and sends
the result to standard output:
.PP
.Vb 3
\& #!/usr/bin/perl
\& use HTML::Mason;
\& use strict;
\&
\& my $interp = HTML::Mason::Interp\->new ();
\& $interp\->exec(, ...);
.Ve
.PP
Because no component root was specified, the root is set to your
current working directory. If you have a well defined and contained
component tree, you'll probably want to specify a component root.
.PP
Because no data directory was specified, object files will not be
created and data caching will not work in the default manner. If
performance is an issue, you will want to specify a data directory.
.PP
Here's a slightly fuller script that specifies a component root and
data directory, and captures the result in a variable rather than
sending to standard output:
.PP
.Vb 3
\& #!/usr/bin/perl
\& use HTML::Mason;
\& use strict;
\&
\& my $outbuf;
\& my $interp = HTML::Mason::Interp\->new
\& (comp_root => \*(Aq/path/to/comp_root\*(Aq,
\& data_dir => \*(Aq/path/to/data_dir\*(Aq,
\& out_method => \e$outbuf
\& );
\& $interp\->exec(, ...);
\&
\& # Do something with $outbuf
.Ve