WASD Hypertext Services - Environment Overview

[next] [previous] [contents] [full-page]

5 - Server Side Includes (SSI)

The HTML pre-processor is used to provide dynamic information inside of an otherwise static, HTML (HyperText Markup Language) document. The HTTPd server provides this as internal functionality, scanning the input document for special pre-processor directives, which are replaced by dynamic information based upon the particular directive.

As of version 5.1 WASD SSI has been enhanced to provide flow-control statements, allowing blocks of the document to be conditionally processed, see 5.5 - Flow Control. These extensions allow quite versatile documents to be created without resorting to script processing.

Two documents are provided as examples of SSI processing.

By default the HTML pre-processor is invoked when the document file's extension is ".SHTML". As there is a significant overhead with pre-processed HTML compared to normal HTML, it should only be used when it serves a useful documentary purpose, and not just for the novelty.

Virtual Documents

One effective use for pre-processed HTML is the creation of single virtual documents from two or more physical documents. That is, the pre-processed document is used to include multiple physical documents, that may even be independently administered, to return a composite document to the client. This is a relatively low-overhead activity, but because it is a dynamic document loses the advantages of "If-Modified-Since:" processing (see 2 - HyperText Transport Protocol Daemon).


5.1 - Pre-Expiring Documents

HTML-preprocessed documents are dynamic in the sense that the information presented can be different every time the document is generated (e.g. if time directives are included). If it is important that each time the document is accessed it is regenerated then an HTML META tag can be included in the HTML header to cause the document to expire. This will result in the document being reloaded with each access.

Ensure the document is structured similar to the following and include the <META HTTP-EQUIV= ...> tag with a legitimate date well in the past:

  <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
  <HTML>
  <HEAD>
  <META HTTP-EQUIV="expires" CONTENT="Thu, 01-Jan-1970, 00:00:01 GMT">
  <TITLE> etc. </TITLE>
  </HEAD>
  <BODY>
     etc.
  </BODY>
  </HEAD>


5.2 - Directive Syntax

The syntax follows closely that used by the other implementations, but some directives are tailored to the WASD and VMS environment. The directive is enclosed within an HTML comment and takes the form:

  <!--#directive [[tag1="value"] [tag2="value"] ...] -->

