blob: d4e5bffef9ed7a72015af26a73794d7c9d7945c7 [file] [log] [blame]
Guido van Rossum9a22de11995-01-12 12:29:47 +00001#!/usr/local/bin/python
Guido van Rossum1c9daa81995-09-18 21:52:37 +00002
Guido van Rossum72755611996-03-06 07:20:06 +00003"""Support module for CGI (Common Gateway Interface) scripts.
Guido van Rossum1c9daa81995-09-18 21:52:37 +00004
Guido van Rossum72755611996-03-06 07:20:06 +00005This module defines a number of utilities for use by CGI scripts written in
6Python.
Guido van Rossum9a22de11995-01-12 12:29:47 +00007
8
Guido van Rossum72755611996-03-06 07:20:06 +00009Introduction
10------------
11
Guido van Rossum391b4e61996-03-06 19:11:33 +000012A CGI script is invoked by an HTTP server, usually to process user
13input submitted through an HTML <FORM> or <ISINPUT> element.
Guido van Rossum72755611996-03-06 07:20:06 +000014
Guido van Rossum391b4e61996-03-06 19:11:33 +000015Most often, CGI scripts live in the server's special cgi-bin
16directory. The HTTP server places all sorts of information about the
17request (such as the client's hostname, the requested URL, the query
18string, and lots of other goodies) in the script's shell environment,
19executes the script, and sends the script's output back to the client.
Guido van Rossum72755611996-03-06 07:20:06 +000020
Guido van Rossum391b4e61996-03-06 19:11:33 +000021The script's input is connected to the client too, and sometimes the
22form data is read this way; at other times the form data is passed via
23the "query string" part of the URL. This module (cgi.py) is intended
24to take care of the different cases and provide a simpler interface to
25the Python script. It also provides a number of utilities that help
26in debugging scripts, and the latest addition is support for file
27uploads from a form (if your browser supports it -- Grail 0.3 and
28Netscape 2.0 do).
Guido van Rossum72755611996-03-06 07:20:06 +000029
Guido van Rossum391b4e61996-03-06 19:11:33 +000030The output of a CGI script should consist of two sections, separated
31by a blank line. The first section contains a number of headers,
32telling the client what kind of data is following. Python code to
33generate a minimal header section looks like this:
Guido van Rossum72755611996-03-06 07:20:06 +000034
35 print "Content-type: text/html" # HTML is following
36 print # blank line, end of headers
37
Guido van Rossum391b4e61996-03-06 19:11:33 +000038The second section is usually HTML, which allows the client software
39to display nicely formatted text with header, in-line images, etc.
40Here's Python code that prints a simple piece of HTML:
Guido van Rossum72755611996-03-06 07:20:06 +000041
42 print "<TITLE>CGI script output</TITLE>"
43 print "<H1>This is my first CGI script</H1>"
44 print "Hello, world!"
45
Guido van Rossum391b4e61996-03-06 19:11:33 +000046(It may not be fully legal HTML according to the letter of the
47standard, but any browser will understand it.)
Guido van Rossum72755611996-03-06 07:20:06 +000048
49
50Using the cgi module
51--------------------
52
Guido van Rossum391b4e61996-03-06 19:11:33 +000053Begin by writing "import cgi". Don't use "from cgi import *" -- the
54module defines all sorts of names for its own use that you don't want
55in your namespace.
Guido van Rossum72755611996-03-06 07:20:06 +000056
Guido van Rossum391b4e61996-03-06 19:11:33 +000057If you have a standard form, it's best to use the SvFormContentDict
58class. Instantiate the SvFormContentDict class exactly once: it
59consumes any input on standard input, which can't be wound back (it's
60a network connection, not a disk file).
Guido van Rossum72755611996-03-06 07:20:06 +000061
Guido van Rossum391b4e61996-03-06 19:11:33 +000062The SvFormContentDict instance can be accessed as if it were a Python
63dictionary. For instance, the following code checks that the fields
Guido van Rossum72755611996-03-06 07:20:06 +000064"name" and "addr" are both set to a non-empty string:
65
66 form = SvFormContentDict()
67 form_ok = 0
68 if form.has_key("name") and form.has_key("addr"):
69 if form["name"] != "" and form["addr"] != "":
70 form_ok = 1
71 if not form_ok:
72 print "<H1>Error</H1>"
73 print "Please fill in the name and addr fields."
74 return
75 ...actual form processing here...
76
Guido van Rossum391b4e61996-03-06 19:11:33 +000077If you have an input item of type "file" in your form and the client
78supports file uploads, the value for that field, if present in the
79form, is not a string but a tuple of (filename, content-type, data).
Guido van Rossum72755611996-03-06 07:20:06 +000080
81
82Overview of classes
83-------------------
84
Guido van Rossum391b4e61996-03-06 19:11:33 +000085SvFormContentDict: single value form content as dictionary; described
Guido van Rossum72755611996-03-06 07:20:06 +000086above.
87
Guido van Rossum391b4e61996-03-06 19:11:33 +000088FormContentDict: multiple value form content as dictionary (the form
89items are lists of values). Useful if your form contains multiple
90fields with the same name.
Guido van Rossum72755611996-03-06 07:20:06 +000091
Guido van Rossum391b4e61996-03-06 19:11:33 +000092Other classes (FormContent, InterpFormContentDict) are present for
Guido van Rossum72755611996-03-06 07:20:06 +000093backwards compatibility only.
94
95
96Overview of functions
97---------------------
98
Guido van Rossum391b4e61996-03-06 19:11:33 +000099These are useful if you want more control, or if you want to employ
100some of the algorithms implemented in this module in other
101circumstances.
Guido van Rossum72755611996-03-06 07:20:06 +0000102
103parse(): parse a form into a Python dictionary.
104
105parse_qs(qs): parse a query string.
106
Guido van Rossum391b4e61996-03-06 19:11:33 +0000107parse_multipart(...): parse input of type multipart/form-data (for
108file uploads).
Guido van Rossum72755611996-03-06 07:20:06 +0000109
Guido van Rossum391b4e61996-03-06 19:11:33 +0000110parse_header(string): parse a header like Content-type into a main
111value and a dictionary of parameters.
Guido van Rossum72755611996-03-06 07:20:06 +0000112
113test(): complete test program.
114
115print_environ(): format the shell environment in HTML.
116
117print_form(form): format a form in HTML.
118
Guido van Rossum391b4e61996-03-06 19:11:33 +0000119print_environ_usage(): print a list of useful environment variables in
120HTML.
Guido van Rossum72755611996-03-06 07:20:06 +0000121
Guido van Rossum391b4e61996-03-06 19:11:33 +0000122escape(): convert the characters "&", "<" and ">" to HTML-safe
123sequences. Use this if you need to display text that might contain
124such characters in HTML. To translate URLs for inclusion in the HREF
125attribute of an <A> tag, use urllib.quote().
Guido van Rossum72755611996-03-06 07:20:06 +0000126
127
128Caring about security
129---------------------
130
Guido van Rossum391b4e61996-03-06 19:11:33 +0000131There's one important rule: if you invoke an external program (e.g.
132via the os.system() or os.popen() functions), make very sure you don't
133pass arbitrary strings received from the client to the shell. This is
134a well-known security hole whereby clever hackers anywhere on the web
135can exploit a gullible CGI script to invoke arbitrary shell commands.
136Even parts of the URL or field names cannot be trusted, since the
137request doesn't have to come from your form!
Guido van Rossum72755611996-03-06 07:20:06 +0000138
Guido van Rossum391b4e61996-03-06 19:11:33 +0000139To be on the safe side, if you must pass a string gotten from a form
140to a shell command, you should make sure the string contains only
141alphanumeric characters, dashes, underscores, and periods.
Guido van Rossum72755611996-03-06 07:20:06 +0000142
143
144Installing your CGI script on a Unix system
145-------------------------------------------
146
Guido van Rossum391b4e61996-03-06 19:11:33 +0000147Read the documentation for your HTTP server and check with your local
148system administrator to find the directory where CGI scripts should be
Guido van Rossum72755611996-03-06 07:20:06 +0000149installed; usually this is in a directory cgi-bin in the server tree.
150
Guido van Rossum391b4e61996-03-06 19:11:33 +0000151Make sure that your script is readable and executable by "others"; the
152Unix file mode should be 755 (use "chmod 755 filename"). Make sure
153that the first line of the script contains "#!" starting in column 1
154followed by the pathname of the Python interpreter, for instance:
Guido van Rossum72755611996-03-06 07:20:06 +0000155
156 #!/usr/local/bin/python
157
Guido van Rossum391b4e61996-03-06 19:11:33 +0000158Make sure the Python interpreter exists and is executable by "others".
Guido van Rossum72755611996-03-06 07:20:06 +0000159
Guido van Rossum391b4e61996-03-06 19:11:33 +0000160Make sure that any files your script needs to read or write are
161readable or writable, respectively, by "others" -- their mode should
162be 644 for readable and 666 for writable. This is because, for
163security reasons, the HTTP server executes your script as user
164"nobody", without any special privileges. It can only read (write,
165execute) files that everybody can read (write, execute). The current
166directory at execution time is also different (it is usually the
167server's cgi-bin directory) and the set of environment variables is
168also different from what you get at login. in particular, don't count
169on the shell's search path for executables ($PATH) or the Python
170module search path ($PYTHONPATH) to be set to anything interesting.
Guido van Rossum72755611996-03-06 07:20:06 +0000171
Guido van Rossum391b4e61996-03-06 19:11:33 +0000172If you need to load modules from a directory which is not on Python's
173default module search path, you can change the path in your script,
174before importing other modules, e.g.:
Guido van Rossum72755611996-03-06 07:20:06 +0000175
176 import sys
177 sys.path.insert(0, "/usr/home/joe/lib/python")
178 sys.path.insert(0, "/usr/local/lib/python")
179
180(This way, the directory inserted last will be searched first!)
181
Guido van Rossum391b4e61996-03-06 19:11:33 +0000182Instructions for non-Unix systems will vary; check your HTTP server's
Guido van Rossum72755611996-03-06 07:20:06 +0000183documentation (it will usually have a section on CGI scripts).
184
185
186Testing your CGI script
187-----------------------
188
Guido van Rossum391b4e61996-03-06 19:11:33 +0000189Unfortunately, a CGI script will generally not run when you try it
190from the command line, and a script that works perfectly from the
191command line may fail mysteriously when run from the server. There's
192one reason why you should still test your script from the command
193line: if it contains a syntax error, the python interpreter won't
194execute it at all, and the HTTP server will most likely send a cryptic
195error to the client.
Guido van Rossum72755611996-03-06 07:20:06 +0000196
Guido van Rossum391b4e61996-03-06 19:11:33 +0000197Assuming your script has no syntax errors, yet it does not work, you
198have no choice but to read the next section:
Guido van Rossum72755611996-03-06 07:20:06 +0000199
200
201Debugging CGI scripts
202---------------------
203
Guido van Rossum391b4e61996-03-06 19:11:33 +0000204First of all, check for trivial installation errors -- reading the
205section above on installing your CGI script carefully can save you a
206lot of time. If you wonder whether you have understood the
207installation procedure correctly, try installing a copy of this module
208file (cgi.py) as a CGI script. When invoked as a script, the file
209will dump its environment and the contents of the form in HTML form.
210Give it the right mode etc, and send it a request. If it's installed
211in the standard cgi-bin directory, it should be possible to send it a
212request by entering a URL into your browser of the form:
Guido van Rossum72755611996-03-06 07:20:06 +0000213
214 http://yourhostname/cgi-bin/cgi.py?name=Joe+Blow&addr=At+Home
215
Guido van Rossum391b4e61996-03-06 19:11:33 +0000216If this gives an error of type 404, the server cannot find the script
217-- perhaps you need to install it in a different directory. If it
218gives another error (e.g. 500), there's an installation problem that
219you should fix before trying to go any further. If you get a nicely
220formatted listing of the environment and form content (in this
221example, the fields should be listed as "addr" with value "At Home"
222and "name" with value "Joe Blow"), the cgi.py script has been
223installed correctly. If you follow the same procedure for your own
224script, you should now be able to debug it.
Guido van Rossum72755611996-03-06 07:20:06 +0000225
Guido van Rossum391b4e61996-03-06 19:11:33 +0000226The next step could be to call the cgi module's test() function from
227your script: replace its main code with the single statement
Guido van Rossum72755611996-03-06 07:20:06 +0000228
229 cgi.test()
230
Guido van Rossum391b4e61996-03-06 19:11:33 +0000231This should produce the same results as those gotten from installing
232the cgi.py file itself.
Guido van Rossum72755611996-03-06 07:20:06 +0000233
Guido van Rossum391b4e61996-03-06 19:11:33 +0000234When an ordinary Python script raises an unhandled exception
235(e.g. because of a typo in a module name, a file that can't be opened,
236etc.), the Python interpreter prints a nice traceback and exits.
237While the Python interpreter will still do this when your CGI script
238raises an exception, most likely the traceback will end up in one of
239the HTTP server's log file, or be discarded altogether.
Guido van Rossum72755611996-03-06 07:20:06 +0000240
Guido van Rossum391b4e61996-03-06 19:11:33 +0000241Fortunately, once you have managed to get your script to execute
242*some* code, it is easy to catch exceptions and cause a traceback to
243be printed. The test() function below in this module is an example.
244Here are the rules:
Guido van Rossum72755611996-03-06 07:20:06 +0000245
Guido van Rossum391b4e61996-03-06 19:11:33 +0000246 1. Import the traceback module (before entering the
247 try-except!)
Guido van Rossum72755611996-03-06 07:20:06 +0000248
Guido van Rossum391b4e61996-03-06 19:11:33 +0000249 2. Make sure you finish printing the headers and the blank
250 line early
Guido van Rossum72755611996-03-06 07:20:06 +0000251
252 3. Assign sys.stderr to sys.stdout
253
254 3. Wrap all remaining code in a try-except statement
255
256 4. In the except clause, call traceback.print_exc()
257
258For example:
259
260 import sys
261 import traceback
262 print "Content-type: text/html"
263 print
264 sys.stderr = sys.stdout
265 try:
266 ...your code here...
267 except:
268 print "\n\n<PRE>"
269 traceback.print_exc()
270
Guido van Rossum391b4e61996-03-06 19:11:33 +0000271Notes: The assignment to sys.stderr is needed because the traceback
272prints to sys.stderr. The print "\n\n<PRE>" statement is necessary to
273disable the word wrapping in HTML.
Guido van Rossum72755611996-03-06 07:20:06 +0000274
Guido van Rossum391b4e61996-03-06 19:11:33 +0000275If you suspect that there may be a problem in importing the traceback
276module, you can use an even more robust approach (which only uses
277built-in modules):
Guido van Rossum72755611996-03-06 07:20:06 +0000278
279 import sys
280 sys.stderr = sys.stdout
281 print "Content-type: text/plain"
282 print
283 ...your code here...
284
Guido van Rossum391b4e61996-03-06 19:11:33 +0000285This relies on the Python interpreter to print the traceback. The
286content type of the output is set to plain text, which disables all
287HTML processing. If your script works, the raw HTML will be displayed
288by your client. If it raises an exception, most likely after the
289first two lines have been printed, a traceback will be displayed.
290Because no HTML interpretation is going on, the traceback will
291readable.
Guido van Rossum72755611996-03-06 07:20:06 +0000292
293Good luck!
294
295
296Common problems and solutions
297-----------------------------
298
Guido van Rossum391b4e61996-03-06 19:11:33 +0000299- Most HTTP servers buffer the output from CGI scripts until the
300script is completed. This means that it is not possible to display a
301progress report on the client's display while the script is running.
Guido van Rossum72755611996-03-06 07:20:06 +0000302
303- Check the installation instructions above.
304
Guido van Rossum391b4e61996-03-06 19:11:33 +0000305- Check the HTTP server's log files. ("tail -f logfile" in a separate
Guido van Rossum72755611996-03-06 07:20:06 +0000306window may be useful!)
307
Guido van Rossum391b4e61996-03-06 19:11:33 +0000308- Always check a script for syntax errors first, by doing something
309like "python script.py".
Guido van Rossum72755611996-03-06 07:20:06 +0000310
311- When using any of the debugging techniques, don't forget to add
312"import sys" to the top of the script.
313
Guido van Rossum391b4e61996-03-06 19:11:33 +0000314- When invoking external programs, make sure they can be found.
315Usually, this means using absolute path names -- $PATH is usually not
316set to a very useful value in a CGI script.
Guido van Rossum72755611996-03-06 07:20:06 +0000317
Guido van Rossum391b4e61996-03-06 19:11:33 +0000318- When reading or writing external files, make sure they can be read
319or written by every user on the system.
Guido van Rossum72755611996-03-06 07:20:06 +0000320
Guido van Rossum391b4e61996-03-06 19:11:33 +0000321- Don't try to give a CGI script a set-uid mode. This doesn't work on
322most systems, and is a security liability as well.
Guido van Rossum72755611996-03-06 07:20:06 +0000323
324
325History
326-------
327
Guido van Rossum391b4e61996-03-06 19:11:33 +0000328Michael McLay started this module. Steve Majewski changed the
329interface to SvFormContentDict and FormContentDict. The multipart
330parsing was inspired by code submitted by Andreas Paepcke. Guido van
331Rossum rewrote, reformatted and documented the module and is currently
332responsible for its maintenance.
Guido van Rossum72755611996-03-06 07:20:06 +0000333
334"""
335
336
337# Imports
338# =======
339
340import string
341import regsub
342import sys
343import os
344import urllib
345
346
347# A shorthand for os.environ
348environ = os.environ
349
350
351# Parsing functions
352# =================
353
354def parse(fp=None):
355 """Parse a query in the environment or from a file (default stdin)"""
356 if not fp:
357 fp = sys.stdin
358 if not environ.has_key('REQUEST_METHOD'):
359 environ['REQUEST_METHOD'] = 'GET' # For testing
Guido van Rossum9a22de11995-01-12 12:29:47 +0000360 if environ['REQUEST_METHOD'] == 'POST':
Guido van Rossum72755611996-03-06 07:20:06 +0000361 ctype, pdict = parse_header(environ['CONTENT_TYPE'])
362 if ctype == 'multipart/form-data':
363 return parse_multipart(fp, ctype, pdict)
364 elif ctype == 'application/x-www-form-urlencoded':
365 clength = string.atoi(environ['CONTENT_LENGTH'])
366 qs = fp.read(clength)
367 else:
368 qs = '' # Bad content-type
Guido van Rossum9a22de11995-01-12 12:29:47 +0000369 environ['QUERY_STRING'] = qs
Guido van Rossum1c9daa81995-09-18 21:52:37 +0000370 elif environ.has_key('QUERY_STRING'):
Guido van Rossum9a22de11995-01-12 12:29:47 +0000371 qs = environ['QUERY_STRING']
Guido van Rossum1c9daa81995-09-18 21:52:37 +0000372 else:
Guido van Rossum72755611996-03-06 07:20:06 +0000373 if sys.argv[1:]:
374 qs = sys.argv[1]
375 else:
376 qs = ""
377 environ['QUERY_STRING'] = qs
Guido van Rossume7808771995-08-07 20:12:09 +0000378 return parse_qs(qs)
379
380
381def parse_qs(qs):
382 """Parse a query given as a string argument"""
Guido van Rossum9a22de11995-01-12 12:29:47 +0000383 name_value_pairs = string.splitfields(qs, '&')
384 dict = {}
385 for name_value in name_value_pairs:
386 nv = string.splitfields(name_value, '=')
387 if len(nv) != 2:
388 continue
389 name = nv[0]
Guido van Rossum391b4e61996-03-06 19:11:33 +0000390 value = urllib.unquote(regsub.gsub('+', ' ', nv[1]))
Guido van Rossum9a22de11995-01-12 12:29:47 +0000391 if len(value):
392 if dict.has_key (name):
393 dict[name].append(value)
394 else:
395 dict[name] = [value]
396 return dict
397
398
Guido van Rossum72755611996-03-06 07:20:06 +0000399def parse_multipart(fp, ctype, pdict):
400 """Parse multipart input.
Guido van Rossum9a22de11995-01-12 12:29:47 +0000401
Guido van Rossum72755611996-03-06 07:20:06 +0000402 Arguments:
403 fp : input file
404 ctype: content-type
405 pdict: dictionary containing other parameters of conten-type header
406
407 Returns a dictionary just like parse_qs() (keys are the field
408 names, each value is a list of values for that field) except
409 that if the value was an uploaded file, it is a tuple of the
410 form (filename, content-type, data). Note that content-type
411 is the raw, unparsed contents of the content-type header.
412
413 XXX Should we parse further when the content-type is
414 multipart/*?
415
416 """
417 import mimetools
418 if pdict.has_key('boundary'):
419 boundary = pdict['boundary']
420 else:
421 boundary = ""
422 nextpart = "--" + boundary
423 lastpart = "--" + boundary + "--"
424 partdict = {}
425 terminator = ""
426
427 while terminator != lastpart:
428 bytes = -1
429 data = None
430 if terminator:
431 # At start of next part. Read headers first.
432 headers = mimetools.Message(fp)
433 clength = headers.getheader('content-length')
434 if clength:
435 try:
436 bytes = string.atoi(clength)
437 except string.atoi_error:
438 pass
439 if bytes > 0:
440 data = fp.read(bytes)
441 else:
442 data = ""
443 # Read lines until end of part.
444 lines = []
445 while 1:
446 line = fp.readline()
447 if not line:
448 terminator = lastpart # End outer loop
449 break
450 if line[:2] == "--":
451 terminator = string.strip(line)
452 if terminator in (nextpart, lastpart):
453 break
454 if line[-2:] == '\r\n':
455 line = line[:-2]
456 elif line[-1:] == '\n':
457 line = line[:-1]
458 lines.append(line)
459 # Done with part.
460 if data is None:
461 continue
462 if bytes < 0:
463 data = string.joinfields(lines, "\n")
464 line = headers['content-disposition']
465 if not line:
466 continue
467 key, params = parse_header(line)
468 if key != 'form-data':
469 continue
470 if params.has_key('name'):
471 name = params['name']
472 else:
473 continue
474 if params.has_key('filename'):
475 data = (params['filename'],
476 headers.getheader('content-type'), data)
477 if partdict.has_key(name):
478 partdict[name].append(data)
479 else:
480 partdict[name] = [data]
481
482 return partdict
Guido van Rossum9a22de11995-01-12 12:29:47 +0000483
484
Guido van Rossum72755611996-03-06 07:20:06 +0000485def parse_header(line):
486 """Parse a Content-type like header.
487
488 Return the main content-type and a dictionary of options.
489
490 """
491 plist = map(string.strip, string.splitfields(line, ';'))
492 key = string.lower(plist[0])
493 del plist[0]
494 pdict = {}
495 for p in plist:
496 i = string.find(p, '=')
497 if i >= 0:
498 name = string.lower(string.strip(p[:i]))
499 value = string.strip(p[i+1:])
500 if len(value) >= 2 and value[0] == value[-1] == '"':
501 value = value[1:-1]
502 pdict[name] = value
503 return key, pdict
504
505
506# Main classes
507# ============
Guido van Rossum9a22de11995-01-12 12:29:47 +0000508
509class FormContentDict:
Guido van Rossum72755611996-03-06 07:20:06 +0000510 """Basic (multiple values per field) form content as dictionary.
511
512 form = FormContentDict()
513
514 form[key] -> [value, value, ...]
515 form.has_key(key) -> Boolean
516 form.keys() -> [key, key, ...]
517 form.values() -> [[val, val, ...], [val, val, ...], ...]
518 form.items() -> [(key, [val, val, ...]), (key, [val, val, ...]), ...]
519 form.dict == {key: [val, val, ...], ...}
520
521 """
Guido van Rossum9a22de11995-01-12 12:29:47 +0000522 def __init__( self ):
523 self.dict = parse()
524 self.query_string = environ['QUERY_STRING']
525 def __getitem__(self,key):
526 return self.dict[key]
527 def keys(self):
528 return self.dict.keys()
529 def has_key(self, key):
530 return self.dict.has_key(key)
531 def values(self):
532 return self.dict.values()
533 def items(self):
534 return self.dict.items()
535 def __len__( self ):
536 return len(self.dict)
537
538
Guido van Rossum9a22de11995-01-12 12:29:47 +0000539class SvFormContentDict(FormContentDict):
Guido van Rossum72755611996-03-06 07:20:06 +0000540 """Strict single-value expecting form content as dictionary.
541
Guido van Rossum391b4e61996-03-06 19:11:33 +0000542 IF you only expect a single value for each field, then
543 form[key] will return that single value. It will raise an
544 IndexError if that expectation is not true. IF you expect a
545 field to have possible multiple values, than you can use
546 form.getlist(key) to get all of the values. values() and
547 items() are a compromise: they return single strings where
548 there is a single value, and lists of strings otherwise.
Guido van Rossum72755611996-03-06 07:20:06 +0000549
550 """
551 def __getitem__(self, key):
552 if len(self.dict[key]) > 1:
Guido van Rossum9a22de11995-01-12 12:29:47 +0000553 raise IndexError, 'expecting a single value'
554 return self.dict[key][0]
Guido van Rossum72755611996-03-06 07:20:06 +0000555 def getlist(self, key):
Guido van Rossum9a22de11995-01-12 12:29:47 +0000556 return self.dict[key]
Guido van Rossum72755611996-03-06 07:20:06 +0000557 def values(self):
Guido van Rossum9a22de11995-01-12 12:29:47 +0000558 lis = []
Guido van Rossum72755611996-03-06 07:20:06 +0000559 for each in self.dict.values():
Guido van Rossum9a22de11995-01-12 12:29:47 +0000560 if len( each ) == 1 :
Guido van Rossum72755611996-03-06 07:20:06 +0000561 lis.append(each[0])
562 else: lis.append(each)
Guido van Rossum9a22de11995-01-12 12:29:47 +0000563 return lis
Guido van Rossum72755611996-03-06 07:20:06 +0000564 def items(self):
Guido van Rossum9a22de11995-01-12 12:29:47 +0000565 lis = []
566 for key,value in self.dict.items():
567 if len(value) == 1 :
Guido van Rossum72755611996-03-06 07:20:06 +0000568 lis.append((key, value[0]))
569 else: lis.append((key, value))
Guido van Rossum9a22de11995-01-12 12:29:47 +0000570 return lis
571
572
Guido van Rossum9a22de11995-01-12 12:29:47 +0000573class InterpFormContentDict(SvFormContentDict):
Guido van Rossum72755611996-03-06 07:20:06 +0000574 """This class is present for backwards compatibility only."""
Guido van Rossum9a22de11995-01-12 12:29:47 +0000575 def __getitem__( self, key ):
576 v = SvFormContentDict.__getitem__( self, key )
577 if v[0] in string.digits+'+-.' :
578 try: return string.atoi( v )
579 except ValueError:
580 try: return string.atof( v )
581 except ValueError: pass
582 return string.strip(v)
583 def values( self ):
584 lis = []
585 for key in self.keys():
586 try:
587 lis.append( self[key] )
588 except IndexError:
589 lis.append( self.dict[key] )
590 return lis
591 def items( self ):
592 lis = []
593 for key in self.keys():
594 try:
595 lis.append( (key, self[key]) )
596 except IndexError:
597 lis.append( (key, self.dict[key]) )
598 return lis
599
600
Guido van Rossum9a22de11995-01-12 12:29:47 +0000601class FormContent(FormContentDict):
Guido van Rossum72755611996-03-06 07:20:06 +0000602 """This class is present for backwards compatibility only."""
Guido van Rossum9a22de11995-01-12 12:29:47 +0000603 def values(self,key):
604 if self.dict.has_key(key):return self.dict[key]
605 else: return None
606 def indexed_value(self,key, location):
607 if self.dict.has_key(key):
608 if len (self.dict[key]) > location:
609 return self.dict[key][location]
610 else: return None
611 else: return None
612 def value(self,key):
613 if self.dict.has_key(key):return self.dict[key][0]
614 else: return None
615 def length(self,key):
616 return len (self.dict[key])
617 def stripped(self,key):
618 if self.dict.has_key(key):return string.strip(self.dict[key][0])
619 else: return None
620 def pars(self):
621 return self.dict
622
623
Guido van Rossum72755611996-03-06 07:20:06 +0000624# Test/debug code
625# ===============
Guido van Rossum9a22de11995-01-12 12:29:47 +0000626
Guido van Rossum72755611996-03-06 07:20:06 +0000627def test():
628 """Robust test CGI script.
629
630 Dump all information provided to the script in HTML form.
Guido van Rossum9a22de11995-01-12 12:29:47 +0000631
Guido van Rossum72755611996-03-06 07:20:06 +0000632 """
633 import traceback
634 print "Content-type: text/html"
635 print
636 sys.stderr = sys.stdout
637 try:
638 print_environ()
639 print_form(FormContentDict())
640 print
Guido van Rossum391b4e61996-03-06 19:11:33 +0000641 print "<H3>Current Working Directory:</H3>"
Guido van Rossum72755611996-03-06 07:20:06 +0000642 try:
643 pwd = os.getcwd()
644 except os.error, msg:
645 print "os.error:", escape(str(msg))
646 else:
647 print escape(pwd)
648 print
649 except:
650 print "\n\n<PRE>" # Turn of word wrap
651 traceback.print_exc()
Guido van Rossum9a22de11995-01-12 12:29:47 +0000652
Guido van Rossum72755611996-03-06 07:20:06 +0000653def print_environ():
654 """Dump the shell environment in HTML form."""
655 keys = environ.keys()
656 keys.sort()
657 print
658 print "<H3>Shell environment:</H3>"
659 print "<DL>"
660 for key in keys:
661 print "<DT>", escape(key), "<DD>", escape(environ[key])
662 print "</DL>"
663 print
664
665def print_form(form):
666 """Dump the contents of a form in HTML form."""
667 keys = form.keys()
668 keys.sort()
669 print
670 print "<H3>Form contents:</H3>"
671 print "<DL>"
672 for key in keys:
673 print "<DT>" + escape(key) + ":",
674 print "<i>" + escape(`type(form[key])`) + "</i>"
675 print "<DD>" + escape(`form[key]`)
676 print "</DL>"
677 print
Guido van Rossum9a22de11995-01-12 12:29:47 +0000678
679def print_environ_usage():
Guido van Rossum72755611996-03-06 07:20:06 +0000680 """Print a list of environment variables used by the CGI protocol."""
Guido van Rossum9a22de11995-01-12 12:29:47 +0000681 print """
Guido van Rossum72755611996-03-06 07:20:06 +0000682<H3>These environment variables could have been set:</H3>
683<UL>
Guido van Rossum9a22de11995-01-12 12:29:47 +0000684<LI>AUTH_TYPE
685<LI>CONTENT_LENGTH
686<LI>CONTENT_TYPE
687<LI>DATE_GMT
688<LI>DATE_LOCAL
689<LI>DOCUMENT_NAME
690<LI>DOCUMENT_ROOT
691<LI>DOCUMENT_URI
692<LI>GATEWAY_INTERFACE
693<LI>LAST_MODIFIED
694<LI>PATH
695<LI>PATH_INFO
696<LI>PATH_TRANSLATED
697<LI>QUERY_STRING
698<LI>REMOTE_ADDR
699<LI>REMOTE_HOST
700<LI>REMOTE_IDENT
701<LI>REMOTE_USER
702<LI>REQUEST_METHOD
703<LI>SCRIPT_NAME
704<LI>SERVER_NAME
705<LI>SERVER_PORT
706<LI>SERVER_PROTOCOL
707<LI>SERVER_ROOT
708<LI>SERVER_SOFTWARE
709</UL>
710"""
711
Guido van Rossum9a22de11995-01-12 12:29:47 +0000712
Guido van Rossum72755611996-03-06 07:20:06 +0000713# Utilities
714# =========
Guido van Rossum9a22de11995-01-12 12:29:47 +0000715
Guido van Rossum72755611996-03-06 07:20:06 +0000716def escape(s):
717 """Replace special characters '&', '<' and '>' by SGML entities."""
718 s = regsub.gsub("&", "&amp;", s) # Must be done first!
719 s = regsub.gsub("<", "&lt;", s)
720 s = regsub.gsub(">", "&gt;", s)
Guido van Rossumeb9e9d21995-02-27 13:16:11 +0000721 return s
Guido van Rossum9a22de11995-01-12 12:29:47 +0000722
Guido van Rossum9a22de11995-01-12 12:29:47 +0000723
Guido van Rossum72755611996-03-06 07:20:06 +0000724# Invoke mainline
725# ===============
726
727# Call test() when this file is run as a script (not imported as a module)
728if __name__ == '__main__':
729 test()