The Server Side Includes (SSI) scripting language triggers further processing on your static web pages. The server parses an HTML page looking for SSI directives. It then processes those directives and creates a new page that in turn is passed back to the user. The modification directives that SSI supplies can do simple text replacement or can call programs to supply the text. The range of possibilities is endless for SSI, and you will see an example of each SSI directive in this chapter.
Getting Started
SSI Configuration Statements
After adding these statements, you will need to restart the HTTP server to activate them.
You may also have to add Includes in Options Indexes FollowSymLinks to make this work with the default settings, as shown here:
The shtml portion of the AddHandler statement specifies the file extension that will be used to tell the server which HTML files need to be parsed for SSI directives. Only files with this extension will be parsed for SSI directives.
SSI Configuration Statements with XBitHack Directive
When configured this way, the .shtml file extensions will be ignored, and only files with the owner execute bit set will be parsed for SSI directives.
There are additional statements that can be placed in the HTTP server configuration file that will alter the processing of the file by SSI, but we will look at those later in this chapter.
SSI directives placed in the output of CGI programs will not be processed. This because no filename is associated with the CGI output, so the server has no way to know whether it needs to be parsed.
The pound sign (#) is what identifies this comment as an SSI directive. If a directive accepts attributes, then the attributes should follow the directive name. There are eight SSI directives plus some miscellaneous ones, and the following sections describe each one.
The config SSI Directive
errmg | This is the message sent back to the client when an error occurs during document parsing. |
---|---|
sizefmt | This is the value to use when displaying the size of a file. Valid values are bytes or abbrev for a size in kilobytes or megabytes as appropriate. |
timefmt | This value is the same as passed to the C function strftime() library routine. |
An Example HTML Page Using the SSI errmsg Directive
As you can see, this SSI directive can save you a lot of work updating content in your HTML pages. When the file is modified, the file size and update timestamp can also be updated automatically.
The error message produced can also be modified throughout the document to make it specific to errors in different parts of the document.
The echo SSI Directive
var | This is the name of the environment to be printed. Only the following environment variables may be specified: DATE_GMT, DATE_LOCAL, DOCUMENT_NAME, DOCUMENT_URI, and LAST_MODIFIED. |
An Example of the SSI echo Directive
Although the number of environment variables is restricted, the echo directive is still a convenient directive to use when needed. It can still save time and reduce the number of times an HTML file is updated.
The exec SSI Directive
The exec SSI directive executes either a shell command or a CGI script. A prudent webmaster will put the option IncludesNOEXEC in the server config file to disable this SSI directive. But if available, it allows the output from a shell command, program, or CGI script to be included at that point in the HTML file.
cgi | This is a %-encoded URL relative path to the CGI script. If the path does not include a leading slash, it is taken to be relative to the current document. The document is invoked as a CGI script even if the server does not recognize it as a CGI program. All the rules for a directory containing a CGI script must be observed. If suexec is turned on, it will be enforced. The QUERY_STRING and PATH_INFO environment variables passed to the original document will be passed in turn to the specified CGI script as well as the include variables. Note that the include virtual SSI directive should be used in preference to the exec directive if possible. |
---|---|
cmd | The server prepends the /bin/sh string to the front of this attribute and then attempts to execute it. The include variables are available to the command, and its output of the program will be included in the HTML file at that point. |
The documentation for the SSI exec directive is not exactly clear. You should be aware that whatever HTML appears in the original HTML request will be thrown away on successful execution of the code being called. This is true for both the cgi and cmd attributes.
Example Code for the SSI Directives exec cgi and exec cmd
Note that the only thing the documents in Listing 4-5 do is call the SSI directives exec cgi and exec cmd. These commands will in turn call a script to output the actual HTML for the request.
The Scripts Called by the SSI Directives in Listing 4-5
The code in Listing 4-6 is responsible for all the output from each request. The Python script is called for the first request, and the shell script is called from the second request.
Figure 4-3 shows the output in the browser. You cannot quite see it, but the request field indicates that this output came from the original HTML request and not the scripts that were called from the HTML. This hides the fact that a CGI or CMD SSI directive was called to actually create the output dynamically. Even if you look at the source for the document, you cannot tell it did not come from the HTML request. This could be useful in hiding just how the output HTML was created.
You should also note that the QUERY_STRING and CONTEXT_DOCUMENT_ROOT are the values passed to the original HTML request and remain unmodified when passed to the cgi and cmd attributes. There could be other environment variables that have original values as well. This can be useful when the directory where the HTML file resides is important to the request.
It is preferable to use the include SSI directive instead of the exec directive wherever possible as the potential of a security failure goes up when this exec directive is used.
The fsize SSI Directive
file | This is a path/filename relative to the directory containing the current HTML file. |
---|---|
virtual | The %-encoded URL path relative to the DOCUMENT_ROOT from the server config file. If the specification does not begin with a slash (/), it means that it is relative to the current HTML document. |
The HTML Document Containing the fsize Directive
Output from the fsize directive appears inline within the output HTML page. The example in Figure 4-4 has paragraph tags surrounding the size so that it stands out in the example. Also, the size of the original HTML file is small, less than a kilobyte in size, which means there is not a qualifier for the size.
The flastmod SSI Directive
file | This is a path/filename relative to the directory containing the current HTML file. |
---|---|
virtual | This is the %-encoded URL path relative to the DOCUMENT_ROOT from the server config file. If the specification does not begin with a slash (/), it means that it is relative to the current HTML document. |
The HTML Document Containing the flastmod Directive
Output from the flastmod directive appears inline within the output HTML page. The example in Figure 4-5 has paragraph tags surrounding the timestamp so that it stands out in the example. The timestamp is shown using the default format.
The include SSI Directive
file | This is a path/filename relative to the directory containing the current HTML file. |
---|---|
virtual | The %-encoded URL path relative to the DOCUMENT_ROOT from the server config file. If the specification does not begin with a slash (/), it means that it is relative to the current HTML document. |
The HTML Document Containing the flastmod Directive
Output from the include directive appears inline within the output HTML page. You should ensure that the included content is a real HTML fragment and not an entire HTML page.
Please note it is not possible to call a script using this directive. Also, the included file may not contain other SSI directives as they will be ignored.
Additional SSI Directives
We will be introducing several SSI directives and concepts in this section because they are all closely related. This will include the set directive, additional variables that can be used in your SSI HTML pages, and conditional directives for selecting sets of phrases to be included in your document.
You should note that all the directives and variables described in this section are available in Apache version 2.4 and newer. They may not be available in your HTTP server.
The SSI set Directive
The two attributes var and value describe the name of the variable and its assigned value, respectively. In addition, there are two more attributes that are used only occasionally. They are decoding and encoding and are used for encoding and decoding the value passed to the variable name. There are several values you can pass in these attributes depending on the encoding you want to translate to/from the value attribute. You should see the Apache documentation before attempting to use them.
One last thing of note is to not use uppercase for your variable names. Apache reserves the right to add new variables to the current list, and those names will be uppercase names.
DATE_GMT | This is the server’s current timestamp in GMT format. |
---|---|
DATE_LOCAL | This is the server’s current timestamp in the server’s local format. |
DOCUMENT_ARGS | This is the same as the CGI variable QUERY_STRING. If no arguments were passed, this will be the empty string. |
DOCUMENT_NAME | This is the filename of the current HTML file. |
DOCUMENT_PATH_INFO | This is the same the CGI PATH_INFO variable. |
DOCUMENT_URO | This is the main HTML DOCUMENT_URI. In the cases of nested includes, this is not the URI of the nested file. |
LAST_MODIFIED | This is the last modified timestamp of the main HTML file. |
QUERY_STRING_UNESCAPED | This is the unescaped value of the query string. |
USER_NAME | This is the username of the owner of the main HTML document. |
All of these variables are available to be used in the set directive as well as all the conditional directives.
An HTML Example Showing How to Use the Available Variables
The SSI Conditional Directives
The SSI conditional directives allow the user to specify HTML text to be included under certain conditions. The directives are if, elif, else, and endif. These directives operate in almost the same way as the C/C++ directives with the same names. The if directive specifies a condition, and if it is true, the text following it is included in the document. The elif directive specifies a different condition that is evaluated if the previous if or elif condition is false. The else condition includes the text that follows it if all previous conditions are false. The endif directive ends all conditional text.
Do not mix the conditional directives with the previously documented set directive. The conditional directives are all evaluated early in the parsing phase of the HTML. The set directive (as well as all other SSI directives) is evaluated in a later phase after all the conditional directives have already been evaluated. Thus, the conditional directives have no access to the variables produced by the set directive.
A Sample HTMP Page Using the Conditional Directives
The previous command is the correct way to obtain a positive result from the script. Any other name or not providing one at all will give a negative result.
The syntax of the conditional directive is simple and matches the other directives we have examined so far. There is only a single attribute, and it is used on the if and elif conditional directives. The expr attribute specifies the conditional expression to be evaluated. The syntax of this condition will be explored a little later. If the condition is true, then the text following the directive will be included. The text can include other conditional directives or and of the SSI directives. Text is included until either an elif, else, or endif SSI directive is found. If the expression is false, all the text is skipped until the next conditional directive is found.
If we examine the condition on the if directive, we see that something called the QUERY_STRING is being examined for something on the right side of the expression. The QUERY_STRING is the same as for the CGI scripts. This is surrounded by %{...} to mark it as a known variable. We will list all the known variables for conditional expressions a little later. The right side of the expression is a regular expression. This expression uses the same syntax as regular expressions in Perl 5.0. The middle operator specifies how the variables on each side are to be evaluated. We will examine all the possible operators a little later.
Table 4-1 describes all the available variables for use by the conditional directives. These are the only variables that can be used by the conditional directives.
SSI Conditional Directive Variables
Name | Description |
---|---|
HTTP_ACCEPT | Named HTTP request header variable. |
HTTP_COOKIE | Named HTTP request header variable. |
HTTP_FORWARDED | Named HTTP request header variable. |
HTTP_HOST | Named HTTP request header variable. |
HTTP_PROXY_CONNECTION | Named HTTP request header variable. |
HTTP_REFERER | Named HTTP request header variable. |
HTTP_USER_AGENT | Named HTTP request header variable. |
REQUEST_METHOD | The HTTP method of the incoming request (e.g., GET). |
REQUEST_SCHEME | The scheme part of the request’s URI. |
REQUEST_URI | The path part of the request’s URI. |
DOCUMENT_URI | Same as REQUEST_URI. |
REQUEST_FILENAME | The full local filesystem path to the file or script matching the request, if this has already been determined by the server at the time REQUEST_FILENAME is referenced. Otherwise, such as when used in virtual host context, the same value as REQUEST_URI. |
SCRIPT_FILENAME | Same as REQUEST_FILENAME. |
LAST_MODIFIED | The date and time of last modification of the file in the format 20101231235959, if this has already been determined by the server at the time LAST_MODIFIED is referenced. |
SCRIPT_USER | The username of the owner of the script. |
SCRIPT_GROUP | The group name of the group of the script. |
PATH_INFO | The trailing path name information. |
QUERY_STRING | The query string of the current request. |
IS_SUBREQ | "true" if the current request is a subrequest, "false" otherwise. |
THE_REQUEST | The complete request line (e.g., "GET /index.html HTTP/1.1"). |
REMOTE_ADDR | The IP address of the remote host. |
REMOTE_PORT | The port of the remote host (2.4.26 and later). |
REMOTE_HOST | The hostname of the remote host. |
REMOTE_USER | The name of the authenticated user, if any (not available during <If>). |
REMOTE_IDENT | The username set by mod_ident. |
SERVER_NAME | The ServerName of the current vhost. |
SERVER_PORT | The server port of the current vhost; see ServerName. |
SERVER_ADMIN | The ServerAdmin of the current vhost. |
SERVER_PROTOCOL | The protocol used by the request. |
DOCUMENT_ROOT | The DocumentRoot of the current vhost. |
AUTH_TYPE | The configured AuthType (e.g., "basic"). |
CONTENT_TYPE | The content type of the response (not available during <If>). |
HANDLER | The name of the handler creating the response. |
HTTP2 | "on" if the request uses http/2, "off" otherwise. |
HTTPS | "on" if the request uses https, "off" otherwise. |
IPV6 | "on" if the connection uses IPv6, "off" otherwise. |
REQUEST_STATUS | The HTTP error status of the request (not available during <If>). |
REQUEST_LOG_ID | The error log ID of the request (see ErrorLogFormat). |
CONN_LOG_ID | The error log ID of the connection (see ErrorLogFormat). |
CONN_REMOTE_ADDR | The peer IP address of the connection (see the mod_remoteip module). |
CONTEXT_PREFIX | Tells you how the server used an Alias directive (or a similar feature, like mod_userdir) to translate the URL path to the file system path. |
CONTEXT_DOCUMENT_ROOT | Tells you how the server used an Alias directive (or a similar feature, like mod_userdir) to translate the URL path to the file system path. |
TIME_YEAR | The current year (e.g., 2010). |
TIME_MON | The current month (01, ..., 12). |
TIME_DAY | The current day of the month (01, ...). |
TIME_HOUR | The hour part of the current time (00, ..., 23). |
TIME_MIN | The minute part of the current time. |
TIME_SEC | The second part of the current time. |
TIME_WDAY | The day of the week (starting with 0 for Sunday). |
TIME | The date and time in the format 20101231235959. |
SERVER_SOFTWARE | The server version string. |
API_VERSION | The date of the API version (module magic number). |
The variables listed in Table 4-1 must always be specified in uppercase. The SSI processor is case sensitive, so keep that in mind as you write your HTML.
In addition to the variables listed in Table 4-1, you may also include quoted text as a constant. Constants can be surrounded with either single (') or double (") quotes.
Conditional Directive Binary Operators
Name | Alternative | Description |
---|---|---|
== | = | String equality |
!= | String inequality | |
< | String less than | |
<= | String less than or equal | |
> | String greater than | |
>= | String greater than or equal | |
=~ | String matches the regular expression | |
!~ | String does not match the regular expression | |
-eq | eq | Integer equality |
-ne | ne | Integer inequality |
-lt | lt | Integer less than |
-le | le | Integer less than or equal |
-gt | gt | Integer greater than |
-ge | ge | Integer greater than or equal |
-ipmatch | IP address matches address/netmask | |
-strmatch | Left string matches pattern given by right string (containing wildcards *, ?, []) | |
-strcmatch | Same as -strmatch, but case insensitive | |
-fnmatch | Same as -strmatch, but slashes are not matched by wildcards |
Conditional Directive Unary Operators
Name | Description |
---|---|
-d | The argument is treated as a filename. True if file exists and is a directory. |
-e | The argument is treated as a filename. True if the file (or dir or special) exists. |
-f | The argument is treated as a filename. True if the file exists and is a regular file. |
-s | The argument is treated as a filename. True if the file exists and is a regular file. |
-L | The argument is treated as a filename. True if the file exists and is a symlink. |
-h | The argument is treated as a filename. True if the exists and is a symlink (same as -L). |
-F | True if string is a valid file, accessible via all the server’s currently configured access controls for that path. This uses an internal subrequest to do the check, so use it with care; it can impact your server’s performance. |
-U | True if string is a valid URL, accessible via all the server’s currently configured access controls for that path. This uses an internal subrequest to do the check, so use it with care; it can impact your server’s performance. |
-A | Alias for -U. |
-n | True if string is not empty. |
-z | True if string is empty. |
-T | False if string is empty, "0", "off", "false", or "no" (case insensitive). True otherwise. |
-R | Same as "%{REMOTE_ADDR} -ipmatch . . .", but more efficient. |
At this point, it should be noted that there are no OR or AND operators. This means that only simple comparisons can be made in an if directive. Multiple comparisons must be made by nesting if directives.
Conditional Directive Functions
Name | Description | Notes |
---|---|---|
req, http | Gets HTTP request header; header names may be added to the Vary header | |
req_novary | Same as req, but header names will not be added to the Vary header | |
resp | Gets HTTP response header (most response headers will not yet be set during <If>) | |
reqenv | Looks up request environment variable (as a shortcut, v can also be used to access variables) | Ordering |
osenv | Looks up operating system environment variable | |
note | Looks up request note | Ordering |
env | Returns first match of note, reqenv, osenv | Ordering |
tolower | Converts string to lowercase | |
toupper | Converts string to uppercase | |
escape | Escapes special characters in %hex encoding | |
unescape | Unescapes %hex-encoded string, leaving encoded slashes alone; return empty string if %00 is found | |
base64 | Encodes the string using base64 encoding | |
unbase64 | Decodes base64-encoded string; returns truncated string if 0x00 is found | |
md5 | Hashes the string using MD5, then encodes the hash with hexadecimal encoding | |
sha1 | Hashes the string using SHA1, then encodes the hash with hexadecimal encoding | |
file | Reads contents from a file (including line endings, when present) | Restricted |
filemod | Returns last modification time of a file (or 0 if file does not exist or is not a regular file) | Restricted |
filesize | Returns size of a file (or 0 if file does not exist or is not a regular file) | Restricted |
The functions marked “Restricted” in the final column are not available in some modules like mod_include.
The functions marked “Ordering” in the final column require some consideration for the ordering of different components of the server. You should remember that the if directive is evaluated early in the response processing.
Summary
Using SSI can be as easy or complicated as you want to make it. While it does not fit every situation, it is a useful tool for easing your web server maintenance. Used under the right circumstances, it can make everything easier.
This chapter has introduced all the concepts needed to make SSI work for you whatever your needs. Just remember that the main SSI directives are evaluated after the SSI conditional directives.