=head1 NAME

HTML::Mason::Admin - Mason Administrator's Guide

=head1 DESCRIPTION

This guide is intended for the sysadmin/webmaster in charge of
installing, configuring, or tuning a Mason system.

=head1 SITE CONFIGURATION METHODS

There are three ways to configure a Mason site:

=over 4

=item *

Minimal configuration, relying on default Mason behavior. Simplest and least flexible.

=item *

Configuration via httpd.conf directives. Medium complexity and flexibility.

=item *

Configuration via a handler script (handler.pl). Most complex but most flexible.

=back

The next three sections discuss these methods in detail. We recommend
that you start with the simplest method and work your way forward as
the need for flexibility arises.

It is important to note that you cannot mix httpd.conf configuration
directives with a handler script.  Depending on how you declare your
C<PerlHandler>, one or the other will always take precedence and the
other will be ignored.

Mason is very flexible, and you can replace parts of it by creating
your own classes.  This documentation assumes that you are simply
using the classes provide in the Mason distribution.  Customizing and
subclassing is covered in the
L<Subclassing|HTML::Mason::Subclassing> document.

XXX: Must write that (can use appendix C from the book!).

=head1 MINIMAL CONFIGURATION

The absolutely most minimal configuration looks like this:

    PerlModule HTML::Mason::ApacheHandler

    <FilesMatch "\.html$">
        SetHandler perl-script
        PerlHandler HTML::Mason::ApacheHandler
    </FilesMatch>

All .html files under your document root will be served through Mason.
The PerlModule line makes sure that mod_perl loads that Mason code
before the server works, which can end up saving memory.

With this configuration, your I<component root> will be the same as
the C<DocumentRoot> setting, and your I<data directory> will be a
directory called "mason" located under your C<ServerRoot>.

The I<component root> is the top of your component source tree.  See
L<CONFIGURING VIRTUAL SITES|"CONFIGURING VIRTUAL SITES"> to understand
why the component root and C<DocumentRoot> might differ.

When Mason handles a request, the requested filename must be
underneath your component root -- that gives Mason a legitimate
component to start with.  If the filename is not underneath the
component root, Mason will place a warning in the error logs and
return 404.

The I<data directory> is a writable directory that Mason uses for
various features and optimizations. Mason will create the directory on
startup, if necessary, and set its permissions according to the web
server User/Group.

You can, of course, manually specify one of these or both, if you
don't like Mason's defaults.

    PerlSetVar MasonCompRoot /usr/local/www/htdocs
    PerlSetVar MasonDataDir /var/mason
    PerlModule HTML::Mason::ApacheHandler

    <FilesMatch "\.html$">
        SetHandler perl-script
        PerlHandler HTML::Mason::ApacheHandler
    </FilesMatch>

=head1 CONFIGURATION VIA httpd.conf DIRECTIVES

Mason's configuration parameters are set via mod_perl's C<PerlSetVar>
and C<PerlAddVar> directives, though the latter directive is only
available in mod_perl version 1.24 and greater.  Though these
parameters are all strings in your httpd.conf file, Mason treats them
as if they were several different types:

=over 4

=item * string

The variable's value is simply taken literally and used.  The string
should be surrounded by quotes if the string contains whitespace, and
these quotes will be automatically removed by Apache before Mason sees
the variable.

=item * boolean

The variable's value is used as a boolean, and is subject to Perl's
rules on truth/falseness.  It is recommended that you use 0 (false) or
1 (true) for these arguments.

=item * code

The string is treated as a piece of code and C<eval>'ed.  This is used
for parameters that expect subroutine references.  For example, an
anonymous subroutine might look like:

 PerlSetVar  MasonOutMode  "sub { ... }"

A named subroutine call would look like this:

 PerlSetVar  MasonOutmode  "\&handle_output"

=item * list

To set a list parameter, use C<PerlAddVar> for the values, like this:

 PerlAddVar  MasonPreloads  /foo/bar/baz.comp
 PerlAddVar  MasonPreloads  /foo/bar/quux.comp

