2  CGI Scripts With Inputs

The most interesting CGI scripts are those that produce outputs in response to user's inputs. In the most common cases, a user fills out a Web form and then presses a button to submit the information. Pressing the button gathers the information from the various form items and sends them to the server, which forwards them to the CGI script that is specified as the recipient.




<html>
   <title>
     Finger Gateway 2
   </title>
   <body>
     <h3>Finger Gateway 2</h3>
     <form action=".../finger.ss"
           method="post">
       <input type="text"
              name="who" />
       <input type="submit"
           value="FINGER" />
  </form>
</body>
</html> 

Figure 17:  A Web form

Take a look at figure 17. The left column contains a Web page specification in XHTML -- an HTML version that satisfies XML standards (see section 2). The right column shows what the page looks like in a Web browser.

;Binding = (cons (union sym str) string)

;Bindings = (listof binding)

;HTML-string = strings that conform to HTML conventions

;


;; output-http-headers : -> void
;; to print all the http headers needed for a normal HTML response

;; get-bindings : -> Bindings
;; to produce the bindings in the given HTTP request

;; extract-bindings : (union symbol string) Bindings -> (listof string)
;; to extract all strings associated with a given key

;; extract-binding/single : (union symbol string) Bindings -> string
;; to determine that there is exactly one binding for a given key and
;; to extract this string

;; stringhtml : string -> HTML-string
;; to convert a plain string into an HTML-string

Figure 18:  Scheme's basic functions for CGI scripts

The specification describes the body as a two-part entity: a title and a form. Between the form tags we see two input tags. The first one specifies a text field, into which a user can type a line of text. The second one is a submit button. When the user clicks on this button, the form submits the user's inputs according to the protocol specified with the <form> tag.

Each form has two attributes: a method and an action. In our example, the method is post; the action -- see the underlined part -- is a URL that points to a CGI script. When the action attribute points to a CGI script, a click on the submit button requests from the server to invoke the CGI script and to submit the user inputs to the script as a list of bindings. In our example, there is a single binding: who.

For a Scheme CGI script, a binding is a cons cell that contains a symbol (or a string) and a string. The symbol is called a key; the string is a value. A script may obtain all inputs as a list of bindings via (get-bindings). To extract the values for a specific key, the script can use extract-bindings, which extracts the list of strings for all occurrences of the key. If the key doesn't occur, the list is empty. If the key occurs exactly once, the script can use extract-binding/single instead. It ensures that there is exactly one binding for the given key, and it produces the string associated with this binding. These data definitions and operations are specified in figure 18.

(define FINGER "/usr/bin/finger")

;; read-all : iport -> (listof string)
(define (read-all ip)
  (let ([next (read-line ip)])
    (cond
      [(eof-object? next) '()]
      [else (cons next (read-all ip))])))

;; --- the script ---

(define the-bindings (get-bindings))

(define the-user (extract-binding/single 'who the-bindings))

(output-http-headers)

(write-xml/content 
 (xexprxml
   `(html
      (title "Finger Gateway")
      (body ([bgcolor "white"])
	(p ,(stringhtml (read-line (car (process "date")))))
	,@(map (lambda (x) `(p ,(stringhtml x)))
	       (read-all
		 (car
		   (process
		     (string-append FINGER " " the-user)))))))))

Figure 19:  A CGI finger server

For an illustration of these capabilities, let's extend the simple ``finger server'' from section 1. The front-end will be the Web form from figure 17. It accepts a username whose key is who. The CGI script fingers that user or fingers all currently logged in users if the who attribute is the empty string.

In contrast to the simple finger server in figure 16, the extended script must first obtain the inputs and especially the name:

(define the-bindings (get-bindings))

(define the-user (extract-binding/single 'who the-bindings))

It uses extract-binding/single to make sure that there is exactly only one who field.11

Now the script can run the finger program with an input:

... (process (string-append FINGER " " the-user)) ...

If the user doesn't fill in the text field of the Web form, the-user is the empty string. In that case, the string supplied to process is just the plain FINGER string.

The revised finger server is in figure 19. Unlike the original finger server in figure 19, the new program must be used in conjunction with a Web page. Otherwise it is impossible to supply a user name.


11 If someone else writes a Web page with, say a checkbox, then the who key may have several values. Using extract-binding/single is just one kind of erorr-checking; a robust CGI script does more.