It's Mod. It's Layout. Any Questions?

by Brian Aker

Like most adventures into open source, mod_layout began as a need. Around 1997, I was working on a web site called the Virtual Hospital (http://www.vh.org/). At the time, we were using Netscape's Fast Track server. I really wanted to switch over to Apache but had to overcome two hurdles. First, we had to get management to accept that it would be easy to find people who knew how to configure Apache (Netscape's graphical interface seemed to create a belief that it would be easy to configure and maintain) and, second, Netscape could do footers. The Netscape server supports footers by allowing you to arbitrarily add HTML to the end of any document that it is processing. This is far from perfect, but it serves the basic needs of most sites.

The first hurdle was easy to clear, seeing how we had to edit the Netscape server's configuration file consistently, and with so little documentation available on its file format, we found that maintenance quickly became a chore.

The second problem was solved by creating a custom handler. The solution was a small application written in C that was called for every HTML document. While this worked, it had a number of problems. For example, we now had an application being run a couple of times every second. This also didn't solve the problem of our CGI scripts, which still had to be modified so their output matched that of the HTML handler. This was far from an ideal solution.

I kept running into similar problems as I worked on different web sites. Someone would come along and want copyrights, headers or something similar applied to all documents on their site, and, typically, they would present me with yet another new web site technology for creating content. They would also want to do this without changing the content of their site, and it had to be easy to update and modify.

To answer these demands, I created ModLayout. ModLayout determines whether to handle a document by looking at the handler and mime type. For instance, if you wish to handle PHP4 scripts, you would use the directive LayoutHandler with the argument application/x-http-php. ModLayout handles most of the common MIME types without the need to specify the handler in Apache's configuration file; these can be disabled with “LayoutDefaultHandlers Off”, and you can then add back in what you want to have wrapped. Often sites will have specific documents that they don't want wrapped. For this, you can use the directive “LayoutIgnoreURI”, and there are also ignore directives for removing only the header, footer or HTTP header.

ModLayout provides three additional stages to the Apache process. It provides a header stage, a footer stage and a stage for doing HTTP headers. If you need to create HTTP headers dynamically for all documents, ModLayout will let you do this. Headers and footers occur on the HTML page before and after the original document.

There are three types of headers and footers. You can either add a simple piece of text:

LayoutHeader "Sample header"
LayoutFooter "Sample Footer"

or you can insert entire files by using:

LayoutHeader /usr/local/apache/htdocs/header.html
LayoutFooter /usr/local/apache/htdocs/footer.html
or by URI:
LayoutHeader /header.pl
LayoutFooter /footer.php
The above examples will work when you have simple requirements for headers and footers. The first two examples also work well because their content is cached in the Apache process. If you need something that is dynamic, however, you can use the URI example. ModLayout does not care about the type of URI used, it can be anything from simple CGIs and SSI to complex applications written in Perl, PHP or Java. Custom modules written in C using the Apache API can also be used. If you desire to just use only HTML but not have it cached, you can simply specify its URI and not its full path. ModLayout also provides additional environment variables for URIs being called as headers and footers. These supply information about the state of the original document. One of ModLayout's great advantages is that it works with any form of content and is language neutral.

A common use of ModLayout is to attach a copyright notice to all of the documents on a site. To do this, you could use the following:

<VirtualHost www.example.com>
     <...insert normal content..>
     LayoutFooter "<P>Copyright Example.com 1995-200"
     LayoutHandler "application/x-httpd-php"
</VirtualHost>

The above would insert the text at the bottom of every document on the www.example.com virtual host for all of the default handlers, including HTML pages and CGI scripts, and also on any PHP4 script present.

If you want to tack on the date the original document was last modified, you could insert the following into a PHP document, and save it as last-modified.php.

<?php
     echo("Copyright 2000 FooBar INC. <BR> Last Modified");
     echo ($LAYOUT_LAST_MODIFIED);
?>

and change the LayoutFooter directive to /last_modified.php.

Now, let's look at a more complex problem. Let's say you wanted to create a custom look and feel for a given site that was enforced by the web server, the following would serve as an example:

<VirtualHost www.example.com>
     <...insert normal content..>
     LayoutHeader "/header.php"
     LayoutFooter "/footer.pl"
     LayoutIgnoreHeaderURI "/index.html"
     LayoutHandler "application/x-httpd-php"
</VirtualHost>

In the above example, the site would have a custom header created by a PHP script and a Perl script running as the footer. All default handlers are wrapped along with any PHP scripts that are on the site. Notice that the index.html document will not be wrapped though, since most sites have a custom front page but want to have a default look for internal pages on the site. You can also use something like mod_random and its random quote feature to create your own banner ad system.

When using mod_random, the thing to remember when creating headers is that you need to be careful not to create invalid HTML (which, thankfully, most browsers will handle). But, if you are enforcing a look and feel on pages that outside users are creating, they can easily end up with a messy output.

Keep in mind that inserting any HTML before a page with frames will break the frames. At the moment, the solution most people employ is to use footers and/or create floating Javascript boxes). In a future version, you will be able to turn off headers, footers and wrapped content by directives received from a URI that is called from a header or footer.

For sites that have a more complex need, see Listing 1.

Listing 1

The example provided in Listing 1 is currently used for http://www.tangent.org/. This allows for web site document wrapping which affects the main document root content but leaves user's home pages alone. While the entire site uses the same footer, the header has been changed for different sections. ModRandom is used for inserting random quotes into the footers (thankfully these are just from The Simpsons and nothing annoying, like an ad banner).

Controlling ModLayout with Directory, Virtualhost and Location tags, allows you to work out some fairly complicated logic. You can also control what creates the HTTP headers through LayoutHTTPOverride and by creating your own dynamic HTTP headers with LayoutHTTPHeader. At the moment, there are about 24 total directives and ModLayout is under fairly active development, (developer releases occur about once a month and full releases about every two months). Feature suggestions are encouraged, and there is a mailing list for discussing features, HOWTOs and bugs. For more information, check out the Modlayout home page, http://tangent.org/mod_layout/.

Although ModLayout began as a solution to a problem that I kept running into, today it is very much the result of people writing in and requesting new features. It's future direction will pretty much depend on what people ask for and need.

Brian Aker is “getting paid to work on a BBS. Imagine that.” The BBS is the famous http://www.slashdot.org/, where he is a “database thug and Apache guy.” He is also the author of mod_random and other Apache modules.

Load Disqus comments