Chapter 9:  Introduction to Content Delivery


The modules that provide basic content delivery features are compiled into Stronghold by default. This chapter shows you how to


Server-Side Imagemaps

Imagemaps are files that define coordinates on an image as links. A single imagemap can act as a link to several different destinations, depending on which part of the image a user clicks. While most browsers now support client-side imagemaps, server-side imaginable work with all browsers that support images. Stronghold has an imagemap module that processes server-side imagemaps independent of the CGI module.

To enable imagemap handling

With the imagemap handler in place, you can place an image in an HTML files and then create an imagemap file that defines the shapes, coordinates, and destinations of its links. When you link the HTML image tag to the imagemap file, the image becomes an imagemap.

A linked region can take one of four shapes: polygon, circle, rectangle, or point. Your imagemap file must define these parameters:

An imagemap file consists of a list of directives that define these parameters. There are six imagemap directives:

Directive Description

base

The value of base is a URL, and any relative URLs that appear in the imagemap file are interpreted relative to this one. If base is not specified, the default is the root document for this domain. Be sure to include a trailing slash if necessary.

default

This directive specifies the action required if a user clicks an unmapped region of an image. Unless the ImapDefault directive specifies otherwise, the default value is "nocontent," meaning that nothing happens when an unmapped region is clicked.

poly

All shape directives take a value followed by a list of coordinates. A polygon can have from 3 to 100 points in its coordinate list.

circle

Two coordinates are required for a circle: the center point and a point on the circle itself.

rect

Two coordinates are required for a rectangle: the upper left corner point and the lower right corner point.

point

The point directive takes a single coordinate.

For any directive, there are six possible values:

Value Description

URL

A relative or absolute URL that specifies the destination of a link.

map

Unless the ImapValue directive is set to "none," map causes Stronghold to generate an HTML index of the shapes and links contained in the imagemap file, much like a directory index.

menu

Like map, this value causes Stronghold to create an HTML index of the shapes and links in the imagemap file.

referer

The referer value creates a link to the page indicated in the Referer header of the last client request.

nocontent

Sends the 204 (No Content) status code, which causes the client to take no action and keep displaying the current page.

error

Sends the 500 (Internal Server Error) status code. This value is used only with the default directive.

For example, imagine that you want to use this image as a navigation bar:


Extracted pic [1]
Figure 9-2:  A Navigation Bar

Using an image-editing application such as Photoshop, you must first determine the shapes and pixel coordinates of the linked regions on the image:


Extracted pic [2]
Figure 9-3:  Coordinates on an Imagemap

The imagemap file for this image would look something like this:

base http://www.your_host.org/
default map
poly previous/ 14,36 66,16 66,60
rect products/ 80,18 196,46
circle help/ 245,40 270,60
rect services/ 293,18 410,46
poly next/ 425,16 425,60 478,38

In this example, the URLs specified in the shape definitions are all relative to
http://www.your_host.org/. If a user clicks an unmapped region of the navigation bar, the server returns a linked list of the imagemap's destinations. The linked shapes are defined by x and y pixel coordinates. Polygons require the coordinates of each of their corners, while rectangles only require those of two opposing corners and circles require those of a radius.

With the imagemap file in place, you must link the HTML image reference to it, like this:

<a href=/maps/navigation.map><img src=navbar.gif ISMAP></a>

Test the imagemap by viewing it in your browser and moving the mouse pointer over it. As the pointer passes over a linked region, the destination of the link appears in the browser's status bar. Click an unmapped region to see the linked list defined in the imagemap file. Optionally, you can add quoted description strings to the end of each region definition to make the linked list more descriptive:

rect products/ 80,18 196,46 "BetaCom Products"


Content Negotiation

The World Wide Web is populated by an enormous variety of users speaking many different languages. To accommodate only the largest segment of users, you can construct a site in English or the language most widely used by your audience, but this alienates other users. To compensate, you can use content negotiation to cater to many varieties of users.

Content negotiation involves an exchange of information between client and server. Under HTTP/1.1, a client's initial request includes headers that specify which file types the client can handle:

GET /home/ HTTP/1.1
Connection: Keep-Alive
User-Agent: Mozilla/3.0 (WinNT; I)
Host: www.host.com
Accept: text/html, text/plain, image/gif, image/jpeg, image/pjpeg ...
Accept-Encoding: compress, gzip, winzip
Accept-Language en; q=1.0, de; q=.8, fr; q=.6,

The request includes a list of acceptable media type in the Accept field, acceptable encoding types in the Accept-Encoding field, and acceptable languages in the Accept-Language field. The numbers in the Accept-Language field are q-values, and they rank the language types according to the user's preference. In this scenario, English is the preferred language, but German and French are also acceptable.