A tag provides parameter information to the directive. A directive may have zero, one or more parameters. Values supplied with any tag may be literal or via variable substitution (see 5.4 - Variables. A value must be encolosed by quotation marks if it contains white-space.

A directive can be split over multiple lines provided the new line begins naturally on white-space within the directive. For example, this is correctly split

  <!--#echo
  created[="<EMPHASIS>(time-format)"] -->
while the following is not (and would produce an error)
  <!--#echo creat
  ed[="<EMPHASIS>(time-format)"] -->

Directive and tag keywords are case insensitive. The tag value may or may not be case sensitive, depending upon the command/tag. Generally the effect of a command is to produce additional text to be inserted in the document, although it is possible to control the flow of processing in a document with decision structures.


5.3 - Directive Commands


5.3.1 - #ACCESSES

The #accesses directive allows the number of times the document has been accessed to be included. It does this by creating a counter file in the same location and using the same name with a dollar symbol appended to the type (extension). The count may be reset by deleting the file. This is an expensive function (in terms of file system activity) and so should be used appropriately. It can be disabled by server configuration. Three tags provide additional functionality:


5.3.2 - #CONFIG

The #config directive allows time and file size formats to be specified for all subsequent directives providing these values. Optional specifications for individual directives may still be made, and override, do not supercede, any specification made using a config directive. A config directive may be made once, or any number of times in a document, and applies until another is made, or until the end of the document.


5.3.3 - #DIR

The #dir directive generates an Index of ... directory listing inside an HTML document. Apart from not generating a title (it is up to the pre-processed document to title, or otherwise caption, the listing) it provides all the functionality of the WASD HTTPd directory listing (see 4 - Directory Listing), including query string format control via the "par=" parameter (note that from the "?httpd=index" introducer used with directory listings is not necessary from SSI). It is an WASD HTTPd extension to pre-processed HTML.

For example:

  <!--#dir /ht_root/src/httpd/" -->

  <!--#dir /ht_root/src/httpd/*.c" par="layout=UL__S&nops=yes" -->


5.3.4 - #DCL

The #dcl directive executes a DCL command and incorporates the output into the processed document. It is an WASD HTTPd extension to the more common exec directive, which is also included.

By default, output from the DCL command has all HTML-forbidden characters (e.g. "<", "&") escaped before inclusion in the processed document. Thus command output cannot interfere with document markup, but nor can the DCL command provide HTML markup. This behaviour may be changed by appending the following tag to the directive:

  type="text/html"

Some #dcl directives are for privileged documents only, documents defined as those being owned by the SYSTEM account, and not being world-writeable. The reason for this should be obvious. There are implicit security concerns about any document being able to execute any DCL command(s), even if it is being executed in a completely unprivileged process. Hence only innocuous commands are allowed in standard documents.


5.3.5 - #ECHO

The #echo directive incorporates the specified information into the processed document. Multiple tags may be used within the one directive.


5.3.6 - #ELIF

The #elif directive (else-if) allows blocks of HTML markup and SSI directives to be conditionally processed, see 5.5 - Flow Control and 5.3.13 - #IF. This directive effectively allows a case statement to be constructed.

  <!--#elif var="[{variable}|literal" -->


5.3.7 - #ELSE

The else directive allows blocks of HTML markup and SSI directives to be conditionally processed, see 5.5 - Flow Control. It is the default block after an "#if", "#orif" or "#elif".

  <!--#else -->


5.3.8 - #ENDIF

The #endif directive marks the end of a block of document text being conditionally processed, see 5.5 - Flow Control.

  <!--#endif -->


5.3.9 - #EXEC

The #exec directive executes a DCL command and incorporates the output into the processed document. It is the VMS equivalent of the exec shell directive of some Unix implementations. It is implemented in the same way as the #DCL directive, and so the general detail of that directive applies. It supports only the cmd tag, the cgi tag, allowing execution of CGI scripts, is not supported.

  <!--#exec cmd="show device/full tape1:" -->

The exec directive is for privileged documents only, documents defined as those being owned by the SYSTEM account, and not being world-writeable. The reason for this should be obvious. There are implicit security concerns about any document being able to execute any DCL command(s), even if it is being executed in a completely unprivileged process.


5.3.10 - #FCREATED

The #fcreated directive incorporates the creation date/time of a specified file/document into the processed document.


5.3.11 - #FLASTMOD

The #flastmod directive incorporates the last modification date/time of a specified file/document into the processed document.


5.3.12 - #FSIZE

The #fsize directive incorporates the size, in bytes, kbytes or Mbytes, of a specified file/document into the processed document.


5.3.13 - #IF

The #if directive allows blocks of HTML markup and SSI directives to be conditionally processed, see 5.5 - Flow Control.

As in the following examples:

  <!--#if value={DOCUMENT_URI} eqs="/ht_root/doc/env/xssi.shtml" -->
  <!--#if value={COUNT} lt=10 -->
  <!--#if value="This is a test!" eqs={STRING} -->
  <!--#if value={PATH_INFO} srch="*/env/*" -->


5.3.14 - #INCLUDE

The #include directive incorporates the contents of a specified file/document into the processed document.

The contents of the specified file are included differently depending on the MIME content-type of the file. Files of text/html content-type (HTML documents) are included directly, and any HTML tags within them contribute to the markup of the document. Files of text/plain content-type (plain-text documents) are encapsulated in "<PRE></PRE>" tags and have all HTML-forbidden characters (e.g. "<", "&") escaped before inclusion in the processed document. An HTML file can be forced to be included as plain-text by using the following syntax:

  <!--#include virtual="example.html" type="text/plain" -->

Other SSI files may be included and their content dynamically included in the resulting document. To prevent a recursive inclusion of documents the nesting level of SSI documents is limited to five.


5.3.15 - #ORIF

The #orif directive (or-if) allows blocks of HTML markup and SSI directives to be conditionally processed, see 5.5 - Flow Control and 5.3.13 - #IF. In the absence of any real expression parser this directive allows a block to be processed if one of multiple conditions are met.

  <!--#orif var="[{variable}|literal" -->


5.3.16 - #PRINTENV

The #printenv directive prints a plain-text list of all SSI-specific, then CGI, then document-assigned variables (see 5.4 - Variables). This directive is intended for use when debugging flow-controlled SSI documents.

  <!--#printenv -->

The following link uses the example SSI document HT_ROOT:[DOC.ENV]XSSI.SHTML to demonstrate this.

  xssi.shtml?httpd=ssi&printenv=yes&test1=one&test2=two&test3=three


5.3.17 - #SET

The #set directive allows a user variable to be assigned or modified, see 5.4 - Variables.

  <!--#set var="variable-name" value="whatever" -->

Variables are always stored as strings and have a finite but generally usable length. Some comparison tags provided in the flow-control directives treat the contents of variables as numbers. A numeric conversion is done at evaluation time.


5.3.18 - #SSI

The #ssi directive allows multiple SSI directives to be used without the requirement to enclose them in the normal HTML comment tags (i.e. <!-- -->). This helps reduce the clutter in an SSI document that uses the extended capabilities of variable assignment and flow control. Document HTML cannot be included between the opening and closing comment elements of the "#ssi" tag, although of course document output can be generated using the "#echo" tag.

  <!--#ssi
  #set var=HOUR value={DATE_LOCAL,12,2}
  #if var={HOUR} lt=12
    #set var=GREETING value="Good morning"
  #elif var={HOUR} lt=19
    #set var=GREETING value="Good afternoon"
  #else
    #set var=GREETING value="Good evening"
  #endif
  -->

The example SSI document HT_ROOT:[DOC.ENV]XSSI.SHTML illustrates this concept.


5.3.19 - #STOP

The #stop directive causes the server to stop processing the document. It can be used with flow control structures to conditionally process only part of a document.

  <!--#stop -->


5.3.20 - #TRACE

The #trace directive switches document processing trace on or off. This directive is intended for use when debugging flow-controlled SSI documents.

  <!--#trace ON|OFF -->

Output from a trace is colour-coded.

The following link provides an example of a document trace.


5.4 - Variables

The SSI processor maintains information about the server, date and time, request path, request parameters, etc., accessable via variable name. Although these server variables cannot be modified by the document the processor also allows the author to create and assign new document variables by name.

Server assigned variables comprise some SSI-specific as well as the same CGI variables available to CGI scripts. These may be found listed in the "CGI Scripting" chapter of the Technical Overview.

The following link provides a list of the SSI and CGI variables available to SSI documents.

Whenever a directive uses information from a tag (see 5.2 - Directive Syntax) values from variables may be substituted as as a whole or partial value. This is done using curly braces to delimit the variable name. For example

  <!--#include virtual={FILENAME} -->
would include the file named by the contents of a variable named "FILENAME". When using a variable in a tag it is not necessary to enclose the tag parameter in quotation marks unless there is additional literal text. Variables may also be used within literal strings, producing a compound, resultant string, as in the following example
  <!--#echo var="Hello {REMOTE_HOST}, time here is {LOCAL_TIME}" -->

Variables are considered numeric when they begin with a digit. Those beginning with an alphabetic are considered to have a numeric value of zero.

Variables are considered to be boolean false if empty and true when not empty.

Substrings

It is also possible to extract substrings from variables using the following syntax,

  {variable-name,start-index,count}

where the start-index begins with the zeroth character and numbers up to the last character in the string, and count may be zero or any positive number. If only one number is supplied it is regarded as a count and the string is extracted from the zeroth character.

To illustrate,

  <!--#set var=EXAMPLE value="This is an example!" -->
  <!--#echo "{EXAMPLE,2}at was {EXAMPLE,8,999}" -->

would output

  That was an example!

Other "Functions"

Example

The example SSI document HT_ROOT:[DOC.ENV]XSSI.SHTML illustrates these concepts.


5.5 - Flow Control

WASD SSI allows blocks of document to be conditionally processed. This uses constructs in a similar way to any programming language. The emphasis has been on simplicity and speed of processing. No complex expression parser is provided. Despite this, complex document constructs can be implemented. Flow control structures may be nested up to eight levels.

The "#if", "#orif" and "#elif" directives must provide an evaluation. This can be single variable, which if numeric and non-zero is considered true, if zero if false, or can be a string, which if empty is false, and if not empty is true. Tests can be made against the variable which when evaluated return a true or false. Multiple tests may be made against the one variable, or against more than one variable. Multiple tests act as a logical AND of the results and terminate when the first fails.

The following is a simple example illustration of variable setting, use of variable substrings, and conditional processing of document blocks.

  <!--##trace par=ON -->
  <HTML>
  <!--#set var=HOUR value={DATE_LOCAL,12,5} -->
  <!--#if var={HOUR} lt=12 -->
  <!--#set var=GREETING value="Good morning" -->
  <!--#elif var={HOUR} lt=19 -->
  <!--#set var=GREETING value="Good afternoon" -->
  <!--#else -->
  <!--#set var=GREETING value="Good evening" -->
  <!--#endif -->
  <HEAD>
  <TITLE><!--#echo var={GREETING} -->
  <!--#echo var="{REMOTE_HOST}!" --></TITLE>
  </HEAD>
  <BODY>
  <H1>Simple XSSI Demonstration</H1>
  <!--#echo var={GREETING} --> <!--#echo var={REMOTE_HOST} -->,
  the time here is <!--#echo var={DATE_LOCAL,12,5} -->.
  <!--#if var={REMOTE_HOST} eqs={REMOTE_ADDR} -->
  (Sorry, I do not know your name, DNS lookup must be disabled!)
  <!--#endif -->
  </BODY>
  </HTML>

The example SSI document HT_ROOT:[DOC.ENV]XSSI.SHTML further illustrates these concepts.


5.6 - Query Strings

A query string may be passed to an SSI document in much the same way as to a CGI script. In this way the behaviour of the document can be varied in accordance to information explicitly passed to it when accessed. To prevent the server's default query engine being given the request precede any query string with "?httpd=ssi". The server detects this and passes the request instead to the SSI processor. Just append the desired query string components to this as if they were form elements. For example:

  ?httpd=ssi&printenv=no
  ?httpd=ssi&printenv=yes
  ?httpd=ssi&trace=yes&test2=one&test2=two&test3=three

The following link uses the example SSI document HT_ROOT:[DOC.ENV]XSSI.SHTML to demonstrate this. Look for the (FORM_TEST1=one), etc.

  xssi.shtml?httpd=ssi&printenv=yes&test1=one&test2=two&test3=three


5.7 - File and Virtual Specifications

Documents may be specified using either the "FILE" or "VIRTUAL" tags.

The "FILE" tag expects an absolute VMS file specification.

The "VIRTUAL" tag expects an URL-style path to a document. This can be an absolute or relative path. See 3.3 - Document Specification for further details.


5.8 - Time Format

Note: Time formatting only applies if the HTTPd server has been compiled using DEC C.

Whenever a time directive is used an optional tag can be included to specify the format of the output. The default looks a little VMS-ish. If a format specification is made it must confirm to the C programming language function strftime().

The format specifier follows a similar syntax to the C standard library printf() family of functions, where conversion specifiers are introduced by percentage symbols. Here are some example uses:

  The date is <!--#echo date_local fmt="%d/%m/%y" -->.
  The time is <!--#echo date_local fmt="%r" -->.
  The day-of-the-week is <!--#echo date_local fmt="%A" -->.

A problem with any supplied time formatting specification will be reported.

The following table provides the general conversion specifiers. For futher information on the formatting process refer to a C programming library document on the strftime() function.

  Specifier      Replaced by
  ---------      -------------------------------------------------------------

  a              The locale's abbreviated weekday name
 
  A              The locale's full weekday name
 
  b              The locale's abbreviated month name
 
  B              The locale's full month name
 
  c              The locale's appropriate date and time representation
 
  C              The century number (the year divided by 100 and truncated
                 to an integer) as a decimal number (00 - 99)
 
  d              The day of the month as a decimal number (01 - 31)
 
  D              Same as %m/%d/%y
 
  e              The day of the month as a decimal number (1 - 31) in a
                 2 digit field with the leading space character fill
 
  Ec             The locale's alternative date and time representation
 
  EC             The name of the base year (period) in the locale's
                 alternative representation
 
  Ex             The locale's alternative date representation
 
  EX             The locale's alternative time representation
 
  Ey             The offset from the base year (%EC) in the locale's
                 alternative representation
 
  EY             The locale's full alternative year representation
 
  h              Same as %b
 
  H              The hour (24-hour clock) as a decimal number (00 - 23)
 
  I              The hour (12-hour clock) as a decimal number (01 - 12)
 
  j              The day of the year as a decimal number (001 - 366)
 
  m              The month as a decimal number (01 - 12)
 
  M              The minute as a decimal number (00 - 59)
 
  n              The newline character
 
  Od             The day of the month using the locale's alternative
                  numeric symbols
 
  Oe             The date of the month using the locale's alternative
                 numeric symbols
 
  OH             The hour (24-hour clock) using the locale's alternative
                 numeric symbols
 
  OI             The hour (12-hour clock) using the locale's alternative
                 numeric symbols
 
  Om             The month using the locale's alternative numeric symbols
 
  OM             The minutes using the locale's alternative numeric symbols
 
  OS             The seconds using the locale's alternative numeric symbols
 
  Ou             The weekday as a number in the locale's alternative
                 representation (Monday=1)
 
  OU             The week number of the year (Sunday as the first day of the
                 week) using the locale's alternative numeric symbols
 
  OV             The week number of the year (Monday as the first day of the
                 week) as a decimal number (01 -53) using the locale's
                 alterntative numeric symbols. If the week containing January 1
                 has four or more days in the new year, it is considered
                 as week 1.  Otherwise, it is considered as week 53 of the
                 previous year, and the next week is week 1.
 
  Ow             The weekday as a number (Sunday=0) using the locale's
                 alternative numeric symbols
 
  OW             The week number of the year (Monday as the first day of
                 the week) using the locale's alternative numeric symbols
 
  Oy             The year without the century using the locale's alternative
                 numeric symbols
 
  p              The locale's equivalent of the AM/PM designations associated
                 with a 12-hour clock
 
  r              The time in AM/PM notation
 
  R              The time in 24-hour notation (%H:%M)
 
  S              The second as a decimal number (00 - 61)
 
  t              The tab character
 
  T              The time (%H:%M:%S)
 
  u              The weekday as a decimal number between 1 and 7 (Monday=1)
 
  U              The week number of the year (the first Sunday as the first
                 day of week 1) as a decimal number (00 - 53)
 
  V              The week number of the year (Monday as the first day of the
                 week) as a decimal number (00 - 53). If the week containing
                 January 1 has four or more days in the new year, it is
                 considered as week 1. Otherwise, it is considered as week 53
                 of the previous year, and the next week is week 1.
 
  w              The weekday as a decimal number (0 [Sunday] - 6)
 
  W              The week number of the year (the first Monday as the first
                 day of week 1) as a decimal number (00 - 53)
 
  x              The locale's appropriate date representation
 
  X              The locale's appropriate time representation
 
  y              The year without century as a decimal number (00 - 99)
 
  Y              The year with century as a decimal number
 
  Z              Timezone name or abbreviation. If timezone information is
                 not available, no character is output.
 
  %              %


[next] [previous] [contents] [full-page]