As noted above, C<PerlAddVar> is only available in mod_perl 1.24 and
up.  This means that it is only possible to assign a single value
(using C<PerlSetVar>) to list parameters if you are using a mod_perl
older than 1.24.

=back

All of the configuration parameters allowed in the F<httpd.conf> file
correspond to constructor parameters for various Mason
objects. Configuration parameters are named predictably by taking the
mixed-caps form of the new() parameter and prefixing "Mason".  For
example, comp_root becomes MasonCompRoot and data_dir becomes
MasonDataDir.

All of the available parameters, along with their F<httpd.conf> name,
are listed in L<HTML::Mason::Params|HTML::Mason::Params>.

=head1 CONFIGURING VIA A HANDLER SCRIPT

For maximum flexibility, you may choose to write a custom script to
create your Mason objects and handle requests. In our documentation
and examples we call this script C<handler.pl>, though you may name it
whatever you like.

The C<handler.pl> file is responsible for creating the three Mason
objects and supplying the many parameters that control how your
components are parsed and executed. It also provides the opportunity
to execute arbitrary code at three important junctures: the server
initialization, the beginning of a request, and the end of a request.
A wide set of behaviors can be implemented with a mere few lines of
well-placed Perl in your C<handler.pl>.  In this section we present the
basics of setting up C<handler.pl> as well as some ideas for more
advanced applications.

=head2 Declaring your handler.pl

This method requires only a bit of Apache configuration.  First, use a
PerlRequire directive to tell mod_perl to load your handler.pl.  This
file can be located anywhere, though the Apache conf/ subdirectory is
a good place as any.  Second, set your PerlHandler simply to the
package you declare in your F<handler.pl> file (such as
MyMason::MyApp), rather than HTML::Mason::ApacheHandler.

    PerlRequire /path/to/handler.pl

    <FilesMatch "\.html$">
        SetHandler perl-script
        # notice - no ::ApacheHandler!
        PerlHandler MyMason::MyApp
    </FilesMatch>

=head2 Creating the Mason objects

F<handler.pl> explicitly creates just one Mason object, the
ApacheHandler. This object routes mod_perl requests to Mason.  It, in
turn, creates the Interp object, which creates a number of other
objects, including the Compiler, Lexer, Resolver, and Request(s).
These objects, excluding the Request, are created once in the parent
httpd and then copied to each child process.

These objects have a fair number of possible parameters, which are
discussed in the next two subsections. The various parameters are
documented in B<L<HTML::Mason::Params|HTML::Mason::Params>> reference,
as well as the individual reference manuals for each object:
B<L<HTML::Mason::Interp|HTML::Mason::Interp>>,
B<L<HTML::Mason::ApacheHandler|HTML::Mason::ApacheHandler>>,
B<L<HTML::Mason::Request|HTML::Mason::Request>>,
B<L<HTML::Mason::Compiler|HTML::Mason::Compiler>> and
B<L<HTML::Mason::Compiler::ToObject|HTML::Mason::Compiler::ToObject>>,
and B<L<HTML::Mason::Resolver::File|HTML::Mason::Resolver::File>>. The
B<L<HTML::Mason::Lexer|HTML::Mason::Lexer>> object takes no
parameters.

The advantage of embedding these parameters in objects is that
advanced configurations can create more than one set of objects,
choosing which set to use at request time.  For example, suppose you
have a staging site and a production site running on the same web
server, distinguishing between them with a configuration variable
called C<version>:

    # Create Mason objects for staging site
    my $ah1 = new HTML::Mason::ApacheHandler (comp_root => '/var/www/staging');

    # Create Mason objects for production site
    my $ah2 = new HTML::Mason::ApacheHandler (comp_root => '/var/www/prod');

    sub handler {
        ...

        # Choose the right ApacheHandler
        if ($r->dir_config('version') eq ' staging') {
            $ah1->handle_request($r);
        } else {
            $ah2->handle_request($r);
        }
    }

=head2 Multiple component roots

You may specify multiple component roots to be searched in the spirit
of Perl's C<@INC>. To do so you must specify a list of lists:

    comp_root => [[key1, root1], [key2, root2], ...]

