blob: ab6dda843606a22db2430e37fa39e36e3154a00b [file] [log] [blame]
Guido van Rossum152f9d91997-02-18 16:55:33 +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 Rossum7aee3841996-03-07 18:00:44 +00005This module defines a number of utilities for use by CGI scripts
6written in Python.
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
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000035 print "Content-type: text/html" # HTML is following
36 print # blank line, end of headers
Guido van Rossum72755611996-03-06 07:20:06 +000037
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
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000042 print "<TITLE>CGI script output</TITLE>"
43 print "<H1>This is my first CGI script</H1>"
44 print "Hello, world!"
Guido van Rossum72755611996-03-06 07:20:06 +000045
Guido van Rossum43055421997-05-28 15:11:01 +000046It 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
Guido van Rossum0147db01996-03-09 03:16:04 +000054module defines all sorts of names for its own use or for backward
55compatibility that you don't want in your namespace.
Guido van Rossum72755611996-03-06 07:20:06 +000056
Guido van Rossum0147db01996-03-09 03:16:04 +000057It's best to use the FieldStorage class. The other classes define in this
58module are provided mostly for backward compatibility. Instantiate it
59exactly once, without arguments. This reads the form contents from
60standard input or the environment (depending on the value of various
61environment variables set according to the CGI standard). Since it may
62consume standard input, it should be instantiated only once.
Guido van Rossum72755611996-03-06 07:20:06 +000063
Guido van Rossum0147db01996-03-09 03:16:04 +000064The FieldStorage instance can be accessed as if it were a Python
65dictionary. For instance, the following code (which assumes that the
66Content-type header and blank line have already been printed) checks that
67the fields "name" and "addr" are both set to a non-empty string:
Guido van Rossum72755611996-03-06 07:20:06 +000068
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000069 form = cgi.FieldStorage()
70 form_ok = 0
71 if form.has_key("name") and form.has_key("addr"):
72 if form["name"].value != "" and form["addr"].value != "":
73 form_ok = 1
74 if not form_ok:
75 print "<H1>Error</H1>"
76 print "Please fill in the name and addr fields."
77 return
78 ...further form processing here...
Guido van Rossum72755611996-03-06 07:20:06 +000079
Guido van Rossum4032c2c1996-03-09 04:04:35 +000080Here the fields, accessed through form[key], are themselves instances
81of FieldStorage (or MiniFieldStorage, depending on the form encoding).
Guido van Rossum72755611996-03-06 07:20:06 +000082
Guido van Rossum4032c2c1996-03-09 04:04:35 +000083If the submitted form data contains more than one field with the same
84name, the object retrieved by form[key] is not a (Mini)FieldStorage
Guido van Rossum43055421997-05-28 15:11:01 +000085instance but a list of such instances. If you are expecting this
86possibility (i.e., when your HTML form comtains multiple fields with
87the same name), use the type() function to determine whether you have
88a single instance or a list of instances. For example, here's code
89that concatenates any number of username fields, separated by commas:
Guido van Rossum4032c2c1996-03-09 04:04:35 +000090
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000091 username = form["username"]
92 if type(username) is type([]):
93 # Multiple username fields specified
94 usernames = ""
95 for item in username:
96 if usernames:
97 # Next item -- insert comma
98 usernames = usernames + "," + item.value
99 else:
100 # First item -- don't insert comma
101 usernames = item.value
102 else:
103 # Single username field specified
104 usernames = username.value
Guido van Rossum0147db01996-03-09 03:16:04 +0000105
106If a field represents an uploaded file, the value attribute reads the
107entire file in memory as a string. This may not be what you want. You can
108test for an uploaded file by testing either the filename attribute or the
109file attribute. You can then read the data at leasure from the file
110attribute:
111
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000112 fileitem = form["userfile"]
113 if fileitem.file:
114 # It's an uploaded file; count lines
115 linecount = 0
116 while 1:
117 line = fileitem.file.readline()
118 if not line: break
119 linecount = linecount + 1
Guido van Rossum0147db01996-03-09 03:16:04 +0000120
Guido van Rossum4032c2c1996-03-09 04:04:35 +0000121The file upload draft standard entertains the possibility of uploading
122multiple files from one field (using a recursive multipart/*
123encoding). When this occurs, the item will be a dictionary-like
124FieldStorage item. This can be determined by testing its type
125attribute, which should have the value "multipart/form-data" (or
126perhaps another string beginning with "multipart/"). It this case, it
127can be iterated over recursively just like the top-level form object.
128
Guido van Rossum0147db01996-03-09 03:16:04 +0000129When a form is submitted in the "old" format (as the query string or as a
130single data part of type application/x-www-form-urlencoded), the items
131will actually be instances of the class MiniFieldStorage. In this case,
132the list, file and filename attributes are always None.
Guido van Rossum7aee3841996-03-07 18:00:44 +0000133
Guido van Rossum72755611996-03-06 07:20:06 +0000134
Guido van Rossum0147db01996-03-09 03:16:04 +0000135Old classes
136-----------
Guido van Rossum72755611996-03-06 07:20:06 +0000137
Guido van Rossum0147db01996-03-09 03:16:04 +0000138These classes, present in earlier versions of the cgi module, are still
Guido van Rossum16d5b111996-10-24 14:44:32 +0000139supported for backward compatibility. New applications should use the
140FieldStorage class.
Guido van Rossum7aee3841996-03-07 18:00:44 +0000141
Guido van Rossum0147db01996-03-09 03:16:04 +0000142SvFormContentDict: single value form content as dictionary; assumes each
143field name occurs in the form only once.
Guido van Rossum72755611996-03-06 07:20:06 +0000144
Guido van Rossum391b4e61996-03-06 19:11:33 +0000145FormContentDict: multiple value form content as dictionary (the form
146items are lists of values). Useful if your form contains multiple
147fields with the same name.
Guido van Rossum72755611996-03-06 07:20:06 +0000148
Guido van Rossum391b4e61996-03-06 19:11:33 +0000149Other classes (FormContent, InterpFormContentDict) are present for
Guido van Rossum0147db01996-03-09 03:16:04 +0000150backwards compatibility with really old applications only. If you still
151use these and would be inconvenienced when they disappeared from a next
152version of this module, drop me a note.
Guido van Rossum72755611996-03-06 07:20:06 +0000153
154
Guido van Rossum0147db01996-03-09 03:16:04 +0000155Functions
156---------
Guido van Rossum72755611996-03-06 07:20:06 +0000157
Guido van Rossum391b4e61996-03-06 19:11:33 +0000158These are useful if you want more control, or if you want to employ
159some of the algorithms implemented in this module in other
160circumstances.
Guido van Rossum72755611996-03-06 07:20:06 +0000161
Guido van Rossume08c04c1996-11-11 19:29:11 +0000162parse(fp, [environ, [keep_blank_values, [strict_parsing]]]): parse a
163form into a Python dictionary.
Guido van Rossum72755611996-03-06 07:20:06 +0000164
Guido van Rossume08c04c1996-11-11 19:29:11 +0000165parse_qs(qs, [keep_blank_values, [strict_parsing]]): parse a query
166string (data of type application/x-www-form-urlencoded).
Guido van Rossum72755611996-03-06 07:20:06 +0000167
Guido van Rossum0147db01996-03-09 03:16:04 +0000168parse_multipart(fp, pdict): parse input of type multipart/form-data (for
Guido van Rossum391b4e61996-03-06 19:11:33 +0000169file uploads).
Guido van Rossum72755611996-03-06 07:20:06 +0000170
Guido van Rossum391b4e61996-03-06 19:11:33 +0000171parse_header(string): parse a header like Content-type into a main
172value and a dictionary of parameters.
Guido van Rossum72755611996-03-06 07:20:06 +0000173
174test(): complete test program.
175
176print_environ(): format the shell environment in HTML.
177
178print_form(form): format a form in HTML.
179
Guido van Rossum391b4e61996-03-06 19:11:33 +0000180print_environ_usage(): print a list of useful environment variables in
181HTML.
Guido van Rossum72755611996-03-06 07:20:06 +0000182
Guido van Rossum391b4e61996-03-06 19:11:33 +0000183escape(): convert the characters "&", "<" and ">" to HTML-safe
184sequences. Use this if you need to display text that might contain
185such characters in HTML. To translate URLs for inclusion in the HREF
186attribute of an <A> tag, use urllib.quote().
Guido van Rossum72755611996-03-06 07:20:06 +0000187
Guido van Rossumc204c701996-09-05 19:07:11 +0000188log(fmt, ...): write a line to a log file; see docs for initlog().
189
Guido van Rossum72755611996-03-06 07:20:06 +0000190
191Caring about security
192---------------------
193
Guido van Rossum391b4e61996-03-06 19:11:33 +0000194There's one important rule: if you invoke an external program (e.g.
195via the os.system() or os.popen() functions), make very sure you don't
196pass arbitrary strings received from the client to the shell. This is
197a well-known security hole whereby clever hackers anywhere on the web
198can exploit a gullible CGI script to invoke arbitrary shell commands.
199Even parts of the URL or field names cannot be trusted, since the
200request doesn't have to come from your form!
Guido van Rossum72755611996-03-06 07:20:06 +0000201
Guido van Rossum391b4e61996-03-06 19:11:33 +0000202To be on the safe side, if you must pass a string gotten from a form
203to a shell command, you should make sure the string contains only
204alphanumeric characters, dashes, underscores, and periods.
Guido van Rossum72755611996-03-06 07:20:06 +0000205
206
207Installing your CGI script on a Unix system
208-------------------------------------------
209
Guido van Rossum391b4e61996-03-06 19:11:33 +0000210Read the documentation for your HTTP server and check with your local
211system administrator to find the directory where CGI scripts should be
Guido van Rossum72755611996-03-06 07:20:06 +0000212installed; usually this is in a directory cgi-bin in the server tree.
213
Guido van Rossum391b4e61996-03-06 19:11:33 +0000214Make sure that your script is readable and executable by "others"; the
215Unix file mode should be 755 (use "chmod 755 filename"). Make sure
Guido van Rossum43055421997-05-28 15:11:01 +0000216that the first line of the script contains #! starting in column 1
Guido van Rossum391b4e61996-03-06 19:11:33 +0000217followed by the pathname of the Python interpreter, for instance:
Guido van Rossum72755611996-03-06 07:20:06 +0000218
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000219 #! /usr/local/bin/python
Guido van Rossum72755611996-03-06 07:20:06 +0000220
Guido van Rossum391b4e61996-03-06 19:11:33 +0000221Make sure the Python interpreter exists and is executable by "others".
Guido van Rossum72755611996-03-06 07:20:06 +0000222
Guido van Rossum43055421997-05-28 15:11:01 +0000223Note that it's probably not a good idea to use #! /usr/bin/env python
Guido van Rossumf06ee5f1996-11-27 19:52:01 +0000224here, since the Python interpreter may not be on the default path
Guido van Rossum43055421997-05-28 15:11:01 +0000225given to CGI scripts!!!
Guido van Rossumf06ee5f1996-11-27 19:52:01 +0000226
Guido van Rossum391b4e61996-03-06 19:11:33 +0000227Make sure that any files your script needs to read or write are
228readable or writable, respectively, by "others" -- their mode should
229be 644 for readable and 666 for writable. This is because, for
230security reasons, the HTTP server executes your script as user
231"nobody", without any special privileges. It can only read (write,
232execute) files that everybody can read (write, execute). The current
233directory at execution time is also different (it is usually the
234server's cgi-bin directory) and the set of environment variables is
235also different from what you get at login. in particular, don't count
236on the shell's search path for executables ($PATH) or the Python
237module search path ($PYTHONPATH) to be set to anything interesting.
Guido van Rossum72755611996-03-06 07:20:06 +0000238
Guido van Rossum391b4e61996-03-06 19:11:33 +0000239If you need to load modules from a directory which is not on Python's
240default module search path, you can change the path in your script,
241before importing other modules, e.g.:
Guido van Rossum72755611996-03-06 07:20:06 +0000242
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000243 import sys
244 sys.path.insert(0, "/usr/home/joe/lib/python")
245 sys.path.insert(0, "/usr/local/lib/python")
Guido van Rossum72755611996-03-06 07:20:06 +0000246
Guido van Rossum43055421997-05-28 15:11:01 +0000247This way, the directory inserted last will be searched first!
Guido van Rossum72755611996-03-06 07:20:06 +0000248
Guido van Rossum391b4e61996-03-06 19:11:33 +0000249Instructions for non-Unix systems will vary; check your HTTP server's
Guido van Rossum72755611996-03-06 07:20:06 +0000250documentation (it will usually have a section on CGI scripts).
251
252
253Testing your CGI script
254-----------------------
255
Guido van Rossum391b4e61996-03-06 19:11:33 +0000256Unfortunately, a CGI script will generally not run when you try it
257from the command line, and a script that works perfectly from the
258command line may fail mysteriously when run from the server. There's
259one reason why you should still test your script from the command
260line: if it contains a syntax error, the python interpreter won't
261execute it at all, and the HTTP server will most likely send a cryptic
262error to the client.
Guido van Rossum72755611996-03-06 07:20:06 +0000263
Guido van Rossum391b4e61996-03-06 19:11:33 +0000264Assuming your script has no syntax errors, yet it does not work, you
265have no choice but to read the next section:
Guido van Rossum72755611996-03-06 07:20:06 +0000266
267
268Debugging CGI scripts
269---------------------
270
Guido van Rossum391b4e61996-03-06 19:11:33 +0000271First of all, check for trivial installation errors -- reading the
272section above on installing your CGI script carefully can save you a
273lot of time. If you wonder whether you have understood the
274installation procedure correctly, try installing a copy of this module
275file (cgi.py) as a CGI script. When invoked as a script, the file
276will dump its environment and the contents of the form in HTML form.
277Give it the right mode etc, and send it a request. If it's installed
278in the standard cgi-bin directory, it should be possible to send it a
279request by entering a URL into your browser of the form:
Guido van Rossum72755611996-03-06 07:20:06 +0000280
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000281 http://yourhostname/cgi-bin/cgi.py?name=Joe+Blow&addr=At+Home
Guido van Rossum72755611996-03-06 07:20:06 +0000282
Guido van Rossum391b4e61996-03-06 19:11:33 +0000283If this gives an error of type 404, the server cannot find the script
284-- perhaps you need to install it in a different directory. If it
285gives another error (e.g. 500), there's an installation problem that
286you should fix before trying to go any further. If you get a nicely
287formatted listing of the environment and form content (in this
288example, the fields should be listed as "addr" with value "At Home"
289and "name" with value "Joe Blow"), the cgi.py script has been
290installed correctly. If you follow the same procedure for your own
291script, you should now be able to debug it.
Guido van Rossum72755611996-03-06 07:20:06 +0000292
Guido van Rossum391b4e61996-03-06 19:11:33 +0000293The next step could be to call the cgi module's test() function from
294your script: replace its main code with the single statement
Guido van Rossum72755611996-03-06 07:20:06 +0000295
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000296 cgi.test()
297
Guido van Rossum391b4e61996-03-06 19:11:33 +0000298This should produce the same results as those gotten from installing
299the cgi.py file itself.
Guido van Rossum72755611996-03-06 07:20:06 +0000300
Guido van Rossum43055421997-05-28 15:11:01 +0000301When an ordinary Python script raises an unhandled exception (e.g.,
302because of a typo in a module name, a file that can't be opened,
Guido van Rossum391b4e61996-03-06 19:11:33 +0000303etc.), the Python interpreter prints a nice traceback and exits.
304While the Python interpreter will still do this when your CGI script
305raises an exception, most likely the traceback will end up in one of
306the HTTP server's log file, or be discarded altogether.
Guido van Rossum72755611996-03-06 07:20:06 +0000307
Guido van Rossum391b4e61996-03-06 19:11:33 +0000308Fortunately, once you have managed to get your script to execute
309*some* code, it is easy to catch exceptions and cause a traceback to
310be printed. The test() function below in this module is an example.
311Here are the rules:
Guido van Rossum72755611996-03-06 07:20:06 +0000312
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000313 1. Import the traceback module (before entering the
314 try-except!)
315
316 2. Make sure you finish printing the headers and the blank
317 line early
318
319 3. Assign sys.stderr to sys.stdout
320
321 3. Wrap all remaining code in a try-except statement
322
323 4. In the except clause, call traceback.print_exc()
Guido van Rossum72755611996-03-06 07:20:06 +0000324
325For example:
326
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000327 import sys
328 import traceback
329 print "Content-type: text/html"
330 print
331 sys.stderr = sys.stdout
332 try:
333 ...your code here...
334 except:
335 print "\n\n<PRE>"
336 traceback.print_exc()
Guido van Rossum72755611996-03-06 07:20:06 +0000337
Guido van Rossum391b4e61996-03-06 19:11:33 +0000338Notes: The assignment to sys.stderr is needed because the traceback
339prints to sys.stderr. The print "\n\n<PRE>" statement is necessary to
340disable the word wrapping in HTML.
Guido van Rossum72755611996-03-06 07:20:06 +0000341
Guido van Rossum391b4e61996-03-06 19:11:33 +0000342If you suspect that there may be a problem in importing the traceback
343module, you can use an even more robust approach (which only uses
344built-in modules):
Guido van Rossum72755611996-03-06 07:20:06 +0000345
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000346 import sys
347 sys.stderr = sys.stdout
348 print "Content-type: text/plain"
349 print
350 ...your code here...
Guido van Rossum72755611996-03-06 07:20:06 +0000351
Guido van Rossum391b4e61996-03-06 19:11:33 +0000352This relies on the Python interpreter to print the traceback. The
353content type of the output is set to plain text, which disables all
354HTML processing. If your script works, the raw HTML will be displayed
355by your client. If it raises an exception, most likely after the
356first two lines have been printed, a traceback will be displayed.
357Because no HTML interpretation is going on, the traceback will
358readable.
Guido van Rossum72755611996-03-06 07:20:06 +0000359
Guido van Rossumc204c701996-09-05 19:07:11 +0000360When all else fails, you may want to insert calls to log() to your
361program or even to a copy of the cgi.py file. Note that this requires
362you to set cgi.logfile to the name of a world-writable file before the
363first call to log() is made!
364
Guido van Rossum72755611996-03-06 07:20:06 +0000365Good luck!
366
367
368Common problems and solutions
369-----------------------------
370
Guido van Rossum391b4e61996-03-06 19:11:33 +0000371- Most HTTP servers buffer the output from CGI scripts until the
372script is completed. This means that it is not possible to display a
373progress report on the client's display while the script is running.
Guido van Rossum72755611996-03-06 07:20:06 +0000374
375- Check the installation instructions above.
376
Guido van Rossum391b4e61996-03-06 19:11:33 +0000377- Check the HTTP server's log files. ("tail -f logfile" in a separate
Guido van Rossum72755611996-03-06 07:20:06 +0000378window may be useful!)
379
Guido van Rossum391b4e61996-03-06 19:11:33 +0000380- Always check a script for syntax errors first, by doing something
381like "python script.py".
Guido van Rossum72755611996-03-06 07:20:06 +0000382
383- When using any of the debugging techniques, don't forget to add
384"import sys" to the top of the script.
385
Guido van Rossum391b4e61996-03-06 19:11:33 +0000386- When invoking external programs, make sure they can be found.
387Usually, this means using absolute path names -- $PATH is usually not
388set to a very useful value in a CGI script.
Guido van Rossum72755611996-03-06 07:20:06 +0000389
Guido van Rossum391b4e61996-03-06 19:11:33 +0000390- When reading or writing external files, make sure they can be read
391or written by every user on the system.
Guido van Rossum72755611996-03-06 07:20:06 +0000392
Guido van Rossum391b4e61996-03-06 19:11:33 +0000393- Don't try to give a CGI script a set-uid mode. This doesn't work on
394most systems, and is a security liability as well.
Guido van Rossum72755611996-03-06 07:20:06 +0000395
396
397History
398-------
399
Guido van Rossum391b4e61996-03-06 19:11:33 +0000400Michael McLay started this module. Steve Majewski changed the
401interface to SvFormContentDict and FormContentDict. The multipart
402parsing was inspired by code submitted by Andreas Paepcke. Guido van
403Rossum rewrote, reformatted and documented the module and is currently
404responsible for its maintenance.
Guido van Rossum72755611996-03-06 07:20:06 +0000405
Guido van Rossum0147db01996-03-09 03:16:04 +0000406
407XXX The module is getting pretty heavy with all those docstrings.
408Perhaps there should be a slimmed version that doesn't contain all those
409backwards compatible and debugging classes and functions?
410
Guido van Rossum72755611996-03-06 07:20:06 +0000411"""
412
Guido van Rossum5f322481997-04-11 18:20:42 +0000413__version__ = "2.2"
Guido van Rossum0147db01996-03-09 03:16:04 +0000414
Guido van Rossum72755611996-03-06 07:20:06 +0000415
416# Imports
417# =======
418
419import string
Guido van Rossum72755611996-03-06 07:20:06 +0000420import sys
421import os
Guido van Rossuma5e9fb61997-08-12 18:18:13 +0000422import urllib
Guido van Rossuma5e9fb61997-08-12 18:18:13 +0000423import mimetools
424import rfc822
425from StringIO import StringIO
Guido van Rossum72755611996-03-06 07:20:06 +0000426
Guido van Rossumc204c701996-09-05 19:07:11 +0000427
428# Logging support
429# ===============
430
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000431logfile = "" # Filename to log to, if not empty
432logfp = None # File object to log to, if not None
Guido van Rossumc204c701996-09-05 19:07:11 +0000433
434def initlog(*allargs):
435 """Write a log message, if there is a log file.
436
437 Even though this function is called initlog(), you should always
438 use log(); log is a variable that is set either to initlog
439 (initially), to dolog (once the log file has been opened), or to
440 nolog (when logging is disabled).
441
442 The first argument is a format string; the remaining arguments (if
443 any) are arguments to the % operator, so e.g.
444 log("%s: %s", "a", "b")
445 will write "a: b" to the log file, followed by a newline.
446
447 If the global logfp is not None, it should be a file object to
448 which log data is written.
449
450 If the global logfp is None, the global logfile may be a string
451 giving a filename to open, in append mode. This file should be
452 world writable!!! If the file can't be opened, logging is
453 silently disabled (since there is no safe place where we could
454 send an error message).
455
456 """
457 global logfp, log
458 if logfile and not logfp:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000459 try:
460 logfp = open(logfile, "a")
461 except IOError:
462 pass
Guido van Rossumc204c701996-09-05 19:07:11 +0000463 if not logfp:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000464 log = nolog
Guido van Rossumc204c701996-09-05 19:07:11 +0000465 else:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000466 log = dolog
Guido van Rossumc204c701996-09-05 19:07:11 +0000467 apply(log, allargs)
468
469def dolog(fmt, *args):
470 """Write a log message to the log file. See initlog() for docs."""
471 logfp.write(fmt%args + "\n")
472
473def nolog(*allargs):
474 """Dummy function, assigned to log when logging is disabled."""
475 pass
476
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000477log = initlog # The current logging function
Guido van Rossumc204c701996-09-05 19:07:11 +0000478
479
Guido van Rossum72755611996-03-06 07:20:06 +0000480# Parsing functions
481# =================
482
Guido van Rossumad164711997-05-13 19:03:23 +0000483# Maximum input we will accept when REQUEST_METHOD is POST
484# 0 ==> unlimited input
485maxlen = 0
486
Guido van Rossume08c04c1996-11-11 19:29:11 +0000487def parse(fp=None, environ=os.environ, keep_blank_values=0, strict_parsing=0):
Guido van Rossum773ab271996-07-23 03:46:24 +0000488 """Parse a query in the environment or from a file (default stdin)
489
490 Arguments, all optional:
491
492 fp : file pointer; default: sys.stdin
493
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000494 environ : environment dictionary; default: os.environ
Guido van Rossum773ab271996-07-23 03:46:24 +0000495
496 keep_blank_values: flag indicating whether blank values in
497 URL encoded forms should be treated as blank strings.
498 A true value inicates that blanks should be retained as
499 blank strings. The default false value indicates that
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000500 blank values are to be ignored and treated as if they were
501 not included.
Guido van Rossume08c04c1996-11-11 19:29:11 +0000502
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000503 strict_parsing: flag indicating what to do with parsing errors.
504 If false (the default), errors are silently ignored.
505 If true, errors raise a ValueError exception.
Guido van Rossum773ab271996-07-23 03:46:24 +0000506 """
Guido van Rossum7aee3841996-03-07 18:00:44 +0000507 if not fp:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000508 fp = sys.stdin
Guido van Rossum7aee3841996-03-07 18:00:44 +0000509 if not environ.has_key('REQUEST_METHOD'):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000510 environ['REQUEST_METHOD'] = 'GET' # For testing stand-alone
Guido van Rossum7aee3841996-03-07 18:00:44 +0000511 if environ['REQUEST_METHOD'] == 'POST':
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000512 ctype, pdict = parse_header(environ['CONTENT_TYPE'])
513 if ctype == 'multipart/form-data':
514 return parse_multipart(fp, pdict)
515 elif ctype == 'application/x-www-form-urlencoded':
516 clength = string.atoi(environ['CONTENT_LENGTH'])
517 if maxlen and clength > maxlen:
518 raise ValueError, 'Maximum content length exceeded'
519 qs = fp.read(clength)
520 else:
521 qs = '' # Unknown content-type
522 if environ.has_key('QUERY_STRING'):
523 if qs: qs = qs + '&'
524 qs = qs + environ['QUERY_STRING']
525 elif sys.argv[1:]:
526 if qs: qs = qs + '&'
527 qs = qs + sys.argv[1]
528 environ['QUERY_STRING'] = qs # XXX Shouldn't, really
Guido van Rossum7aee3841996-03-07 18:00:44 +0000529 elif environ.has_key('QUERY_STRING'):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000530 qs = environ['QUERY_STRING']
Guido van Rossum7aee3841996-03-07 18:00:44 +0000531 else:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000532 if sys.argv[1:]:
533 qs = sys.argv[1]
534 else:
535 qs = ""
536 environ['QUERY_STRING'] = qs # XXX Shouldn't, really
Guido van Rossume08c04c1996-11-11 19:29:11 +0000537 return parse_qs(qs, keep_blank_values, strict_parsing)
Guido van Rossume7808771995-08-07 20:12:09 +0000538
539
Guido van Rossume08c04c1996-11-11 19:29:11 +0000540def parse_qs(qs, keep_blank_values=0, strict_parsing=0):
541 """Parse a query given as a string argument.
Guido van Rossum773ab271996-07-23 03:46:24 +0000542
543 Arguments:
544
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000545 qs: URL-encoded query string to be parsed
Guido van Rossum773ab271996-07-23 03:46:24 +0000546
547 keep_blank_values: flag indicating whether blank values in
548 URL encoded queries should be treated as blank strings.
549 A true value inicates that blanks should be retained as
550 blank strings. The default false value indicates that
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000551 blank values are to be ignored and treated as if they were
552 not included.
Guido van Rossume08c04c1996-11-11 19:29:11 +0000553
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000554 strict_parsing: flag indicating what to do with parsing errors.
555 If false (the default), errors are silently ignored.
556 If true, errors raise a ValueError exception.
Guido van Rossum773ab271996-07-23 03:46:24 +0000557 """
Guido van Rossum7aee3841996-03-07 18:00:44 +0000558 name_value_pairs = string.splitfields(qs, '&')
559 dict = {}
560 for name_value in name_value_pairs:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000561 nv = string.splitfields(name_value, '=')
562 if len(nv) != 2:
563 if strict_parsing:
564 raise ValueError, "bad query field: %s" % `name_value`
565 continue
566 name = urllib.unquote(string.replace(nv[0], '+', ' '))
567 value = urllib.unquote(string.replace(nv[1], '+', ' '))
Guido van Rossum773ab271996-07-23 03:46:24 +0000568 if len(value) or keep_blank_values:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000569 if dict.has_key (name):
570 dict[name].append(value)
571 else:
572 dict[name] = [value]
Guido van Rossum7aee3841996-03-07 18:00:44 +0000573 return dict
Guido van Rossum9a22de11995-01-12 12:29:47 +0000574
575
Guido van Rossum0147db01996-03-09 03:16:04 +0000576def parse_multipart(fp, pdict):
Guido van Rossum7aee3841996-03-07 18:00:44 +0000577 """Parse multipart input.
Guido van Rossum9a22de11995-01-12 12:29:47 +0000578
Guido van Rossum7aee3841996-03-07 18:00:44 +0000579 Arguments:
580 fp : input file
Guido van Rossum7aee3841996-03-07 18:00:44 +0000581 pdict: dictionary containing other parameters of conten-type header
Guido van Rossum72755611996-03-06 07:20:06 +0000582
Guido van Rossum0147db01996-03-09 03:16:04 +0000583 Returns a dictionary just like parse_qs(): keys are the field names, each
584 value is a list of values for that field. This is easy to use but not
585 much good if you are expecting megabytes to be uploaded -- in that case,
586 use the FieldStorage class instead which is much more flexible. Note
587 that content-type is the raw, unparsed contents of the content-type
588 header.
589
590 XXX This does not parse nested multipart parts -- use FieldStorage for
591 that.
592
593 XXX This should really be subsumed by FieldStorage altogether -- no
594 point in having two implementations of the same parsing algorithm.
Guido van Rossum72755611996-03-06 07:20:06 +0000595
Guido van Rossum7aee3841996-03-07 18:00:44 +0000596 """
Guido van Rossum7aee3841996-03-07 18:00:44 +0000597 if pdict.has_key('boundary'):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000598 boundary = pdict['boundary']
Guido van Rossum7aee3841996-03-07 18:00:44 +0000599 else:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000600 boundary = ""
Guido van Rossum7aee3841996-03-07 18:00:44 +0000601 nextpart = "--" + boundary
602 lastpart = "--" + boundary + "--"
603 partdict = {}
604 terminator = ""
605
606 while terminator != lastpart:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000607 bytes = -1
608 data = None
609 if terminator:
610 # At start of next part. Read headers first.
611 headers = mimetools.Message(fp)
612 clength = headers.getheader('content-length')
613 if clength:
614 try:
615 bytes = string.atoi(clength)
616 except string.atoi_error:
617 pass
618 if bytes > 0:
619 if maxlen and bytes > maxlen:
620 raise ValueError, 'Maximum content length exceeded'
621 data = fp.read(bytes)
622 else:
623 data = ""
624 # Read lines until end of part.
625 lines = []
626 while 1:
627 line = fp.readline()
628 if not line:
629 terminator = lastpart # End outer loop
630 break
631 if line[:2] == "--":
632 terminator = string.strip(line)
633 if terminator in (nextpart, lastpart):
634 break
635 lines.append(line)
636 # Done with part.
637 if data is None:
638 continue
639 if bytes < 0:
640 if lines:
641 # Strip final line terminator
642 line = lines[-1]
643 if line[-2:] == "\r\n":
644 line = line[:-2]
645 elif line[-1:] == "\n":
646 line = line[:-1]
647 lines[-1] = line
648 data = string.joinfields(lines, "")
649 line = headers['content-disposition']
650 if not line:
651 continue
652 key, params = parse_header(line)
653 if key != 'form-data':
654 continue
655 if params.has_key('name'):
656 name = params['name']
657 else:
658 continue
659 if partdict.has_key(name):
660 partdict[name].append(data)
661 else:
662 partdict[name] = [data]
Guido van Rossum72755611996-03-06 07:20:06 +0000663
Guido van Rossum7aee3841996-03-07 18:00:44 +0000664 return partdict
Guido van Rossum9a22de11995-01-12 12:29:47 +0000665
666
Guido van Rossum72755611996-03-06 07:20:06 +0000667def parse_header(line):
Guido van Rossum7aee3841996-03-07 18:00:44 +0000668 """Parse a Content-type like header.
669
670 Return the main content-type and a dictionary of options.
671
672 """
673 plist = map(string.strip, string.splitfields(line, ';'))
674 key = string.lower(plist[0])
675 del plist[0]
676 pdict = {}
677 for p in plist:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000678 i = string.find(p, '=')
679 if i >= 0:
680 name = string.lower(string.strip(p[:i]))
681 value = string.strip(p[i+1:])
682 if len(value) >= 2 and value[0] == value[-1] == '"':
683 value = value[1:-1]
684 pdict[name] = value
Guido van Rossum7aee3841996-03-07 18:00:44 +0000685 return key, pdict
Guido van Rossum72755611996-03-06 07:20:06 +0000686
687
Guido van Rossum243ddcd1996-03-07 06:33:07 +0000688# Classes for field storage
689# =========================
690
691class MiniFieldStorage:
692
Guido van Rossum0147db01996-03-09 03:16:04 +0000693 """Like FieldStorage, for use when no file uploads are possible."""
Guido van Rossum243ddcd1996-03-07 06:33:07 +0000694
Guido van Rossum7aee3841996-03-07 18:00:44 +0000695 # Dummy attributes
696 filename = None
697 list = None
698 type = None
Guido van Rossum773ab271996-07-23 03:46:24 +0000699 file = None
Guido van Rossum4032c2c1996-03-09 04:04:35 +0000700 type_options = {}
Guido van Rossum7aee3841996-03-07 18:00:44 +0000701 disposition = None
702 disposition_options = {}
703 headers = {}
Guido van Rossum243ddcd1996-03-07 06:33:07 +0000704
Guido van Rossum7aee3841996-03-07 18:00:44 +0000705 def __init__(self, name, value):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000706 """Constructor from field name and value."""
707 self.name = name
708 self.value = value
Guido van Rossum773ab271996-07-23 03:46:24 +0000709 # self.file = StringIO(value)
Guido van Rossum7aee3841996-03-07 18:00:44 +0000710
711 def __repr__(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000712 """Return printable representation."""
713 return "MiniFieldStorage(%s, %s)" % (`self.name`, `self.value`)
Guido van Rossum243ddcd1996-03-07 06:33:07 +0000714
715
716class FieldStorage:
717
Guido van Rossum7aee3841996-03-07 18:00:44 +0000718 """Store a sequence of fields, reading multipart/form-data.
Guido van Rossum243ddcd1996-03-07 06:33:07 +0000719
Guido van Rossum7aee3841996-03-07 18:00:44 +0000720 This class provides naming, typing, files stored on disk, and
721 more. At the top level, it is accessible like a dictionary, whose
722 keys are the field names. (Note: None can occur as a field name.)
723 The items are either a Python list (if there's multiple values) or
724 another FieldStorage or MiniFieldStorage object. If it's a single
725 object, it has the following attributes:
Guido van Rossum243ddcd1996-03-07 06:33:07 +0000726
Guido van Rossum7aee3841996-03-07 18:00:44 +0000727 name: the field name, if specified; otherwise None
Guido van Rossum243ddcd1996-03-07 06:33:07 +0000728
Guido van Rossum7aee3841996-03-07 18:00:44 +0000729 filename: the filename, if specified; otherwise None; this is the
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000730 client side filename, *not* the file name on which it is
731 stored (that's a temporary file you don't deal with)
Guido van Rossum243ddcd1996-03-07 06:33:07 +0000732
Guido van Rossum7aee3841996-03-07 18:00:44 +0000733 value: the value as a *string*; for file uploads, this
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000734 transparently reads the file every time you request the value
Guido van Rossum7aee3841996-03-07 18:00:44 +0000735
736 file: the file(-like) object from which you can read the data;
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000737 None if the data is stored a simple string
Guido van Rossum7aee3841996-03-07 18:00:44 +0000738
739 type: the content-type, or None if not specified
740
741 type_options: dictionary of options specified on the content-type
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000742 line
Guido van Rossum7aee3841996-03-07 18:00:44 +0000743
744 disposition: content-disposition, or None if not specified
745
746 disposition_options: dictionary of corresponding options
747
748 headers: a dictionary(-like) object (sometimes rfc822.Message or a
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000749 subclass thereof) containing *all* headers
Guido van Rossum7aee3841996-03-07 18:00:44 +0000750
751 The class is subclassable, mostly for the purpose of overriding
752 the make_file() method, which is called internally to come up with
753 a file open for reading and writing. This makes it possible to
754 override the default choice of storing all files in a temporary
755 directory and unlinking them as soon as they have been opened.
756
757 """
758
Guido van Rossum773ab271996-07-23 03:46:24 +0000759 def __init__(self, fp=None, headers=None, outerboundary="",
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000760 environ=os.environ, keep_blank_values=0, strict_parsing=0):
761 """Constructor. Read multipart/* until last part.
Guido van Rossum7aee3841996-03-07 18:00:44 +0000762
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000763 Arguments, all optional:
Guido van Rossum7aee3841996-03-07 18:00:44 +0000764
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000765 fp : file pointer; default: sys.stdin
Guido van Rossumb1b4f941998-05-08 19:55:51 +0000766 (not used when the request method is GET)
Guido van Rossum7aee3841996-03-07 18:00:44 +0000767
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000768 headers : header dictionary-like object; default:
769 taken from environ as per CGI spec
Guido van Rossum7aee3841996-03-07 18:00:44 +0000770
Guido van Rossum773ab271996-07-23 03:46:24 +0000771 outerboundary : terminating multipart boundary
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000772 (for internal use only)
Guido van Rossum7aee3841996-03-07 18:00:44 +0000773
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000774 environ : environment dictionary; default: os.environ
Guido van Rossum773ab271996-07-23 03:46:24 +0000775
776 keep_blank_values: flag indicating whether blank values in
777 URL encoded forms should be treated as blank strings.
778 A true value inicates that blanks should be retained as
779 blank strings. The default false value indicates that
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000780 blank values are to be ignored and treated as if they were
781 not included.
Guido van Rossum773ab271996-07-23 03:46:24 +0000782
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000783 strict_parsing: flag indicating what to do with parsing errors.
784 If false (the default), errors are silently ignored.
785 If true, errors raise a ValueError exception.
Guido van Rossume08c04c1996-11-11 19:29:11 +0000786
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000787 """
788 method = 'GET'
789 self.keep_blank_values = keep_blank_values
790 self.strict_parsing = strict_parsing
791 if environ.has_key('REQUEST_METHOD'):
792 method = string.upper(environ['REQUEST_METHOD'])
Guido van Rossum01852831998-06-25 02:40:17 +0000793 if method == 'GET' or method == 'HEAD':
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000794 if environ.has_key('QUERY_STRING'):
795 qs = environ['QUERY_STRING']
796 elif sys.argv[1:]:
797 qs = sys.argv[1]
798 else:
799 qs = ""
800 fp = StringIO(qs)
801 if headers is None:
802 headers = {'content-type':
803 "application/x-www-form-urlencoded"}
804 if headers is None:
Guido van Rossumcff311a1998-06-11 14:06:59 +0000805 headers = {}
806 if method == 'POST':
807 # Set default content-type for POST to what's traditional
808 headers['content-type'] = "application/x-www-form-urlencoded"
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000809 if environ.has_key('CONTENT_TYPE'):
810 headers['content-type'] = environ['CONTENT_TYPE']
811 if environ.has_key('CONTENT_LENGTH'):
812 headers['content-length'] = environ['CONTENT_LENGTH']
813 self.fp = fp or sys.stdin
814 self.headers = headers
815 self.outerboundary = outerboundary
Guido van Rossum7aee3841996-03-07 18:00:44 +0000816
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000817 # Process content-disposition header
818 cdisp, pdict = "", {}
819 if self.headers.has_key('content-disposition'):
820 cdisp, pdict = parse_header(self.headers['content-disposition'])
821 self.disposition = cdisp
822 self.disposition_options = pdict
823 self.name = None
824 if pdict.has_key('name'):
825 self.name = pdict['name']
826 self.filename = None
827 if pdict.has_key('filename'):
828 self.filename = pdict['filename']
Guido van Rossum7aee3841996-03-07 18:00:44 +0000829
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000830 # Process content-type header
Barry Warsaw302331a1999-01-08 17:42:03 +0000831 #
832 # Honor any existing content-type header. But if there is no
833 # content-type header, use some sensible defaults. Assume
834 # outerboundary is "" at the outer level, but something non-false
835 # inside a multi-part. The default for an inner part is text/plain,
836 # but for an outer part it should be urlencoded. This should catch
837 # bogus clients which erroneously forget to include a content-type
838 # header.
839 #
840 # See below for what we do if there does exist a content-type header,
841 # but it happens to be something we don't understand.
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000842 if self.headers.has_key('content-type'):
843 ctype, pdict = parse_header(self.headers['content-type'])
Barry Warsaw302331a1999-01-08 17:42:03 +0000844 elif self.outerboundary:
845 ctype, pdict = "text/plain", {}
846 else:
847 ctype, pdict = 'application/x-www-form-urlencoded', {}
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000848 self.type = ctype
849 self.type_options = pdict
850 self.innerboundary = ""
851 if pdict.has_key('boundary'):
852 self.innerboundary = pdict['boundary']
853 clen = -1
854 if self.headers.has_key('content-length'):
855 try:
856 clen = string.atoi(self.headers['content-length'])
857 except:
858 pass
859 if maxlen and clen > maxlen:
860 raise ValueError, 'Maximum content length exceeded'
861 self.length = clen
Guido van Rossum7aee3841996-03-07 18:00:44 +0000862
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000863 self.list = self.file = None
864 self.done = 0
865 self.lines = []
866 if ctype == 'application/x-www-form-urlencoded':
867 self.read_urlencoded()
868 elif ctype[:10] == 'multipart/':
Guido van Rossumf5745001998-10-20 14:43:02 +0000869 self.read_multi(environ, keep_blank_values, strict_parsing)
Barry Warsaw302331a1999-01-08 17:42:03 +0000870 elif self.outerboundary:
871 # we're in an inner part, but the content-type wasn't something we
872 # understood. default to read_single() because the resulting
873 # FieldStorage won't be a mapping (and doesn't need to be).
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000874 self.read_single()
Barry Warsaw302331a1999-01-08 17:42:03 +0000875 else:
876 # we're in an outer part, but the content-type wasn't something we
877 # understood. we still want the resulting FieldStorage to be a
878 # mapping, so parse it as if it were urlencoded
879 self.read_urlencoded()
Guido van Rossum7aee3841996-03-07 18:00:44 +0000880
881 def __repr__(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000882 """Return a printable representation."""
883 return "FieldStorage(%s, %s, %s)" % (
884 `self.name`, `self.filename`, `self.value`)
Guido van Rossum7aee3841996-03-07 18:00:44 +0000885
886 def __getattr__(self, name):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000887 if name != 'value':
888 raise AttributeError, name
889 if self.file:
890 self.file.seek(0)
891 value = self.file.read()
892 self.file.seek(0)
893 elif self.list is not None:
894 value = self.list
895 else:
896 value = None
897 return value
Guido van Rossum7aee3841996-03-07 18:00:44 +0000898
899 def __getitem__(self, key):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000900 """Dictionary style indexing."""
901 if self.list is None:
902 raise TypeError, "not indexable"
903 found = []
904 for item in self.list:
905 if item.name == key: found.append(item)
906 if not found:
907 raise KeyError, key
908 if len(found) == 1:
909 return found[0]
910 else:
911 return found
Guido van Rossum7aee3841996-03-07 18:00:44 +0000912
913 def keys(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000914 """Dictionary style keys() method."""
915 if self.list is None:
916 raise TypeError, "not indexable"
917 keys = []
918 for item in self.list:
919 if item.name not in keys: keys.append(item.name)
920 return keys
Guido van Rossum7aee3841996-03-07 18:00:44 +0000921
Guido van Rossum0147db01996-03-09 03:16:04 +0000922 def has_key(self, key):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000923 """Dictionary style has_key() method."""
924 if self.list is None:
925 raise TypeError, "not indexable"
926 for item in self.list:
927 if item.name == key: return 1
928 return 0
Guido van Rossum0147db01996-03-09 03:16:04 +0000929
Guido van Rossum88b85d41997-01-11 19:21:33 +0000930 def __len__(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000931 """Dictionary style len(x) support."""
932 return len(self.keys())
Guido van Rossum88b85d41997-01-11 19:21:33 +0000933
Guido van Rossum7aee3841996-03-07 18:00:44 +0000934 def read_urlencoded(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000935 """Internal: read data in query string format."""
936 qs = self.fp.read(self.length)
937 dict = parse_qs(qs, self.keep_blank_values, self.strict_parsing)
938 self.list = []
939 for key, valuelist in dict.items():
940 for value in valuelist:
941 self.list.append(MiniFieldStorage(key, value))
942 self.skip_lines()
Guido van Rossum7aee3841996-03-07 18:00:44 +0000943
Guido van Rossum030d2ec1998-12-09 22:16:46 +0000944 FieldStorageClass = None
945
Guido van Rossumf5745001998-10-20 14:43:02 +0000946 def read_multi(self, environ, keep_blank_values, strict_parsing):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000947 """Internal: read a part that is itself multipart."""
948 self.list = []
Guido van Rossum030d2ec1998-12-09 22:16:46 +0000949 klass = self.FieldStorageClass or self.__class__
950 part = klass(self.fp, {}, self.innerboundary,
951 environ, keep_blank_values, strict_parsing)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000952 # Throw first part away
953 while not part.done:
954 headers = rfc822.Message(self.fp)
Guido van Rossum030d2ec1998-12-09 22:16:46 +0000955 part = klass(self.fp, headers, self.innerboundary,
956 environ, keep_blank_values, strict_parsing)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000957 self.list.append(part)
958 self.skip_lines()
Guido van Rossum7aee3841996-03-07 18:00:44 +0000959
960 def read_single(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000961 """Internal: read an atomic part."""
962 if self.length >= 0:
963 self.read_binary()
964 self.skip_lines()
965 else:
966 self.read_lines()
967 self.file.seek(0)
Guido van Rossum7aee3841996-03-07 18:00:44 +0000968
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000969 bufsize = 8*1024 # I/O buffering size for copy to file
Guido van Rossum7aee3841996-03-07 18:00:44 +0000970
971 def read_binary(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000972 """Internal: read binary data."""
973 self.file = self.make_file('b')
974 todo = self.length
975 if todo >= 0:
976 while todo > 0:
977 data = self.fp.read(min(todo, self.bufsize))
978 if not data:
979 self.done = -1
980 break
981 self.file.write(data)
982 todo = todo - len(data)
Guido van Rossum7aee3841996-03-07 18:00:44 +0000983
984 def read_lines(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000985 """Internal: read lines until EOF or outerboundary."""
986 self.file = self.make_file('')
987 if self.outerboundary:
988 self.read_lines_to_outerboundary()
989 else:
990 self.read_lines_to_eof()
Guido van Rossum7aee3841996-03-07 18:00:44 +0000991
992 def read_lines_to_eof(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000993 """Internal: read lines until EOF."""
994 while 1:
995 line = self.fp.readline()
996 if not line:
997 self.done = -1
998 break
999 self.lines.append(line)
1000 self.file.write(line)
Guido van Rossum7aee3841996-03-07 18:00:44 +00001001
1002 def read_lines_to_outerboundary(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +00001003 """Internal: read lines until outerboundary."""
1004 next = "--" + self.outerboundary
1005 last = next + "--"
1006 delim = ""
1007 while 1:
1008 line = self.fp.readline()
1009 if not line:
1010 self.done = -1
1011 break
1012 self.lines.append(line)
1013 if line[:2] == "--":
1014 strippedline = string.strip(line)
1015 if strippedline == next:
1016 break
1017 if strippedline == last:
1018 self.done = 1
1019 break
1020 odelim = delim
1021 if line[-2:] == "\r\n":
1022 delim = "\r\n"
1023 line = line[:-2]
1024 elif line[-1] == "\n":
1025 delim = "\n"
1026 line = line[:-1]
1027 else:
1028 delim = ""
1029 self.file.write(odelim + line)
Guido van Rossum7aee3841996-03-07 18:00:44 +00001030
1031 def skip_lines(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +00001032 """Internal: skip lines until outer boundary if defined."""
1033 if not self.outerboundary or self.done:
1034 return
1035 next = "--" + self.outerboundary
1036 last = next + "--"
1037 while 1:
1038 line = self.fp.readline()
1039 if not line:
1040 self.done = -1
1041 break
1042 self.lines.append(line)
1043 if line[:2] == "--":
1044 strippedline = string.strip(line)
1045 if strippedline == next:
1046 break
1047 if strippedline == last:
1048 self.done = 1
1049 break
Guido van Rossum7aee3841996-03-07 18:00:44 +00001050
Guido van Rossuma5e9fb61997-08-12 18:18:13 +00001051 def make_file(self, binary=None):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +00001052 """Overridable: return a readable & writable file.
Guido van Rossum7aee3841996-03-07 18:00:44 +00001053
Guido van Rossum45e2fbc1998-03-26 21:13:24 +00001054 The file will be used as follows:
1055 - data is written to it
1056 - seek(0)
1057 - data is read from it
Guido van Rossum7aee3841996-03-07 18:00:44 +00001058
Guido van Rossum45e2fbc1998-03-26 21:13:24 +00001059 The 'binary' argument is unused -- the file is always opened
1060 in binary mode.
Guido van Rossum7aee3841996-03-07 18:00:44 +00001061
Guido van Rossum45e2fbc1998-03-26 21:13:24 +00001062 This version opens a temporary file for reading and writing,
1063 and immediately deletes (unlinks) it. The trick (on Unix!) is
1064 that the file can still be used, but it can't be opened by
1065 another process, and it will automatically be deleted when it
1066 is closed or when the current process terminates.
Guido van Rossum4032c2c1996-03-09 04:04:35 +00001067
Guido van Rossum45e2fbc1998-03-26 21:13:24 +00001068 If you want a more permanent file, you derive a class which
1069 overrides this method. If you want a visible temporary file
1070 that is nevertheless automatically deleted when the script
1071 terminates, try defining a __del__ method in a derived class
1072 which unlinks the temporary files you have created.
Guido van Rossum7aee3841996-03-07 18:00:44 +00001073
Guido van Rossum45e2fbc1998-03-26 21:13:24 +00001074 """
1075 import tempfile
1076 return tempfile.TemporaryFile("w+b")
1077
Guido van Rossum243ddcd1996-03-07 06:33:07 +00001078
1079
Guido van Rossum4032c2c1996-03-09 04:04:35 +00001080# Backwards Compatibility Classes
1081# ===============================
Guido van Rossum9a22de11995-01-12 12:29:47 +00001082
1083class FormContentDict:
Guido van Rossum7aee3841996-03-07 18:00:44 +00001084 """Basic (multiple values per field) form content as dictionary.
Guido van Rossum72755611996-03-06 07:20:06 +00001085
Guido van Rossum7aee3841996-03-07 18:00:44 +00001086 form = FormContentDict()
1087
1088 form[key] -> [value, value, ...]
1089 form.has_key(key) -> Boolean
1090 form.keys() -> [key, key, ...]
1091 form.values() -> [[val, val, ...], [val, val, ...], ...]
1092 form.items() -> [(key, [val, val, ...]), (key, [val, val, ...]), ...]
1093 form.dict == {key: [val, val, ...], ...}
1094
1095 """
Guido van Rossum773ab271996-07-23 03:46:24 +00001096 def __init__(self, environ=os.environ):
Guido van Rossumafb5e931996-08-08 18:42:12 +00001097 self.dict = parse(environ=environ)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +00001098 self.query_string = environ['QUERY_STRING']
Guido van Rossum7aee3841996-03-07 18:00:44 +00001099 def __getitem__(self,key):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +00001100 return self.dict[key]
Guido van Rossum7aee3841996-03-07 18:00:44 +00001101 def keys(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +00001102 return self.dict.keys()
Guido van Rossum7aee3841996-03-07 18:00:44 +00001103 def has_key(self, key):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +00001104 return self.dict.has_key(key)
Guido van Rossum7aee3841996-03-07 18:00:44 +00001105 def values(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +00001106 return self.dict.values()
Guido van Rossum7aee3841996-03-07 18:00:44 +00001107 def items(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +00001108 return self.dict.items()
Guido van Rossum7aee3841996-03-07 18:00:44 +00001109 def __len__( self ):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +00001110 return len(self.dict)
Guido van Rossum9a22de11995-01-12 12:29:47 +00001111
1112
Guido van Rossum9a22de11995-01-12 12:29:47 +00001113class SvFormContentDict(FormContentDict):
Guido van Rossum7aee3841996-03-07 18:00:44 +00001114 """Strict single-value expecting form content as dictionary.
1115
1116 IF you only expect a single value for each field, then form[key]
1117 will return that single value. It will raise an IndexError if
1118 that expectation is not true. IF you expect a field to have
1119 possible multiple values, than you can use form.getlist(key) to
1120 get all of the values. values() and items() are a compromise:
1121 they return single strings where there is a single value, and
1122 lists of strings otherwise.
1123
1124 """
1125 def __getitem__(self, key):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +00001126 if len(self.dict[key]) > 1:
1127 raise IndexError, 'expecting a single value'
1128 return self.dict[key][0]
Guido van Rossum7aee3841996-03-07 18:00:44 +00001129 def getlist(self, key):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +00001130 return self.dict[key]
Guido van Rossum7aee3841996-03-07 18:00:44 +00001131 def values(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +00001132 lis = []
1133 for each in self.dict.values():
1134 if len( each ) == 1 :
1135 lis.append(each[0])
1136 else: lis.append(each)
1137 return lis
Guido van Rossum7aee3841996-03-07 18:00:44 +00001138 def items(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +00001139 lis = []
1140 for key,value in self.dict.items():
1141 if len(value) == 1 :
1142 lis.append((key, value[0]))
1143 else: lis.append((key, value))
1144 return lis
Guido van Rossum9a22de11995-01-12 12:29:47 +00001145
1146
Guido van Rossum9a22de11995-01-12 12:29:47 +00001147class InterpFormContentDict(SvFormContentDict):
Guido van Rossum7aee3841996-03-07 18:00:44 +00001148 """This class is present for backwards compatibility only."""
1149 def __getitem__( self, key ):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +00001150 v = SvFormContentDict.__getitem__( self, key )
1151 if v[0] in string.digits+'+-.' :
1152 try: return string.atoi( v )
1153 except ValueError:
1154 try: return string.atof( v )
1155 except ValueError: pass
1156 return string.strip(v)
Guido van Rossum7aee3841996-03-07 18:00:44 +00001157 def values( self ):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +00001158 lis = []
1159 for key in self.keys():
1160 try:
1161 lis.append( self[key] )
1162 except IndexError:
1163 lis.append( self.dict[key] )
1164 return lis
Guido van Rossum7aee3841996-03-07 18:00:44 +00001165 def items( self ):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +00001166 lis = []
1167 for key in self.keys():
1168 try:
1169 lis.append( (key, self[key]) )
1170 except IndexError:
1171 lis.append( (key, self.dict[key]) )
1172 return lis
Guido van Rossum9a22de11995-01-12 12:29:47 +00001173
1174
Guido van Rossum9a22de11995-01-12 12:29:47 +00001175class FormContent(FormContentDict):
Guido van Rossum7aee3841996-03-07 18:00:44 +00001176 """This class is present for backwards compatibility only."""
Guido van Rossum0147db01996-03-09 03:16:04 +00001177 def values(self, key):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +00001178 if self.dict.has_key(key) :return self.dict[key]
1179 else: return None
Guido van Rossum0147db01996-03-09 03:16:04 +00001180 def indexed_value(self, key, location):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +00001181 if self.dict.has_key(key):
1182 if len (self.dict[key]) > location:
1183 return self.dict[key][location]
1184 else: return None
1185 else: return None
Guido van Rossum0147db01996-03-09 03:16:04 +00001186 def value(self, key):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +00001187 if self.dict.has_key(key): return self.dict[key][0]
1188 else: return None
Guido van Rossum0147db01996-03-09 03:16:04 +00001189 def length(self, key):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +00001190 return len(self.dict[key])
Guido van Rossum0147db01996-03-09 03:16:04 +00001191 def stripped(self, key):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +00001192 if self.dict.has_key(key): return string.strip(self.dict[key][0])
1193 else: return None
Guido van Rossum7aee3841996-03-07 18:00:44 +00001194 def pars(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +00001195 return self.dict
Guido van Rossum9a22de11995-01-12 12:29:47 +00001196
1197
Guido van Rossum72755611996-03-06 07:20:06 +00001198# Test/debug code
1199# ===============
Guido van Rossum9a22de11995-01-12 12:29:47 +00001200
Guido van Rossum773ab271996-07-23 03:46:24 +00001201def test(environ=os.environ):
Guido van Rossum7aee3841996-03-07 18:00:44 +00001202 """Robust test CGI script, usable as main program.
Guido van Rossum9a22de11995-01-12 12:29:47 +00001203
Guido van Rossum7aee3841996-03-07 18:00:44 +00001204 Write minimal HTTP headers and dump all information provided to
1205 the script in HTML form.
1206
1207 """
1208 import traceback
1209 print "Content-type: text/html"
1210 print
1211 sys.stderr = sys.stdout
1212 try:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +00001213 form = FieldStorage() # Replace with other classes to test those
1214 print_form(form)
Guido van Rossum773ab271996-07-23 03:46:24 +00001215 print_environ(environ)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +00001216 print_directory()
1217 print_arguments()
1218 print_environ_usage()
1219 def f():
1220 exec "testing print_exception() -- <I>italics?</I>"
1221 def g(f=f):
1222 f()
1223 print "<H3>What follows is a test, not an actual exception:</H3>"
1224 g()
Guido van Rossum7aee3841996-03-07 18:00:44 +00001225 except:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +00001226 print_exception()
Guido van Rossumf85de8a1996-08-20 20:22:39 +00001227
Guido van Rossumad164711997-05-13 19:03:23 +00001228 # Second try with a small maxlen...
1229 global maxlen
1230 maxlen = 50
1231 try:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +00001232 form = FieldStorage() # Replace with other classes to test those
1233 print_form(form)
1234 print_environ(environ)
1235 print_directory()
1236 print_arguments()
1237 print_environ_usage()
Guido van Rossumad164711997-05-13 19:03:23 +00001238 except:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +00001239 print_exception()
Guido van Rossumad164711997-05-13 19:03:23 +00001240
Guido van Rossumf85de8a1996-08-20 20:22:39 +00001241def print_exception(type=None, value=None, tb=None, limit=None):
1242 if type is None:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +00001243 type, value, tb = sys.exc_info()
Guido van Rossumf85de8a1996-08-20 20:22:39 +00001244 import traceback
1245 print
1246 print "<H3>Traceback (innermost last):</H3>"
1247 list = traceback.format_tb(tb, limit) + \
Guido van Rossum45e2fbc1998-03-26 21:13:24 +00001248 traceback.format_exception_only(type, value)
Guido van Rossumf85de8a1996-08-20 20:22:39 +00001249 print "<PRE>%s<B>%s</B></PRE>" % (
Guido van Rossum45e2fbc1998-03-26 21:13:24 +00001250 escape(string.join(list[:-1], "")),
1251 escape(list[-1]),
1252 )
Guido van Rossumf15d1591997-09-29 23:22:12 +00001253 del tb
Guido van Rossum9a22de11995-01-12 12:29:47 +00001254
Guido van Rossum773ab271996-07-23 03:46:24 +00001255def print_environ(environ=os.environ):
Guido van Rossum7aee3841996-03-07 18:00:44 +00001256 """Dump the shell environment as HTML."""
1257 keys = environ.keys()
1258 keys.sort()
1259 print
Guido van Rossum503e50b1996-05-28 22:57:20 +00001260 print "<H3>Shell Environment:</H3>"
Guido van Rossum7aee3841996-03-07 18:00:44 +00001261 print "<DL>"
1262 for key in keys:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +00001263 print "<DT>", escape(key), "<DD>", escape(environ[key])
Guido van Rossum7aee3841996-03-07 18:00:44 +00001264 print "</DL>"
1265 print
Guido van Rossum72755611996-03-06 07:20:06 +00001266
1267def print_form(form):
Guido van Rossum7aee3841996-03-07 18:00:44 +00001268 """Dump the contents of a form as HTML."""
1269 keys = form.keys()
1270 keys.sort()
1271 print
Guido van Rossum503e50b1996-05-28 22:57:20 +00001272 print "<H3>Form Contents:</H3>"
Guido van Rossum7aee3841996-03-07 18:00:44 +00001273 print "<DL>"
1274 for key in keys:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +00001275 print "<DT>" + escape(key) + ":",
1276 value = form[key]
1277 print "<i>" + escape(`type(value)`) + "</i>"
1278 print "<DD>" + escape(`value`)
Guido van Rossum7aee3841996-03-07 18:00:44 +00001279 print "</DL>"
1280 print
1281
1282def print_directory():
1283 """Dump the current directory as HTML."""
1284 print
1285 print "<H3>Current Working Directory:</H3>"
1286 try:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +00001287 pwd = os.getcwd()
Guido van Rossum7aee3841996-03-07 18:00:44 +00001288 except os.error, msg:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +00001289 print "os.error:", escape(str(msg))
Guido van Rossum7aee3841996-03-07 18:00:44 +00001290 else:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +00001291 print escape(pwd)
Guido van Rossum7aee3841996-03-07 18:00:44 +00001292 print
Guido van Rossum9a22de11995-01-12 12:29:47 +00001293
Guido van Rossuma8738a51996-03-14 21:30:28 +00001294def print_arguments():
1295 print
Guido van Rossum503e50b1996-05-28 22:57:20 +00001296 print "<H3>Command Line Arguments:</H3>"
Guido van Rossuma8738a51996-03-14 21:30:28 +00001297 print
1298 print sys.argv
1299 print
1300
Guido van Rossum9a22de11995-01-12 12:29:47 +00001301def print_environ_usage():
Guido van Rossum7aee3841996-03-07 18:00:44 +00001302 """Dump a list of environment variables used by CGI as HTML."""
1303 print """
Guido van Rossum72755611996-03-06 07:20:06 +00001304<H3>These environment variables could have been set:</H3>
1305<UL>
Guido van Rossum9a22de11995-01-12 12:29:47 +00001306<LI>AUTH_TYPE
1307<LI>CONTENT_LENGTH
1308<LI>CONTENT_TYPE
1309<LI>DATE_GMT
1310<LI>DATE_LOCAL
1311<LI>DOCUMENT_NAME
1312<LI>DOCUMENT_ROOT
1313<LI>DOCUMENT_URI
1314<LI>GATEWAY_INTERFACE
1315<LI>LAST_MODIFIED
1316<LI>PATH
1317<LI>PATH_INFO
1318<LI>PATH_TRANSLATED
1319<LI>QUERY_STRING
1320<LI>REMOTE_ADDR
1321<LI>REMOTE_HOST
1322<LI>REMOTE_IDENT
1323<LI>REMOTE_USER
1324<LI>REQUEST_METHOD
1325<LI>SCRIPT_NAME
1326<LI>SERVER_NAME
1327<LI>SERVER_PORT
1328<LI>SERVER_PROTOCOL
1329<LI>SERVER_ROOT
1330<LI>SERVER_SOFTWARE
1331</UL>
Guido van Rossum7aee3841996-03-07 18:00:44 +00001332In addition, HTTP headers sent by the server may be passed in the
1333environment as well. Here are some common variable names:
1334<UL>
1335<LI>HTTP_ACCEPT
1336<LI>HTTP_CONNECTION
1337<LI>HTTP_HOST
1338<LI>HTTP_PRAGMA
1339<LI>HTTP_REFERER
1340<LI>HTTP_USER_AGENT
1341</UL>
Guido van Rossum9a22de11995-01-12 12:29:47 +00001342"""
1343
Guido van Rossum9a22de11995-01-12 12:29:47 +00001344
Guido van Rossum72755611996-03-06 07:20:06 +00001345# Utilities
1346# =========
Guido van Rossum9a22de11995-01-12 12:29:47 +00001347
Guido van Rossum64c66201997-07-19 20:11:53 +00001348def escape(s, quote=None):
Guido van Rossum7aee3841996-03-07 18:00:44 +00001349 """Replace special characters '&', '<' and '>' by SGML entities."""
Guido van Rossum45e2fbc1998-03-26 21:13:24 +00001350 s = string.replace(s, "&", "&amp;") # Must be done first!
Guido van Rossum00f9fea1997-12-24 21:18:41 +00001351 s = string.replace(s, "<", "&lt;")
1352 s = string.replace(s, ">", "&gt;",)
Guido van Rossum64c66201997-07-19 20:11:53 +00001353 if quote:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +00001354 s = string.replace(s, '"', "&quot;")
Guido van Rossum7aee3841996-03-07 18:00:44 +00001355 return s
Guido van Rossum9a22de11995-01-12 12:29:47 +00001356
Guido van Rossum9a22de11995-01-12 12:29:47 +00001357
Guido van Rossum72755611996-03-06 07:20:06 +00001358# Invoke mainline
1359# ===============
1360
1361# Call test() when this file is run as a script (not imported as a module)
1362if __name__ == '__main__':
Guido van Rossum7aee3841996-03-07 18:00:44 +00001363 test()