If the root document for the requested directory is only available in a language and format listed in the request, the server simply returns the document. However, imagine that the only root document for /home/happens to be index.pdf.jp, a Portable Document Format (PDF) file in Japanese. Since the server knows from the request that the client cannot handle this file, it responds like this:

HTTP/1.1 406 Not Acceptable

Most requests can be partially fulfilled. For example, imagine that the only root document for /home/ is index.html.en, and that the file references a QuickTime file. All browsers support HTML, but not all have QuickTime plugins. Even if video/quicktime is not among the values in the Accept header, the server returns the HTML file and the client displays a broken link where the animation would have appeared.

Content negotiation provides a mechanism for preventing 406 status codes and broken links by selecting from among several versions of the same file based on the criteria provided in the client request. Although this requires maintaining and organizing parallel file versions, the result is a clean, universally accessible site.


Server-Side Includes

Server-side includes (SSIs) are simple, HTML-embedded directives that instruct Stronghold to execute a program or include data in the HTML document. As a shorthand alternative to CGI, server-side includes can be handy. However, like CGI, they should be used with caution and an eye for security risks.

Since server-side includes are directives for the server, Stronghold must parse them before it delivers the document that contains them. Scanning every requested file for server-side includes can create considerable processor overhead. Instead, you can instruct Stronghold to look for server-side includes only in certain files by including this line in your httpd.conf file:

AddType text/x-server-parsed-html .shtml

When you start Stronghold with this configuration, it only looks for SSI directives when a client requests a file with the .shtml extension. When it finds them, it parses the directives, carries out their instructions, replaces them with their output, and sends the finished document to the client.

Syntax and Directives

All SSI directives follow this format:

<!--#directive parameter="value"-->

Directives can have more than one parameter, and multiple parameters are separated by white space. The valid SSI directives are as follows:

echo

Syntax: echo var="environment-variable"
Context: HTML
Echo inserts the value of one or more SSI environment variables.

include

Syntax: include file|virtual="path"
Context: HTML
The include directive inserts the text of another document, specified either as a file or a virtual file. Path must be relative to the current document in the case of a file, or it can be a virtual path. For example:
<!--#include file="sample.html"-->
<!--#include virtual="/virtual/sample.html"-->

fsize

Syntax: fsize file="path"
Context: HTML
The fsize directive inserts the size of the file specified by path, in bytes. For example:
This file is <!--#fsize file="example.ps"--> bytes.

flastmod

Syntax: flasmodfile="path
Context: HTML

Similar to fsize, flastmod inserts the modification date for the file specified by path, For example:

This file was last modified on <!--#flastmod file="example.html"-->

exec

Syntax: execcmd |cgi="str"
Context: HTML

The exec directive executes a program, either a command-line string or a CGI program, and inserts the output into the current document. For example:

Finger C2Net's president:
<!--#exec cmd="/bin/finger sameer@c2.net"-->
This page has been accessed
<!--#exec cgi="/cgi-bin/counter.pl"--> times.


The exec directive poses a considerable security risk, since it allows users to execute any program on the server platform. As a precaution, we recommend that you set the Options configuration directive to "IncludeNOEXEC."

config

Syntax: config errmsg|sizefmt|timefmt="string"
Context: HTML
You can use the config directive to modify the default SSI behavior. The parameters are as follows:

Format Code Description

%a

Abbreviated day of the week, such as "Sun" for Sunday

%A

Unabbreviated day of the week

%b

Abbreviated month, such as "Jan" for January

%B

Unabbreviated month

%d

Two-digit, numerical day of the month, such as "01"

%D

Numerical month, day, and year in four-digit format, such as "01/24/1997"

%e

Numerical day, such as "1"

%H

24-hour clock hour, such as "17"

%I

12-hour clock hour, such as "11"

%j

Numerical day of the year, such as "278"

%m

Numerical month, such as "11"

%M

Minutes, such as "08"

%p

am or pm

%r

Time, such as "08:23:17 am"

%S

Seconds, such as "56"

%T

24-hour time, such as "23:54:56"

%U

Week of the year, such as "47"

%w

Numerical day of the week, such as "0" for Sunday and "7" for Saturday

%y

Year of the current century, such as "97"

%z

Abbreviated time zone, such as "PST"

printenv

Syntax: printenv
Context: HTML
This directive prints a complete list of all existing SSI variables and their values. It has no attributes. For example:
<!--#printenv-->

set

Syntax: set var="variable" value="value"
Context: HTML
This directive sets the value of an environment variable. For example:
<!--#set var="country" value="Liberia"-->

Flow Control Elements

Stronghold implements Extended SSI, which includes flow control elements much like the ones used in programming languages. With flow control, you can create more sophisticated SSI scripts.