Each pair consists of a key and root.  The key is a string that
identifies the root mnemonically to a component developer. Keys
are case-insensitive and must be distinct.

For example:

    comp_root => [ [ private => '/usr/home/joe/comps' ],
                   [ main    => '/usr/local/www/htdocs' ] ]

This specifies two component roots, a main component tree and a
private tree which overrides certain components.  The order is
respected ala C<@INC>, so I<private> is searched first and I<main> second.
(I chose the C<=E<gt>> notation here because it looks cleaner, but note that
this is a list of lists, not a hash.)

The key has several purposes. Object and data cache filenames use the
(uppercased) key to make sure different components sharing the same path have
different cache and object files. For example, if a component /foo/bar
is found in 'private', then the object file will be

    <data_dir>/obj/PRIVATE/foo/bar

and the cache file

    <data_dir>/cache/PRIVATE+2ffoo+2fbar

=head2 External modules

Components will often need access to external Perl modules. Any such
modules that export symbols should be listed in C<handler.pl>, rather
than the standard practice of using a PerlModule configuration
directive. This is because components are executed inside the
B<HTML::Mason::Commands> package, and can only access symbols exported
to that package. Here's sample module list:

    { package HTML::Mason::Commands;
      use CGI ':standard';
      use LWP::UserAgent;
      ... }

In any case, for optimal memory utilization, make sure all Perl
modules are used in the parent process, and I<not> in
components. Otherwise, each child allocates its own copy and you lose
the benefit of shared memory between parent processes and their
children. See the mod_perl guide's tuning section at
(perl.apache.org/guide) and Vivek Khera's mod_perl tuning guide
(perl.apache.org/tuning) for details.

=head2 File ownership

Apache web servers on Unix that run on privileged ports like 80 start
as root before forking, then spawn children running as the 'User' and
'Group' specified in httpd.conf. This difference leads to permission
errors when child processes try to write files or directories created
by the parent process.

To work around this conflict, Mason remembers all directories and
files created at startup, returning them in response to C<<
interp->files_written >>. This list can be fed to a chown() at the end
of the startup code in C<handler.pl>:

    chown (Apache->server->uid, Apache->server->gid, $ah->interp->files_written);

=head2 Persistent user sessions

With just a few lines in C<handler.pl> you can make a global hash
(e.g. I<%session>) available to all components containing persistent user
session data.  If you set a value in the hash, you will see the change
in future visits by the same user.  The key piece is Jeffrey Baker's
B<Apache::Session> module, available from CPAN.

The file C<eg/session_handler.pl> in the distribution contains the
lines to activate cookie-based sessions using Apache::Session and
CGI::Cookie. You can use C<eg/session_handler.pl> as your new C<handler.pl>
base, or just copy out the appropriate pieces to your existing C<handler.pl>.

The session code is customizable; you can change the user ID location
(e.g. URL instead of cookie), the user data storage mechanism
(e.g. DBI database), and the name of the global hash.

=head2 Using global variables

Global variables generally make programs harder to read, maintain, and
debug, and this is no less true for Mason.  Due to the persistent
mod_perl environment, globals require extra initialization and cleanup
care. And the highly modular nature of Mason pages does not mix well
with globals: it is no fun trying to track down which of twenty
components is stepping on your variable. With the ability to pass
parameters and declare lexical (C<my>) variables in components, there
is very little need for globals at all.

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.
Usually you initialize the global in your C<handler.pl>, either outside
the handler() subroutine (if you only need to set it once) or inside
(if you need to set it every request).

Mason by default parses components in C<strict> mode, so you can't
simply start referring to a new global or you'll get a fatal
warning. The solution is to invoke C<use vars> inside the
package that components execute in, by default B<HTML::Mason::Commands>:

    { package HTML::Mason::Commands;
      use vars qw($dbh %session);
    }

Alternatively you can use the L<Compiler's
allow_globals|HTML::Mason::Compiler/allow_globals> parameter:

    my $ah = new HTML::Mason::ApacheHandler (..., allow_globals => [qw($dbh %session)]);

The only advantage to C<allow_globals> is that it will do the right
thing if you've chosen a different package for components to run in
(via the L<Compiler::ToObject
in_package|HTML::Mason::Compiler::ToObject/in_package> parameter.)

