This document is not a general tutorial on authoring scripts, CGI or any other. A large number of references in the popular computing press covers all aspects of this technology, usually quite comprehensively. The information here is about the specifics of scripting in the WASD environment, which for CGI and ISAPI is generally very much like any other implementation. (Although there are always annoying idiosyncracies, see 1.6 - Scripting Function Library for a partial solution to smoothing out some of these wrinkles.)
Scripts are mechanisms for creating simple HTTP services, sending data to (and sometimes receiving data from) a client, extending the capabilities of the basic HTTPd. Anything that can write to SYS$OUTPUT can be used to generate script output. A DCL procedure or an executable can be the basis for a script. Simply TYPE-ing a file can be provide script output. Scripts execute in processes separate from the actual HTTP server but under it's control and interacting with it.
WASD manages a script's process environment either as a subprocess spawned by the HTTP server, or as a network process created using DECnet. By default it supports subprocess-based CGI scripts without further configuration.
WASD scripting can deployed in a number of environments. Other chapters cover the specifics of these.
Scripts are generally executed within unprivileged (sub)processes created
by the HTTP server. These processes are owned by the HTTP server account
(HTTP$SERVER). Script actions could potentially affect server behaviour. For
example it is possible for a script to issue an "HTTPD/DO=EXIT=NOW"
command, or for subprocesses to create or modify logical name values in the JOB
table (e.g. change the value of LNM$FILE_DEV altering the logical search
path). Obviously these types of actions are undesirable. In addition scripts
can access any WORLD-readable and modify any WORLD-writable resource in the
system/cluster, opening a window for information leakage or
mischievous/malicious actions (some might argue that anyone with important
WORLD-accessable resources on their system deserves all that happens to them -
but we know they're out there :^) Script authors should be aware of any
potential side-effects of their scripts and Web administrators vigilant against
possible malicious behaviours of scripts they do not author.
1.2 - Subprocess Scripting Environment
Process creation under the VMS operating system is notoriously slow and expensive. This is an inescapable overhead when scripting via child processes. An obvious strategy is to avoid, at least as much as possible, the creation of subprocesses. The only way to do this is to share subprocesses between multiple scripts/requests, addressing the attendant complications of isolating potential interactions between requests. These could occur through changes made by any script to the subprocess' enviroment. For VMS this involves symbol and logical name creation, and files opened at the DCL level. In reality few scripts need to make logical name changes and symbols are easily removed between uses. DCL-opened files are a little more problematic, but again, in reality most scripts doing file manipulation will be images.
A reasonable assumption is that for almost all environments scripts can quite safely share subprocesses with great benefit to response latency and system impact (see "Technical Overview, Performance") for a table with some comparative performances). If the local environment requires absolute script isolation for some reason then this subprocess-persistance may easily be disabled with a consequent trade-off on performance.
NOTE:
With this form of subprocess management BYTLM can become an issue. When setting
the HTTPd account BYTLM quota allow approxiamtely 15,000 bytes per subprocess
that can be concurrently active, plus a general allowance (technically, allow
[BufferSizeDclCgiPlusIn] plus [BufferSizeDclCommand] plus [BufferSizeDclOutput]
plus [BufferSizeNetRead]). That is if the subprocess hard-limit
(see below) is 20 then BYTLM should be set to at least 300,000 plus 50,000. Of
course in such a case PRCLM should be set to at least 20, preferably 40. These
and other relevant quotas may be monitored using the HTTPDMON utility or the
server administration menu.
Zombies
The term zombie is used to describe subprocesses when
persisting between uses (the reason should be obvious, they are neither
"alive" (processing a request) nor are they "dead" (deleted) :^)
Zombie subprocesses have a finite time to exist (non-life-time?)
before they are automatically purged from the system (see
see "Technical Overview, Configuration"). This keeps process clutter on
the system to a minimum.
1.3 - Script Run-Time
Scripts are enabled using the exec or script rules in the mapping file (see "Technical Overview, Mapping Rules"). The script portion of the result must be a URL equivalent of the physical VMS procedure or executable specification.
A script is merely an executed or interpreted file. Although by default VMS executables and DCL procedures can be used as scripts, other run-time environments may also be configured. For example, scripts written for the Perl language may be transparently given to the Perl interpreter in a script subprocess. This type of script activation is based on a unique file type (extension following the file name), for the Perl example this is most commonly ".PL", or sometimes ".CGI". Both of these may be configured to automatically invoke the site's Perl interpreter, or any other run-time environment for that matter.
This configuration is performed using the [DclScriptRunTime] parameter, where a file type is associated with a run-time environment. This parameter takes two components, the file extension and the run-time verb. The verb may be specified as a simple, globally-accessable verb (e.g. one embedded in the CLI tables), or in the format to construct a foreign-verb, providing reasonable versatility. Run-time parameters may also be appended to the verb if desired. The server ensures the verb is foreign-assigned if necessary, then used on a command line with the script file name as the final parameter to it.
The following is an example showing a Perl run-time environment being specified. The first line assumes the "Perl" verb is globally accessable on the system (e.g. perhaps provided by the DCL$PATH logical) while the second (for the sake of illustration) shows the same Perl interpreter being configured for a different file type using the foreign verb syntax.
[DclScriptRunTime] .PL PERL .CGI $PERL_EXE:PERL
A file contain a Perl script then may be activated merely by specifying a path such as the following
/cgi-bin/example.pl
To add any required parameters just append them to the verb specified.
[DclScriptRunTime] .XYZ XYZ_INTERPRETER -vms -verbose -etc .XYZ $XYZ_EXE:XYZ_INTERPRETER /vms /verbose /etc
If a more complex run-time environment is required it may be necessary to
wrap the script's execution in a DCL procedure.
Script File Extensions
The WASD server does not require a file type (extension) to be explicitly provided when activating a script. This can help hide the implementation detail of any script. If the script path does not contain a file type the server searches the script location for a file with one of the known file types, first ".COM" for a DCL procedure, then ".EXE" for an executable, then any file types specified using script run-time configuration directive, in the order specified.
For instance, the script activated in the Perl example above could have been specified as below and (provided there was no "EXAMPLE.COM" or "EXAMPLE.EXE" in the search) the same script would have been executed.
/cgi-bin/example
Two logicals provide some control of and input to the DCL subprocess scripting environment (which includes standard CGI, CGIplus and ISAPI, DECnet-based CGI, but excludes DECnet-based OSU).
$ DEFINE /SYSTEM HTTPD$LOGIN HT_ROOT:[LOCAL]HTTPD$LOGIN.COM
Note that each layer of execution added to the scripting environment increases both system overhead and response latency.
$ DEFINE /SYSTEM HTTPD$VERIFY 1
Note that most WASD scripts also contain logical names that can be set for
debugging purposes. These are generally in the format
script_name$DBUG and if exist activate debugging statements
throughout the script.
1.5 - DCL Processing of Requests
To assist with the processing of request content and response generation from within DCL procedures the CGIUTL utility is available in
HT_ROOT:[SRC.MISC]
Functionality includes
Most usefully it can read the request body, decoding form-URL-encoded
contents into DCL symbols and/or a scratch file, allowing a DCL procedure to
easily and effectively process this form of request.
1.6 - Scripting Function Library
A source code collection of C language functions useful for processing the more vexing aspects of CGI and general script programming is available in CGILIB. This and an example implementation is available in
HT_ROOT:[SRC.MISC]
Functionality includes
The WASD scripts use this library extensively and may serve as example
applications.
1.7 - HTTP Persistant-State Cookies
The WASD server is cookie-aware. That is, if the client supplies a "Cookie:" request header line it is passed to a CGI script as "WWW_HTTP_COOKIE" CGI variable symbol. If a cookie is not part of the request this symbol does not exist. A script may use the "Set-Cookie:" response header line to set cookies.
Here is a small demonstration of cookie processing using a DCL script.