cgi.tcl - A Reference Manual (Draft) by Don Libes This document contains technical notes on using cgi.tcl. This document is a draft and has not been officially reviewed. This document assumes that you have read the Tcl '96 paper "CGI Scripting in Tcl". That document will give you the feel for what this code is all about. In contrast, this document provides the details. This document assumes you know HTML. I'm not going to explain what particular tags do or how to use them effectively, except as necessary to understand the document. Some of the commands may not work with all browsers. For example, the cgi_center command is generally understood only by some Netscape browsers because it produces
tags which are not commonly supported. You'll have to use your judgement. Remember: Just because a command exists to produce the HTML doesn't mean your browser will do anything meaningful with it. In that sense, using this code is no different than handcoding HTML. ************************************************** A NOTE ABOUT PROCEDURE NAMES ************************************************** All procedures are named cgi_XXX. You can also call them without the cgi_ prefix. Using the cgi_XXX form is no big deal for rarely used procedures, but the aliases are particularly convenient for things like hr and br. Aliases are suppressed if procedures exist by those names already. (Thus, cgi_eval cannot be invoked as "eval"!) Similarly, you can overwrite the aliases with impunity. Internally, references are only made to the cgi_ names. I'm still thinking about this. If you have strong feelings about it, let me know. ************************************************** SECURITY ************************************************** I frequently see statements saying that Tcl (and other interpretive languages, for that matter) are insecure and should not be used for writing CGI. I disagree. It is possible to use Tcl securely and it really isn't very hard. The key, of course, is to not blindly evaluate user input. There really isn't much reason to. For instance, this library itself is pretty big and does lots of things, but nothing in it evaluates user input. (It does do a lot of evaluation of *programmer* input, but that's quite acceptable.) The two classes of commands you should pay close attention to are commands that do eval operations and commands that invoke external programs. ************************************************** GENERAL NOTES ABOUT PARAMETERS ************************************************** ** There are several basic styles of parameter passing. -- Container commands (e.g., ,
, etc.) The last argument is typically a block of code. Other arguments become attributes. For example: cgi_body bgcolor=red background=white { h4 "hello" } produces:

hello

-- Commands with required arguments Some commands have required arguments. Required arguments which are relatively long, are passed *after* all others. For example: cgi_h4 align=left "Foo's Bar & Grill" Another example: cgi_body bgcolor=red background=white { cgi_h4 "Foo's Bar & Grill" } Commands with relatively short arguments have the short arguments passed *before* all others. This avoids many redundant keywords. In the following example, the "img=" is omitted because it is already implied by the command. The "alt=" is not optional (although the entire argument is). cgi_img foo.gif "alt=Foo's Bar & Grill" Note the quotes around the alt argument. This is only necessary if the argument has whitespace in it - a consequence of Tcl's normal scanning rules. The resulting HTML automatically includes quotes around the value attribute. (See Case-sensitivity.) ** Case-sensitivity and Quotes and Whitespace Attribute names are case sensitive. Use lowercase names for "normal" handling. For example, values for attributes such as "url" and "value" are quoted and encoded. Use uppercase names to suppress the usual processing. (For example, you might want to test how a browser responds to incorrect HTML.) Consider: cgi_body bgcolor=#123456 { p [cgi_img foo.gif "alt=Foo's Bar & Grill"] } This is translated to

Foo's Bar & Grill