Similarly, to initialize the variable in C<handler.pl>, you need to
set it in the component package:

    $HTML::Mason::Commands::dbh = DBI->connect(...);

Alternatively you can use the L<Interp's
set_global|HTML::Mason::Interp/set_global> method:

    $ah->interp->set_global(dbh => DBI->connect(...));

Again, C<set_global> will do the right thing if you've chosen a
different package for components.

Now when referring to these globals inside components, you can use the
plain variable name:

    $dbh->prepare...

=head2 Declining image requests

Mason should be prevented from serving images, tarballs, and other
binary files as regular components. Such a file may inadvertently
contain a Mason character sequence such as "<%", causing an error.

There are several ways to restrict which file types are handled by Mason.
One way is with a line at the top of handler(), e.g.:

    return -1 if $r->content_type && $r->content_type !~ m|^text/|i;

This line allows text/html and text/plain to pass through but not much
else.  It is included (commented out) in the default C<handler.pl>.

Another way is specifying a filename pattern in the Apache
configuration, e.g.:

    <FilesMatch "(\.html|\.txt|^[^\.]+)$">
     SetHandler perl-script
     PerlHandler HTML::Mason
    </FilesMatch>

This directs Mason to handle only files with .html or .txt extension,
as well as those files with no extension.

=head2 Securing top-level components

Users may exploit a server-side scripting environment by invoking
scripts with malicious or unintended arguments. Mason administrators
need to be particularly wary of this because of the tendency to break
out "subroutines" into individually accessible file components.

For example, a Mason developer might create a helpful shared component
for performing sql queries:

    $m->comp('sql_select', table=>'employee', where=>'id=315');

This is a perfectly reasonable component to create and call internally,
but clearly presents a security risk if accessible via URL:

    http://www.foo.com/sql_select?table=credit_cards&where=*

Of course a web user would have to obtain the name of this component
through guesswork or other means, but obscurity alone does not
properly secure a system.  Rather, you should choose a site-wide
policy for distinguishing top-level components from private
components, and make sure your developers stick to this policy. You
can then prevent private components from being served.

One solution is to place all private components inside a directory,
say /private, that lies under the component root but outside the
document root.

Another solution is to decide on a naming convention, for example,
that all private components begin with "_", or that all top-level
components must end in ".html". Then turn all private requests away
with a 404 NOT_FOUND (rather than, say, a 403 FORBIDDEN which would
provide more information than necessary). Use either an Apache directive

    PerlModule Apache::Constants
    <FilesMatch "^_">
    SetHandler perl-script
    PerlInitHandler Apache::Constants::NOT_FOUND
    </FilesMatch>

or a C<handler.pl> directive:

    return 404 if $r->filename =~ m{^_[^/]+$};

Even after you've safely protected internal components, top-level
components that process arguments (such as form handlers) still
present a risk. Users can invoke such a component with arbitrary
argument values via a handcrafted query string. Always check incoming
arguments for validity and never place argument values directly into
SQL, shell commands, etc.

If you would like to use taint mode, be sure to set the compiler's
taint_mode parameter to a true value, so that it will know to untaint
component source coming from the filesystem.

=head2 Allowing directory requests

By default Mason will decline requests for directories, leaving Apache
to serve up a directory index or a FORBIDDEN as appropriate.
Unfortunately this rule applies even if there is a dhandler in the
directory: /foo/bar/dhandler does not get a chance to
handle a request for /foo/bar/.

If you would like Mason to handle directory requests, do the
following:

1. Set the L<ApacheHandler's
   decline_dirs|HTML::Mason::ApacheHandler/decline_dirs> parameter to
   0.

2. If your C<handler.pl> contains the standard "return -1" line to
decline non-text requests (as given in the previous section), add a
clause allowing directory types:

    return -1 if $r->content_type && $r->content_type !~ m|^text/|i
                 && $r->content_type !~ m|directory$|i;

The dhandler that catches a directory request is responsible for
setting a reasonable content type.

=head1 STANDARD FEATURES

