www.cgi
- CGI utility ¶Provides a few basic functions useful to write a CGI script.
In order to write CGI script easily, you may want to use
other modules, such as rfc.uri
(see rfc.uri
- URI parsing and construction),
text.html-lite
(see text.html-lite
- Simple HTML document construction) and
text.tree
(see text.tree
- Lazy text construction).
Note: it seems that there is no active formal specification for CGI. See http://w3c.org/CGI/ for more information.
{www.cgi
}
Normally, httpd passes a cgi program various information
via environment variables.
Most procedures in www.cgi
refer to them (meta-variables).
However, it is sometimes inconvenient to require environment variable access
while you’re developing cgi-related programs.
With this parameter, you can overrides the information of meta-variables.
Metavariables should be a list of two-element lists. Car of each inner list names the variable, and its cadr gives the value of the variable by string.
For example, the following code overrides REQUEST_METHOD
and QUERY_STRING
meta-variables during execution of
my-cgi-procedure
. (See Parameters,
for the details of parameterize
).
(parameterize ((cgi-metavariables '(("REQUEST_METHOD" "GET") ("QUERY_STRING" "x=foo")))) (my-cgi-procedure))
{www.cgi
}
Returns a value of cgi metavariable name.
This function first searches the parameter cgi-metavariables
,
and if the named variable is not found, calls sys-getenv
.
CGI scripts may want to use cgi-get-metavariable
instead
of directly calling sys-getenv
; doing so makes reuse of
the script easier.
{www.cgi
}
Parses query string and returns associative list of parameters.
When a keyword argument query-string is given, it is used
as a source query string. Otherwise, the function checks the
metavariable REQUEST_METHOD
and obtain the query string
depending on the value (either from stdin or from the
metavariable QUERY_STRING
).
If such a metavariable is not defined and
the current input port is a terminal, the function prompts the user
to type parameters; it is useful for interactive debugging.
(If you need just to decompose URL query string, you can use
uri-decompose-query
in rfc.uri
(see rfc.uri
- URI parsing and construction).
This procedure has more features useful for CGI scripting.)
If REQUEST_METHOD
is POST
, this procedure can handle
both application/x-www-form-urlencoded
and
multipart/form-data
as the enctype. The latter is usually
used if the form has file-uploading capability.
When the post data is sent by multipart/form-data
,
each content of the part is treated as a value of the parameter.
That is, the content of uploaded file will be seen as one big
chunk of a string. The other information, such as the original file
name, is discarded. If it is not desirable to read entire file
into a string, you can customize the behavior by the part-handler
argument. The details are explained in the "Handling file uploads"
section below.
When a true value is given to merge-cookies, the cookie
values obtained from the metavariable HTTP_COOKIE
are appended to the result.
Note that the query parameter may have multiple values,
so cdr
of each element in the result is a list, not an atom.
If no value is given to the parameter, #t
is placed as its value.
See the following example:
(cgi-parse-parameters :query-string "foo=123&bar=%22%3f%3f%22&bar=zz&buzz") ⇒ (("foo" "123") ("bar "\"??\"" "zz") ("buzz" #t))
{www.cgi
}
A convenient function to obtain a value of the parameter name from
parsed query string params, which is the value
cgi-parse-parameters
returns. Name should be a string.
Unless true value is given to list, the returned value is a scalar value. If more than one value is associated to name, only the first value is returned. If list is true, the returned value is always a list, even name has only one value.
After the value is retrieved, you can apply a procedure to convert the string value to the appropriate type by giving a procedure to the convert argument. The procedure must take one string argument. If list is true, the convert procedure is applied to each values.
If the parameter name doesn’t appear in the query,
a value given to the keyword argument default is returned;
the default value of default
is #f
if list is false, or ()
otherwise.
{www.cgi
}
Creates a text tree (see text.tree
- Lazy text construction) for the
HTTP header of the reply message. The most simple form is
like this:
(tree->string (cgi-header)) ⇒ "Content-type: text/html\r\n\r\n"
You can specify alternative content-type by the keyword argument
content-type. If you want to set cookies to the client,
specify a list of cookie strings to the keyword argument cookies.
You can use construct-cookie-string
(see rfc.cookie
- HTTP cookie handling)
to build such a list of cookie strings.
The keyword argument location may be used to generate
a Location:
header to redirect the client to the specified URI.
You can also specify the Status:
header by the keyword argument
status. A typical way to redirect the client is as follows:
(cgi-header :status "302 Moved Temporarily" :location target-uri)
{www.cgi
}
The value of this parameter specifies the character encoding scheme (CES)
used for CGI output by cgi-main
defined below.
The default value is Gauche’s native encoding.
If the parameter is set other than the native encoding, cgi-main
converts the output
encoding by gauche.charconv
module
(see gauche.charconv
- Character Code Conversion).
{www.cgi
}
A convenient wrapper function for CGI script.
This function calls cgi-parse-parameters
, then calls
proc with the result of cgi-parse-parameters
.
The keyword argument merge-cookies is passed to
cgi-parse-parameters
.
proc has to return a tree of strings
(see text.tree
- Lazy text construction), including the HTTP header.
cgi-main
outputs the returned tree to the current output port
by write-tree
, then returns zero.
If an error is signaled in proc, it is caught and an HTML
page reporting the error is generated. You can customize the
error page by providing a procedure to the on-error keyword argument.
The procedure takes an <condition>
object (see Conditions),
and has to return a tree of string for the error reporting HTML
page, including an HTTP header.
When output the result, cgi-main
refers to
the value of the parameter cgi-output-character-encoding
,
and converts the character encoding if necessary.
The output behavior of cgi-main
can be customized
by a keyword argument output-proc; if it is given,
the text tree (either the normal return value of proc,
or an error page constructed by the error handler) is passed
to the procedure given to output-proc. The procedure
is responsible to format and output a text to the current
output port, including character conversions, if necessary.
The keyword argument part-handlers are simply passed to
cgi-parse-parameters
, by which you can customize
how the file uploads should be handled. See the "Handling file
uploads" section below for the details.
If you specify to use temporary file(s) by it, cgi-main
makes sure to clean up them whenever proc exits,
even by error. See cgi-add-temporary-file
below
to utilize this feature for other purpose.
Before calling proc, cgi-main
changes the buffering mode
of the current error port to :line
(See port-buffering
in Common port operations for the details about the buffering mode).
This makes the error output easier for web servers to capture.
The following example shows the parameters given to the CGI program.
#!/usr/local/bin/gosh (use text.html-lite) (use www.cgi) (define (main args) (cgi-main (lambda (params) `(,(cgi-header) ,(html-doctype) ,(html:html (html:head (html:title "Example")) (html:body (html:table :border 1 (html:tr (html:th "Name") (html:th "Value")) (map (lambda (p) (html:tr (html:td (html-escape-string (car p))) (html:td (html-escape-string (x->string (cdr p)))))) params)))) ))))
{www.cgi
}
This is supposed to be called inside proc of cgi-main
.
It registers filename as a temporary file, which should be
unlinked when proc exits. It is a convenient way to ensure
that your cgi script won’t leave garbages even if it throws an error.
It is OK in proc to unlink or rename filename after
calling this procedure.
{www.cgi
}
Keeps a list of filenames registered by cgi-add-temporary-file
.
As explained in cgi-parse-parameters
above, file uploads
are handled transparently by default, taking the file content
as the value of the parameter. Sometimes you might want to change this
behavior, for the file might be quite big and you don’t want
to keep around a huge chunk of a string in memory. It is possible to
customize handling of file uploads of cgi-parse-parameters
and cgi-main
by part-handlers argument.
(The argument is only effective for the form data submitted by
multipart/form-data
enctype)
The part-handlers argument is, if given, a list of lists;
each inner list is a form of
(name-pattern action kv-list …)
.
Each uploaded file with a matching parameter name with name-pattern is
handled according to action. (Here, a parameter name
is the ’name’ attribute given to the input
element in the
submitted form, not the name of the uploaded file).
Name-pattern must be either a list of string (matches one of them),
a regexp, or #t
(matches anything).
Action must be either one of the followings:
#f
Default action, i.e. the content of the uploaded file is turned into a string and becomes the value of the parameter.
ignore
The uploaded content is discarded.
file
The uploaded content is saved in a temporary file. The value of the parameter is the pathname of the temporary file.
For this action, you can write an entry like
(name-pattern file prefix)
, to specify the
prefix of the pathname of the temporary file. For example, if you
specify ("image" file "/var/mycgi/incoming/img")
,
the file uploaded as "image"
parameter will be stored as
something like /var/mycgi/incoming/img49g2Ua.
The application should move the temporary file to appropriate
location; if you’re using cgi-main
, the temporary files
created by this action will be unlinked when cgi-main
exits.
file+name
Like file
, but the value of the parameter is a list of
temporary filename and the filename passed by the client.
It is useful if you want to use client’s filename (but do not
blindly assume the client sends a valid pathname; for example,
you shouldn’t use it to rename the uploaded file without
validating it).
procedure
In this case, procedure is called to handle the uploaded
contents. It is called with four arguments:
(procedure name filename part-info iport)
.
Name is the name of the parameter. Filename is
the name of the original file (pathname in the client).
Part-info is a <mime-part>
object that keeps information
about this mime part, and iport is where the body can be
read from.
For the details about these arguments,
see rfc.mime
- MIME message handling; you might be able to
use procedures provided by rfc.mime
, such as mime-retrieve-body
,
to construct your own procedure.
If you create a temporary file in procedure, you can call
cgi-add-temporary-file
to make sure it is removed even if
an error occurs during cgi processing.
If kv-list is given after action, it must be a keyword-value list and further modifies action. The following keywords are supported.
:prefix
Valid only if action is either file
or file+name
.
Specifies the prefix of the temporary file. If you give
:prefix "/tmp/foo"
, for example, the file is saved
as something like /tmp/fooxAgjeQ.
:mode
Valid only if action is either file
or file+name
.
Specifies the mode of the temporary file in unix-style integer. By default
it is #o600
.
Note that the parameters that are not file uploads are not the subject of part-handlers; such parameter values are always turned into a string.
Here’s a short example. Suppose you have a form like this:
<form enctype="multipart/form-data" method="POST" action="mycgi.cgi"> <input type="file" name="imagefile" /> <input type="text" name="description" /> <input type="hidden" name="mode" value="normal" /> </form>
If you use cgi-parse-parameters
in mycgi.cgi
without part-handlers argument,
you’ll get something like the following as the result.
(The actual values depend on how the web client filled the form).
(("imagefile" #**".....(image file content as a string)....") ("description" "my image") ("mode" "normal"))
If you pass '(("imagefile" file :prefix "/tmp/mycgi"))
to part-handlers
instead,
you might get something like the following, with the
content of uploaded file saved in /tmp/mycgi7gq0B
(("imagefile" "/tmp/mycgi7gq0B") ("description" "my image") ("mode" "normal"))
If you use a symbol file+name
instead of file
above,
you’ll get something like ("/tmp/mycgi7gq0B" "logo.jpg")
as
the value of "imagefile"
, where "logo.jpg"
is the
client-side filename. (Note: the client can send any string
as the name of the file, so never assume it is a valid
pathname).