Notice how the ampersand in the alt value has been encoded. Also notice how quotes have been added to the values of bgcolor, url, and alt. Thus you no longer have to add quotes all over the place (or remember when you need to). Embedded whitespace is protected by quoting in the usual Tcl fashion rather than typical HTML fashion. So instead of: img foo.gif alt="foo bar" do this: img foo.gif "alt=foo bar" which will return HTML that is properly quoted: foo bar -- Name-value commands Many commands produce tags that use "name" and "value" attributes. Because these attributes are almost always used in such commands, the first argument is always of the form name=value so the literal "name" and "value" can be omitted. For example: cgi_text color=Red size=5 produces: Reasonable defaults exist. For example, if you don't need the value of a submit button (but the user still needs to see it appear as the label), omit the name: cgi_submit_button =Execute If no "=" is present, the string is assumed to be the "name" attribute. For example: cgi_checkbox Vegies produces a checkbox associated with the variable named "Vegies". (With no specified value, it will be set to "on" if checked.) Most of the commands have reasonable defaults. For example, to quickly script a submit button, the following suffices: cgi_submit_button Certain constructions make no sense and are therefore disallowed. For example, a submit button with a name but no value makes no sense, so cgi_submit_button doesn't allow it. (In other words, if you provide an argument, it has to have "=" in it.) ************************************************** JAVASCRIPT ARGUMENTS ************************************************** JavaScript event attributes such as onClick are handled just like any other attributes in terms of quoting and case sensitivity. Because there are so many attributes on so many tags, they are not documented explicitly in this manual. However, they are all supported. Here is an example: cgi_text age=18 onChange=MinimumAge(this.form.age) ************************************************** PROCEDURES TO ASSIST IN DEBUGGING ************************************************** ** User-id differences You can interactively run and debug CGI scripts by simply running them from the shell, or a Tcl or C debugger. (For convenience, I use Expect instead of tclsh just so that I get the debugger.) In fact, I've never had to resort to the C debugger. However, simply watching the raw output from a shell is very handy. This catches the really basic errors such as incorrect protections, incorrect #! line, etc. Once your script is actually executing, you can rely on cgi_eval (see below). cgi_uid_check user Typically, a CGI script is intended to run from a particular uid, such as "nobody". If you run such scripts interactively, you can end up with conflicts. For example, if the script creates files, files can accidentally end up being owned by you. cgi_uid_check is a convenient mechanism to warn against this problem. Simply call cgi_uid_check in your script. The argument is the uid under which the script should be running. If the given uid does not match the actual uid, cgi_uid_check will generate an error. ** Trapping error messages cgi_eval cgi_eval is the primary error catching/reporting mechanism. Execute commands from cgi_eval so that errors can be caught and reported in a nice way. By default, errors are emailed back to the administrator. "cgi_debug -on" makes errors be immediately viewable in the browser. If an error is caught when debugging is enabled, the diagnostic is anchored with #cgierror. This is useful in scripts that produce voluminous output. cgi_error_occurred cgi_error_occurred returns 1 if an error occurred and was caught by cgi_eval. This separate function simplifies exit handling - for example, rather than always checking the return value of cgi_eval, an app can just test this from a redefined exit. cgi_admin_mail_addr addr cgi_admin_mail_addr sets the administrator's email address. Diagnostics are sent via email if a problem is encountered with the script and debugging is not enabled. cgi_name name cgi_name defines a name for the service. If called with no arguments, the name is returned. The name is currently used in the following places: If email is sent, it comes from [cgi_name]. If errors are emailed, the subject is "[cgi_name]: CGI problem" ** Generating debugging output and other commands cgi_debug args cgi_debug provides rudimentary support for generating debugging messages. Here are some example calls: cgi_debug cmd If debugging is on, the command is evaluated. For example: cgi_debug { h2 "completed initialization" } or cgi_debug {h2 "completed initialization"} Note this is more than simply calling h2. Context is rewound or forwarded to get to a place where this is safe. (And conversely, this call can suppress things such as header elements that haven't been processed yet.) The flag "-noprint" suppresses this manipulation - this is useful for early code that causes no printing. The -- flag causes the next argument to treated as a command even if it looks like another flag. cgi_debug -on Enables debugging messages. This includes debugging messages generated by explicit calls to cgi_debug as well as implicit diagnostics, for example, that report on form input. cgi_debug -temp text Enable debugging for this one line. cgi_debug -off Disable debugging. cgi_debug always returns the old setting ("-on" or "-off"). The initial value is -off. ** Printing arrays cgi_parray arrayname cgi_parray prints out the elements of a Tcl array. cgi_parray is just like Tcl's parray except that its output is appropriately formatted for a browser. ************************************************** BASIC STRUCTURE OF A CGI SCRIPT ************************************************** Typically, the basic structure of most CGI scripts is: package require cgi cgi_eval { cgi_http_head {cmds} cgi_html { cgi_head {cmds} cgi_body {cmds} } } Much of this can be omitted, however. In fact, a typical script looks more like this: package require cgi cgi_eval { cgi_title "title" cgi_body { cmds } } (If you're not using the Tcl package support, replace the 'package require' command with a 'source' command of the specific file containing the cgi.tcl source.) (The "...." in the examples above should be replaced by the true path to the cgi.tcl file.) I'll now go through each of these in more detail as well as some other possibilities for the overall structure. ************************************************** HTTP HEADERS ************************************************** cgi_http_head cmds CGI scripts must produce various headers to explain how the remainder of the output is to be interpreted. No other output may preceed this! With no argument, an HTML content type is produced if the script is running in the CGI environment. This means that most people need not bother calling cgi_http_head. However, if you want to see the HTTP headers and you are not running in the CGI environment, you should call cgi_http_head explicitly. (Alternatively, you can make it appear that you are in the CGI environment by defining the environment variable REQUEST_METHOD.) The remaining commands in this section may be used in cgi_http_head. Most should be intuitively obvious and thus need no explanation. cgi_content_type type Generates a "Content-type:" header. With no argument, cgi_content_type generates a declaration for HTML. If specified, the 'type' argument should be the full MIME-style type/subtype declaration. Any MIME-style parameters should be included in the type argument. cgi_redirect location Generates a redirect header (Status:/Location:/URI:) cgi_target Generates a "Window-target:" header. cgi_refresh seconds url Generates a "Refresh:" header. The url argument is optional. cgi_pragma pragma Generates a "Pragma:" header. cgi_status number string Generates a "Status:" header. ** Cookies cgi_cookie_set name=val args Define a cookie with given name, value, and other arguments. Cookie values are automatically encoded to protect odd characters. A couple expirations are predefined (with intuitive meaning): expires=never expires=now expires=...actual date... Here are some examples: cgi_cookie_set user=don domain=nist.gov expires=never cgi_cookie_set user=don expires=now secure cgi_export_cookie name args Export the named Tcl variable as a cookie. Other arguments are processed as with cgi_cookie_set. Cookies may be read only after calling cgi_input. The following routines read cookie names or specific cookies. cgi_cookie_list Returns the list of all cookies supplied by the server. cgi_cookie_get name Returns the value of the named cookie. If multiple values exists the most specific path mapping is used. If the "-all" flag is used (before the cookie name), a list is returned containing all cookie values for the given name. The list is ordered most-specific (path mapping) to least. I.e., the first value on the list is the same one returned by calling cgi_cookie get without a flag. cgi_import_cookie name Define a Tcl variable with the value of the cookie of the same name. For example, the following command retrieves the cookie named "Password" and stores it in the Tcl variable "Password". cgi_import_cookie Password ************************************************** GENERATING HTML ************************************************** cgi_html tags can be generated using cgi_html. An argument to cgi_html is evaluated to produce the actual HTML code. In practice, it is not necessary to use cgi_html. CGI.tcl will automatically generate the tags when appropriate. (Oddly, modern HTML specs don't require it and most if not all browsers never cared anyway.) cgi_doctype cgi_doctype is a user-defined procedure that produces a SGML DOCTYPE declaration. If it exists, cgi_doctype is automatically invoked at the beginning of cgi_html. (This library does not automatically create DOCTYPE declarations since the library is not restricted to generating SGML for any single DTD. Realistically, DOCTYPEs are pointless for HTML generation since web browsers don't require DOCTYPE declarations. However, if you are creating pages for some other purpose that requires such a declaration, use cgi_doctype.) cgi_head tags can be generated using cgi_head. An argument to cgi_head is evaluated to produce the actual headers. In practice, it is not necessary to use cgi_head. CGI.tcl will automatically generate the tags when appropriate. (Oddly, modern HTML specs don't require it and most if not all browsers never cared anyway. So for example: cgi_head { cgi_title "my page" } is equivalent to: cgi_title "my page" Note that cgi_title will be called automatically if you omit cgi_title, cgi_head, or call cgi_head with no arguments. cgi_title title cgi_title defines the title of a page. It is called from within a pair. If not called from within cgi_head, it implicitly forces it to occur. cgi_title always returns the title. With no argument, cgi_title returns the old title without changing it. cgi_http_equiv cgi_http_equiv is equivalent to cgi_http_head but from within cgi_head. This procedure is defined for completeness - there is no reason to use it. In fact, it doesn't allow all cgi_http_head declarations, so it should be avoided. cgi_meta cgi_meta generates a tag. You can do whatever you want with these. (Read some an HTML document for more info.) For example: meta name=author {content="Don Libes"} cgi_script cmd cgi_script evaluates its arguments inside of tags. This is appropriate for putting in client-side scripting. Optional arguments are passed as attributes to the