This section explains how standard Mason features work and how to
administer them.

=head2 Data caching

Data caching is implemented with DeWitt Clinton's C<Cache::Cache>
module.  For full understanding of this section you should read the
documentation for C<Cache::Cache> as well as for relevant subclasses
(e.g. C<Cache::FileCache>).

=over 4

=item Cache files

By default, C<Cache::FileCache> is the subclass used for data caching,
although this may be overriden by the developer. C<Cache::FileCache>
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
C<data_dir/cache>. The name of the cache subdirectory for a component
is determined by the function C<HTML::Mason::Utils::data_cache_namespace>.

=item Default constructor options

Ordinarily, when C<< $m->cache >> is called, Mason passes to the cache
constructor the C<namespace>, C<username>, and C<cache_root> options,
along with any other options given in the C<< $m->cache >> method.

You may specify other default constructor options with the L<Interp's
data_cache_defaults|HTML::Mason::Interp/data_cache_defaults> parameter.  For
example,

    data_cache_defaults =>
       { cache_class => 'SizeAwareFileCache',
         cache_depth => 2,
         default_expires_in => '1 hour' }

Any options passed to individual C<< $m->cache >> calls override these
defaults.

=item Disabling data caching

If for some reason you want to disable data caching entirely, use

    data_cache_defaults => {cache_class => 'NullCache'}

This subclass faithfully implements the cache API but never stores data.

=back

=head1 PERFORMANCE TUNING

This section explains Mason's various performance enhancements and how
to administer them.

=head2 Code cache

When Mason loads a component, it places it in a memory cache.

The maximum size of the cache is specified with the L<Interp's
code_cache_max_size|HTML::Mason::Interp/code_cache_max_size>
parameter; default is 10MB.  When the cache fills up, Mason frees up
space by discarding a number of 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.  Very
large components (over 20% of the maximum cache size) never get
cached, on the theory that they would force out too many other
components.

Note that the "size" of a component in memory cannot literally be
measured.  It is estimated by the length of the source text plus some
overhead.  Your process growth will not match the code cache
size exactly.

You can prepopulate the cache with components that you know will be
accessed often; see L<Preloading|"Preloading">. Note that preloaded components
possess no special status in the cache and can be discarded like any
others.

Naturally, a cache entry is invalidated if the corresponding component
source file changes.

To turn off code caching completely, set L<Interp's
code_cache_max_size|HTML::Mason::Interp/code_cache_max_size> to 0.

=head2 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.

As a secondary, longer-term cache mechanism, Mason stores a compiled
form of each component in an object file under
C<data_dir/obj/I<component-path>>. 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.

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.

It should be noted that as of version 1.10, line numbers in error are
reported relative to the source file.

If you change any Compiler or Lexer options, you must remove object
files previously created under that compiler or lexer for the changes
to take effect.

If for some reason you don't want Mason to create object files, set
the L<Interp's use_object_files|HTML::Mason::Interp/use_object_files>
parameter to 0.

=head2 Static source mode

As described above, Mason checks the timestamp of a component source
file every time that component is called. This can add up to a lot
of file stats.

If you have a live site with infrequent and well-controlled updates,
you may choose to use
L<static_source|HTML::Mason::Interp/static_source> mode. In this mode
Mason will not check source timestamps when it uses an in-memory cache
or object file.  The disadvantage is that you must remove object files
and restart the server whenever you change component source; however
this process can be easily automated.

=head2 Preloading

You can tell Mason to preload a set of components in the parent
process, rather than loading them on demand, using the L<Interp's
preloads|HTML::Mason::Interp/preloads> parameter.  Each child server
will start with those components loaded in the memory cache. The
trade-offs are:

=over

=item time

a small one-time startup cost, but children save time by not
having to load the components

=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.

=back

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.)

=head1 ERROR REPORTING

When an error occurs, Mason can respond by:

=over

=item *

showing a detailed error message in the browser in HTML.

=item *

die'ing, which sends a 501 to the browser and lets the error message go to the
error logs.

=back

The first option is ideal for development, where you want
immediate feedback on the error.  The second option is usually desired
for production so that users are not exposed to messy error messages. 
You control this option by setting request->error_mode to "output"
or "fatal" respectively.

=head1 CONFIGURING VIRTUAL SITES

These examples extend the single site configurations given so far.

=head2 Multiple sites, one component root

If you want to share some components between your sites, arrange your
httpd.conf so that all DocumentRoots live under a single component space:

    # Web site #1
    <VirtualHost www.site1.com>
        DocumentRoot /usr/local/www/htdocs/site1
        <Location />
            SetHandler perl-script
            PerlHandler HTML::Mason::ApacheHandler
        </Location>
    </VirtualHost>

    # Web site #2
    <VirtualHost www.site2.com>
        DocumentRoot /usr/local/www/htdocs/site2
        <Location />
            SetHandler perl-script
            PerlHandler HTML::Mason::ApacheHandler
        </Location>
    </VirtualHost>

    # Mason configuration
    PerlSetVar MasonCompRoot "/usr/local/www/htdocs"
    PerlSetVar MasonDataDir "/usr/local/mason"
    PerlModule HTML::Mason::ApacheHandler

The directory structure for this scenario might look like:

    /usr/local/www/htdocs/  # component root
        +- shared/          # shared components
        +- site1/           # DocumentRoot for first site
        +- site2/           # DocumentRoot for second site

Incoming URLs for each site can only request components in their
respective DocumentRoots, while components internally can call other
components anywhere in the component space. The shared/ directory
is a private directory for use by components, inaccessible from
the Web.

=head2 Multiple sites, multiple component roots

Sometimes your sites need to have completely distinct component
hierarchies, e.g. if you are providing Mason ISP services for multiple
users. In this case the component root must change depending on the
site requested. Since you can't change an interpreter's component root
dynamically, you need to maintain separate Mason objects for each
site in your C<handler.pl>:

    my %ah;
    foreach my $site (qw(site1 site2 site3)) {
        $ah{$site} = new HTML::Mason::ApacheHandler
            (comp_root => "/usr/local/www/$site",
             data_dir => "/usr/local/mason/$site");
    }

    ...

    sub handler {
        my ($r) = @_;
        my $site = $r->dir_config('site');
        $ah{$site}->handle_request($r);
    }

We assume each virtual server configuration section has a

    PerlSetVar site <site_name>

Above we pre-create all Mason objects in the parent. Another scheme is to
create objects on demand in the child:

    my %ah;

    ...

    sub handler {
        my ($r) = @_;
        my $site = $r->dir_config('site');
        unless exists($ah{$site}) {
            # get comp_root from PerlSetVar as well
            my $comp_root = $r->dir_config('comp_root');
            $ah{$site} = new HTML::Mason::ApacheHandler(comp_root=>$comp_root,...);
        }
    }

The advantage of the second scheme is that you don't have to hardcode
as much information in the C<handler.pl>. The disadvantage is a slight
memory and performance impact. On development servers this shouldn't
matter; on production servers you may wish to profile the two schemes.

=head1 NON-WEB MASON

While most people use Mason for dynamic web applications, that isn't
all you can do with it.

There are some differences worth briefly noting when using Mason
outside the web.

=head2 The Component Root

Both the ApacheHandler and CGIHandler modules provide reasonable
default component roots when none is provided by the user.

When using Mason outside the web, the default component root is simply
the system's root directory.  If you do not provide your own component
root, Mason will allow you to use relative paths in calls to the
L<Interp's load|HTML::Mason::Interp/load> method, in which case the
path will be assumed to be relative to the current working directory.

=head1 AUTHORS

Jonathan Swartz <swartz@pobox.com>, Dave Rolsky <autarch@urth.org>, Ken Williams <ken@mathforum.org>

=head1 SEE ALSO

L<HTML::Mason|HTML::Mason>,
L<HTML::Mason::Interp|HTML::Mason::Interp>,
L<HTML::Mason::ApacheHandler|HTML::Mason::ApacheHandler>,
L<HTML::Mason::Lexer|HTML::Mason::Lexer>,
L<HTML::Mason::Compiler|HTML::Mason::Compiler>

=cut