There are four flow control elements:

<!--#if expr="test-condition"-->
<!--#elif expr="test-condition"-->
<!--#else-->
<!--#endif-->

The test-condition is one of the following:

Test Condition Description

string

True if the string is not empty

string1=string2

True if string1 matches string2

string1!=string2

True if string1 does not match string2

string1>string2

True if string1 is greater than string2

string1>=string2

True if string1 is greater than or equal to string2

string1<string2

True if string1 is less than string2

string1<=string2

True if string1 is less than or equal to string2

(test-condition)

True if test-condition is true

!test-condition

True if test-condition is false

test-condition1 && test-condition2

True if both test-condition1 and test-condition2 are true

test-condition1 || test-condition2

True if either test-condition1 or test-condition2 is true

SSI Environment Variables

In a server-side include string, you can use any environment variables available to the server, including the CGI variables listed in "CGI Error Logging" on page 10-2. SSI also has its own environment variables, listed here.

DOCUMENT_NAME

The filename of the current HTML document. For example:

This file is called <!--#echo var="DOCUMENT_NAME"-->.

DOCUMENT_URL

The URL of the current file. For example:
This document is located at <!--#echo var="DOCUMENT_URL"-->.

QUERY_STRING_UNESCAPED

An unencoded query string whose metacharacters are escaped with a backslash (\).

DATE_LOCAL

The local date and time. For example:

Here in San Francisco, it is now <!--#echo var="DATE_LOCAL"-->

DATE_GMT

The current Greenwich Mean Time. For example:

The current time is <!--#echo var="DATE_GMT"--> GMT.

LAST_MODIFIED

The date and time when the current file was last modified. For example:

I last modified this page on <!--#echo var="LAST_MODIFIED"-->.

Tracking Sessions

Since HTTP implements single, self-contained transactions, it provides no built-in way to track a whole session, which consists of more than one transaction. Exchanges of requests and responses occur individually, and each exchange appears to be unrelated to the last. However, today's complex interactive Web applications require session tracking in order to implement features such as site customization, preference tracking, and so on.

For example, many online commerce sites implement a "shopping basket" that keeps track of items each user chooses, compiling a list of all the items chosen by each user during the course of his or her entire session. Without session tracking, a shopper would only be able to purchase one item at a time through a single, self-contained HTTP transaction. To keep track of requests that originate with the same client, servers set session identifiers that accompany each request and response. Requests with the same session ID belong to the same session.

There are two ways to perform session tracking:

Session Tracking with Cookies

Cookies, supported by the mod_usertrack module, are session ID's that are exchanged as HTTP metainformation. When the Cookie Tracking directive is set to "on", Stronghold automatically generates a session ID whenever it receives a request that does not already include a cookie. Depending on whether it appears inside a container, Cookie Tracking can apply to the whole server, a single virtual host, or only an object such as a directory or file. A session that uses cookies works like this:

# Set-Cookie name=value; expires=date; path=pathname;domain=domain-name; secure

Stronghold sets only the name field and the domain field, unless httpd.conf contains the

CookieExpires directive. Without this directive, cookies are deleted when the client quits and Stronghold issues a new one at the beginning of the next session. When CookieExpires is set, Stronghold sends the expires field and the client saves the cookie until it expires.

Taking advantage of cookies to produce dynamic, customized content requires external programs that control content based on session ID's. Whenever a cookie is set for the current session, each client request includes the Cookie HTTP header. For example,

cookie:name-gv427516826238200473

By reading the HTTP_COOKIE environment variable, a program can track related requests and produce dynamic content based on multiple requests over the course of a session.

The CustomLog directive sets the path and format of any log. It can be used to log cookies for a file. For example,

Costom logs/clickstream "% (cookie) i %r %t"

In this example, each entry in the clickstream log file shows the contents of the Cookie header, the first line of the request, and the time. If you like, you can create a more detailed cookie log, or combine cookie logging with another log.

Session Tracking with PATH_INFO

The PATH_INFO variable places a session identification token in the URL, instead of in the response header. The client then uses the GET request method to communicate its token to the server, instead of the Cookie header described in the previous section. This method accommodates older browsers that do not support cookies, as well as user who do not accept cookies.

For each initial request, a program must generate a new token, embedded in the URL of every link. When the user follows a link, its URL tells the program to generate another page with the same token embedded in its links. The token is passed from page to page throughout the session.


Dynamic Content Delivery

Dynamic content delivery is the publication of variable content and comes in a variety of forms. It may be content from a database or other non-HTML source, frequently-updated content, user-customized content, and so on. The content delivery method you choose depends on the complexity, location, time-sensitivity, format, and security of the data you want to provide to Web users. Stronghold comes with a number of modules that provide different types of dynamic content delivery: