Scheme CGI library


Synopsis

(require "cgitool")

(cgi:let (parameter ...) body ...)

(cgi:parse-query-string &optional string)
(cgi:get-parameter-value name alist &key :default :error :multivalue)

(cgi:parse-cookie &optional string)
(cgi:write-header &key :content-type :cookies :location)

*cgi:error-page-html-options*
(cgi:error fmt args ...)
(cgi:error-page fmt args ...)

Requires

"html-classes"

Description

Cgitool is a collection of procedures useful to write cgi script in Scheme. It supports:

See examples below to get an idea of how to write CGI scripts with this tool. About the protocol of cookie handling, see RFC2109.

High level macro

(cgi:let (parameter-spec ...) body ...) : Macro

This macro is ultimately convenient way to write a CGI script. It retrieves a query-string parameter and "cookies" from environment variable QUERY_STRING and HTTP_COOKIE, respectively, and bound it to local variables according to parameter-spec, then executes body.

parameter-spec can be a symbol or a list.

  • If it is a symbol except &queries or &cookies, cgi:let first looks for a parameter named as the symbol, and binds its value to given symbol. If named parameter is not found, cgi:error is called.
  • If it is the symbol &queries, the assoc-list which cgi:parse-query-string returns is bound to the symbol.
  • If it is the symbol &cookies, the assoc-list which cgi:parse-cookie returns is bound to the symbol.
  • If it is a list, it must be formed like (symbol keyword value ...). Symbol is bound to the value of parameter retrieved. Other options specifies the way to retrieve parameter. Possible options are:
    :name name
    Specifies a parameter name other than symbol.
    :source source
    Specifies the source of the value, either :query or :cookie. If omitted, :query is assumed.
    :convert proc
    Passed to cgi:get-parameter-value.
    :default value
    Passed to cgi:get-parameter-value.
    :error proc
    Passed to cgi:get-parameter-value.
    :multvalue boolean
    Passed to cgi:get-parameter-value.

Error page handling

*cgi:error-page-html-options* : Variable

A list of init-keywords and values, which will be used to create <html-page> object for error page. See schtml for details.

Example: '(:page-title "CGI error" :author-name "shiro")

(cgi:error format . args) : Procedure

Generate CGI header string and html error page (using cgi:error-page) to stdout, and exits. Convenient way to exit the CGI script with error.

Arguments format and args are passed to format and used as a contents of the error page.

(cgi:error-page format . args) : Procedure

Generate error page (<html-page> object).

Arguments format and args are passed to format and used as a contents of the error page.

Query string handling

(cgi:parse-query-string &optional string) : Procedure

Parse query string string and return alist of result. When string is omitted, the value of environment variable QUERY_STRING is used if it is set, or just return '() if it is not set. If provided string is illegal for quoted query string, this procedure generates a html error page and exits.

This procedure calls cgi:url-unquote.

(cgi:get-parameter-value name alist &key :default :error :multivalue :convert) : Procedure

Given alist, an alist of parameters which cgi:parse-query-string or cgi:parse-cookie returns, this procedure looks for name and returns its associated value. Name must be a symbol.

If name is not found in alist, the action depends on the other keyword arguments like this:

  1. If a keyword argument :default is specified, the value is returned.
  2. Otherwise, if a keyword argument :error is specified, call it as a procedure with one argument name.
  3. Otherwise, generates html error page and exits.

If keyword argument :multivalue is true, the procedure returns list of value(s). Otherwise, the procedure returns a string, concatenating all the value(s) with whitespace inbetween.

If keyword argument :convert is specified, it must be a procedure taking one string argument and returning converted value to suitable type. After a value is retrieved, the procedure is applied to it to perform type conversion.

HTTP Header & Cookie handling

(cgi:write-header &key :content-type :cookies :location) : Procedure

Write out CGI header string. Keyword argument :content-type must be a string and is used for content type. The default is "text/html".

Keyword argument :location specifies location header of http, to redirect user's request to new location. This option supercedes content-type option.

Keyword argument :cookies specifies "cookies" to be sent to the client. It is an assoc-list and each element must be the following form:

    (NAME VALUE [keyword arg ...])
Keyword-value pairs are intended for per-cookie attribute values as defined in RFC2109 (new specification). It also supports "old" cookie format in original Netscape proposal. To make two standard coexist, VALUEs are not quoted.

Following attribute specification (keyword-value pair) are recognized. If the attribute is only available either new spec or old spec, it is marked as "(new)" or "(old)". If you mix new-spec-only attribute and old-spec-only attribute, the result will be unknown. Note that if you want to use new specification, you must specify "Version" attribute explicitly (it should be 1).

      :comment STRING    Comment attribute.  (new)
      :domain STRING     Domain attribute.
      :max-age INTEGER   Max-Age attribute.  (new)
      :path STRING       Path attribute.
      :secure BOOLEAN    Secure attribute.
      :version INTEGER   Version attribute.  (new)
      :expires DATE      Expires attribute.  (old)
          If DATE is integer, it must be a seconds from
          Jan 1, 1970 0:0:0 GMT.  If DATE is a string, it must be
          a formatted date string ("Wdy, DD-Mon-YY HH:MM:SS GMT").
(cgi:parse-cookie &optional string) : Procedure

Parse encoded cookie and returns assoc-list. If string is omitted, environment variable HTTP_COOKIE is used.

The "new" format as of RFC2109 can be handled, although all additional attributes (attributes starts with "$") will be ignored.

Examples

This CGI script just gets parameter "name" and prints out a greeting.
#!/sqhnl/bin/snow -f
(require "cgitool")

(cgi:let (name)
  (cgi:write-header)
  (write-html (html-page :page-title "Greeting"
                         :author-name "shiro"
                         :author-email "shiro"
                         :contents (format #f "Hello, ~a." name))))

(exit 0)
This CGI script accepts parameter "year" and "month", and returns calender using unix "cal" command.
#!/sqhnl/bin/snow -f
(require "posix")
(require "cgitool")

;; Default month and year
(define *this-year-and-month*
  (let* ((tmvec (posix-tm->vector
                  (posix-localtime (posix-time))))
         (yy    (+ (vector-ref tmvec 5) 1900))
         (mm    (+ (vector-ref tmvec 4) 1)))
    (if (< yy 1970)          ;; year 2000 problem...
        (cons (+ yy 100) mm)
        (cons yy mm))))

;; Make sure parameter gives correct string
(define (convert-year str)
  (or (string->number str) (car *this-year-and-month*)))
(define (convert-month str)
  (or (string->number str) (cdr *this-year-and-month*)))

;; Process request
(cgi:let ((year  :default "" :convert convert-year)
          (month :default "" :convert convert-month))
  (let ((cal (apply string-append
                    (with-input-from-file
                        (format #f "| cal ~s ~a" month year)
                      (lambda ()
                        (let loop ((line (read-line)))
                          (if (eof-object? line) '()
                              (list* line "\n" (loop (read-line))))))
                      ))))
    (cgi:write-header)
    (write-html
     (html-page :page-title "Calendar"
                :author-name "shiro"
                :author-email "shiro"
                :contents
                (html-text :preformatted? #t
                           :string cal))))
  )

;; All done.
(exit 0)

Shiro Kawai
Square USA Inc.
shiro@squareusa.com