blob: 9fca4d8e7da99cb835e90f954812a49dc9cc2acd [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 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 Rossum243ddcd1996-03-07 06:33:07 +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
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
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 Rossum503e50b1996-05-28 22:57:20 +000069 form = cgi.FieldStorage()
Guido van Rossum72755611996-03-06 07:20:06 +000070 form_ok = 0
71 if form.has_key("name") and form.has_key("addr"):
Guido van Rossum0147db01996-03-09 03:16:04 +000072 if form["name"].value != "" and form["addr"].value != "":
Guido van Rossum72755611996-03-06 07:20:06 +000073 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
Guido van Rossum0147db01996-03-09 03:16:04 +000078 ...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
85instance but a list of such instances. If you expect this possibility
86(i.e., when your HTML form comtains multiple fields with the same
87name), use the type() function to determine whether you have a single
88instance or a list of instances. For example, here's code that
89concatenates any number of username fields, separated by commas:
90
91 username = form["username"]
Guido van Rossum0147db01996-03-09 03:16:04 +000092 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
Guido van Rossum4032c2c1996-03-09 04:04:35 +0000104 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
112 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
120
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
139supported for backward compatibility. New applications should use the
Guido van Rossum7aee3841996-03-07 18:00:44 +0000140
Guido van Rossum0147db01996-03-09 03:16:04 +0000141SvFormContentDict: single value form content as dictionary; assumes each
142field name occurs in the form only once.
Guido van Rossum72755611996-03-06 07:20:06 +0000143
Guido van Rossum391b4e61996-03-06 19:11:33 +0000144FormContentDict: multiple value form content as dictionary (the form
145items are lists of values). Useful if your form contains multiple
146fields with the same name.
Guido van Rossum72755611996-03-06 07:20:06 +0000147
Guido van Rossum391b4e61996-03-06 19:11:33 +0000148Other classes (FormContent, InterpFormContentDict) are present for
Guido van Rossum0147db01996-03-09 03:16:04 +0000149backwards compatibility with really old applications only. If you still
150use these and would be inconvenienced when they disappeared from a next
151version of this module, drop me a note.
Guido van Rossum72755611996-03-06 07:20:06 +0000152
153
Guido van Rossum0147db01996-03-09 03:16:04 +0000154Functions
155---------
Guido van Rossum72755611996-03-06 07:20:06 +0000156
Guido van Rossum391b4e61996-03-06 19:11:33 +0000157These are useful if you want more control, or if you want to employ
158some of the algorithms implemented in this module in other
159circumstances.
Guido van Rossum72755611996-03-06 07:20:06 +0000160
Guido van Rossum0147db01996-03-09 03:16:04 +0000161parse(fp): parse a form into a Python dictionary.
Guido van Rossum72755611996-03-06 07:20:06 +0000162
Guido van Rossum0147db01996-03-09 03:16:04 +0000163parse_qs(qs): parse a query string (data of type
164application/x-www-form-urlencoded).
Guido van Rossum72755611996-03-06 07:20:06 +0000165
Guido van Rossum0147db01996-03-09 03:16:04 +0000166parse_multipart(fp, pdict): parse input of type multipart/form-data (for
Guido van Rossum391b4e61996-03-06 19:11:33 +0000167file uploads).
Guido van Rossum72755611996-03-06 07:20:06 +0000168
Guido van Rossum391b4e61996-03-06 19:11:33 +0000169parse_header(string): parse a header like Content-type into a main
170value and a dictionary of parameters.
Guido van Rossum72755611996-03-06 07:20:06 +0000171
172test(): complete test program.
173
174print_environ(): format the shell environment in HTML.
175
176print_form(form): format a form in HTML.
177
Guido van Rossum391b4e61996-03-06 19:11:33 +0000178print_environ_usage(): print a list of useful environment variables in
179HTML.
Guido van Rossum72755611996-03-06 07:20:06 +0000180
Guido van Rossum391b4e61996-03-06 19:11:33 +0000181escape(): convert the characters "&", "<" and ">" to HTML-safe
182sequences. Use this if you need to display text that might contain
183such characters in HTML. To translate URLs for inclusion in the HREF
184attribute of an <A> tag, use urllib.quote().
Guido van Rossum72755611996-03-06 07:20:06 +0000185
186
187Caring about security
188---------------------
189
Guido van Rossum391b4e61996-03-06 19:11:33 +0000190There's one important rule: if you invoke an external program (e.g.
191via the os.system() or os.popen() functions), make very sure you don't
192pass arbitrary strings received from the client to the shell. This is
193a well-known security hole whereby clever hackers anywhere on the web
194can exploit a gullible CGI script to invoke arbitrary shell commands.
195Even parts of the URL or field names cannot be trusted, since the
196request doesn't have to come from your form!
Guido van Rossum72755611996-03-06 07:20:06 +0000197
Guido van Rossum391b4e61996-03-06 19:11:33 +0000198To be on the safe side, if you must pass a string gotten from a form
199to a shell command, you should make sure the string contains only
200alphanumeric characters, dashes, underscores, and periods.
Guido van Rossum72755611996-03-06 07:20:06 +0000201
202
203Installing your CGI script on a Unix system
204-------------------------------------------
205
Guido van Rossum391b4e61996-03-06 19:11:33 +0000206Read the documentation for your HTTP server and check with your local
207system administrator to find the directory where CGI scripts should be
Guido van Rossum72755611996-03-06 07:20:06 +0000208installed; usually this is in a directory cgi-bin in the server tree.
209
Guido van Rossum391b4e61996-03-06 19:11:33 +0000210Make sure that your script is readable and executable by "others"; the
211Unix file mode should be 755 (use "chmod 755 filename"). Make sure
212that the first line of the script contains "#!" starting in column 1
213followed by the pathname of the Python interpreter, for instance:
Guido van Rossum72755611996-03-06 07:20:06 +0000214
215 #!/usr/local/bin/python
216
Guido van Rossum391b4e61996-03-06 19:11:33 +0000217Make sure the Python interpreter exists and is executable by "others".
Guido van Rossum72755611996-03-06 07:20:06 +0000218
Guido van Rossum391b4e61996-03-06 19:11:33 +0000219Make sure that any files your script needs to read or write are
220readable or writable, respectively, by "others" -- their mode should
221be 644 for readable and 666 for writable. This is because, for
222security reasons, the HTTP server executes your script as user
223"nobody", without any special privileges. It can only read (write,
224execute) files that everybody can read (write, execute). The current
225directory at execution time is also different (it is usually the
226server's cgi-bin directory) and the set of environment variables is
227also different from what you get at login. in particular, don't count
228on the shell's search path for executables ($PATH) or the Python
229module search path ($PYTHONPATH) to be set to anything interesting.
Guido van Rossum72755611996-03-06 07:20:06 +0000230
Guido van Rossum391b4e61996-03-06 19:11:33 +0000231If you need to load modules from a directory which is not on Python's
232default module search path, you can change the path in your script,
233before importing other modules, e.g.:
Guido van Rossum72755611996-03-06 07:20:06 +0000234
235 import sys
236 sys.path.insert(0, "/usr/home/joe/lib/python")
237 sys.path.insert(0, "/usr/local/lib/python")
238
239(This way, the directory inserted last will be searched first!)
240
Guido van Rossum391b4e61996-03-06 19:11:33 +0000241Instructions for non-Unix systems will vary; check your HTTP server's
Guido van Rossum72755611996-03-06 07:20:06 +0000242documentation (it will usually have a section on CGI scripts).
243
244
245Testing your CGI script
246-----------------------
247
Guido van Rossum391b4e61996-03-06 19:11:33 +0000248Unfortunately, a CGI script will generally not run when you try it
249from the command line, and a script that works perfectly from the
250command line may fail mysteriously when run from the server. There's
251one reason why you should still test your script from the command
252line: if it contains a syntax error, the python interpreter won't
253execute it at all, and the HTTP server will most likely send a cryptic
254error to the client.
Guido van Rossum72755611996-03-06 07:20:06 +0000255
Guido van Rossum391b4e61996-03-06 19:11:33 +0000256Assuming your script has no syntax errors, yet it does not work, you
257have no choice but to read the next section:
Guido van Rossum72755611996-03-06 07:20:06 +0000258
259
260Debugging CGI scripts
261---------------------
262
Guido van Rossum391b4e61996-03-06 19:11:33 +0000263First of all, check for trivial installation errors -- reading the
264section above on installing your CGI script carefully can save you a
265lot of time. If you wonder whether you have understood the
266installation procedure correctly, try installing a copy of this module
267file (cgi.py) as a CGI script. When invoked as a script, the file
268will dump its environment and the contents of the form in HTML form.
269Give it the right mode etc, and send it a request. If it's installed
270in the standard cgi-bin directory, it should be possible to send it a
271request by entering a URL into your browser of the form:
Guido van Rossum72755611996-03-06 07:20:06 +0000272
273 http://yourhostname/cgi-bin/cgi.py?name=Joe+Blow&addr=At+Home
274
Guido van Rossum391b4e61996-03-06 19:11:33 +0000275If this gives an error of type 404, the server cannot find the script
276-- perhaps you need to install it in a different directory. If it
277gives another error (e.g. 500), there's an installation problem that
278you should fix before trying to go any further. If you get a nicely
279formatted listing of the environment and form content (in this
280example, the fields should be listed as "addr" with value "At Home"
281and "name" with value "Joe Blow"), the cgi.py script has been
282installed correctly. If you follow the same procedure for your own
283script, you should now be able to debug it.
Guido van Rossum72755611996-03-06 07:20:06 +0000284
Guido van Rossum391b4e61996-03-06 19:11:33 +0000285The next step could be to call the cgi module's test() function from
286your script: replace its main code with the single statement
Guido van Rossum72755611996-03-06 07:20:06 +0000287
288 cgi.test()
289
Guido van Rossum391b4e61996-03-06 19:11:33 +0000290This should produce the same results as those gotten from installing
291the cgi.py file itself.
Guido van Rossum72755611996-03-06 07:20:06 +0000292
Guido van Rossum391b4e61996-03-06 19:11:33 +0000293When an ordinary Python script raises an unhandled exception
294(e.g. because of a typo in a module name, a file that can't be opened,
295etc.), the Python interpreter prints a nice traceback and exits.
296While the Python interpreter will still do this when your CGI script
297raises an exception, most likely the traceback will end up in one of
298the HTTP server's log file, or be discarded altogether.
Guido van Rossum72755611996-03-06 07:20:06 +0000299
Guido van Rossum391b4e61996-03-06 19:11:33 +0000300Fortunately, once you have managed to get your script to execute
301*some* code, it is easy to catch exceptions and cause a traceback to
302be printed. The test() function below in this module is an example.
303Here are the rules:
Guido van Rossum72755611996-03-06 07:20:06 +0000304
Guido van Rossum391b4e61996-03-06 19:11:33 +0000305 1. Import the traceback module (before entering the
306 try-except!)
Guido van Rossum72755611996-03-06 07:20:06 +0000307
Guido van Rossum391b4e61996-03-06 19:11:33 +0000308 2. Make sure you finish printing the headers and the blank
309 line early
Guido van Rossum72755611996-03-06 07:20:06 +0000310
311 3. Assign sys.stderr to sys.stdout
312
313 3. Wrap all remaining code in a try-except statement
314
315 4. In the except clause, call traceback.print_exc()
316
317For example:
318
319 import sys
320 import traceback
321 print "Content-type: text/html"
322 print
323 sys.stderr = sys.stdout
324 try:
325 ...your code here...
326 except:
327 print "\n\n<PRE>"
328 traceback.print_exc()
329
Guido van Rossum391b4e61996-03-06 19:11:33 +0000330Notes: The assignment to sys.stderr is needed because the traceback
331prints to sys.stderr. The print "\n\n<PRE>" statement is necessary to
332disable the word wrapping in HTML.
Guido van Rossum72755611996-03-06 07:20:06 +0000333
Guido van Rossum391b4e61996-03-06 19:11:33 +0000334If you suspect that there may be a problem in importing the traceback
335module, you can use an even more robust approach (which only uses
336built-in modules):
Guido van Rossum72755611996-03-06 07:20:06 +0000337
338 import sys
339 sys.stderr = sys.stdout
340 print "Content-type: text/plain"
341 print
342 ...your code here...
343
Guido van Rossum391b4e61996-03-06 19:11:33 +0000344This relies on the Python interpreter to print the traceback. The
345content type of the output is set to plain text, which disables all
346HTML processing. If your script works, the raw HTML will be displayed
347by your client. If it raises an exception, most likely after the
348first two lines have been printed, a traceback will be displayed.
349Because no HTML interpretation is going on, the traceback will
350readable.
Guido van Rossum72755611996-03-06 07:20:06 +0000351
352Good luck!
353
354
355Common problems and solutions
356-----------------------------
357
Guido van Rossum391b4e61996-03-06 19:11:33 +0000358- Most HTTP servers buffer the output from CGI scripts until the
359script is completed. This means that it is not possible to display a
360progress report on the client's display while the script is running.
Guido van Rossum72755611996-03-06 07:20:06 +0000361
362- Check the installation instructions above.
363
Guido van Rossum391b4e61996-03-06 19:11:33 +0000364- Check the HTTP server's log files. ("tail -f logfile" in a separate
Guido van Rossum72755611996-03-06 07:20:06 +0000365window may be useful!)
366
Guido van Rossum391b4e61996-03-06 19:11:33 +0000367- Always check a script for syntax errors first, by doing something
368like "python script.py".
Guido van Rossum72755611996-03-06 07:20:06 +0000369
370- When using any of the debugging techniques, don't forget to add
371"import sys" to the top of the script.
372
Guido van Rossum391b4e61996-03-06 19:11:33 +0000373- When invoking external programs, make sure they can be found.
374Usually, this means using absolute path names -- $PATH is usually not
375set to a very useful value in a CGI script.
Guido van Rossum72755611996-03-06 07:20:06 +0000376
Guido van Rossum391b4e61996-03-06 19:11:33 +0000377- When reading or writing external files, make sure they can be read
378or written by every user on the system.
Guido van Rossum72755611996-03-06 07:20:06 +0000379
Guido van Rossum391b4e61996-03-06 19:11:33 +0000380- Don't try to give a CGI script a set-uid mode. This doesn't work on
381most systems, and is a security liability as well.
Guido van Rossum72755611996-03-06 07:20:06 +0000382
383
384History
385-------
386
Guido van Rossum391b4e61996-03-06 19:11:33 +0000387Michael McLay started this module. Steve Majewski changed the
388interface to SvFormContentDict and FormContentDict. The multipart
389parsing was inspired by code submitted by Andreas Paepcke. Guido van
390Rossum rewrote, reformatted and documented the module and is currently
391responsible for its maintenance.
Guido van Rossum72755611996-03-06 07:20:06 +0000392
Guido van Rossum0147db01996-03-09 03:16:04 +0000393
394XXX The module is getting pretty heavy with all those docstrings.
395Perhaps there should be a slimmed version that doesn't contain all those
396backwards compatible and debugging classes and functions?
397
Guido van Rossum72755611996-03-06 07:20:06 +0000398"""
399
Guido van Rossum99aa2a41996-07-23 17:27:05 +0000400__version__ = "2.0b2"
Guido van Rossum0147db01996-03-09 03:16:04 +0000401
Guido van Rossum72755611996-03-06 07:20:06 +0000402
403# Imports
404# =======
405
406import string
Guido van Rossum72755611996-03-06 07:20:06 +0000407import sys
408import os
Guido van Rossum72755611996-03-06 07:20:06 +0000409
Guido van Rossum72755611996-03-06 07:20:06 +0000410# Parsing functions
411# =================
412
Guido van Rossum773ab271996-07-23 03:46:24 +0000413def parse(fp=None, environ=os.environ, keep_blank_values=None):
414 """Parse a query in the environment or from a file (default stdin)
415
416 Arguments, all optional:
417
418 fp : file pointer; default: sys.stdin
419
420 environ : environment dictionary; default: os.environ
421
422 keep_blank_values: flag indicating whether blank values in
423 URL encoded forms should be treated as blank strings.
424 A true value inicates that blanks should be retained as
425 blank strings. The default false value indicates that
426 blank values are to be ignored and treated as if they were
427 not included.
428 """
Guido van Rossum7aee3841996-03-07 18:00:44 +0000429 if not fp:
430 fp = sys.stdin
431 if not environ.has_key('REQUEST_METHOD'):
432 environ['REQUEST_METHOD'] = 'GET' # For testing stand-alone
433 if environ['REQUEST_METHOD'] == 'POST':
434 ctype, pdict = parse_header(environ['CONTENT_TYPE'])
435 if ctype == 'multipart/form-data':
Guido van Rossum0147db01996-03-09 03:16:04 +0000436 return parse_multipart(fp, pdict)
Guido van Rossum7aee3841996-03-07 18:00:44 +0000437 elif ctype == 'application/x-www-form-urlencoded':
438 clength = string.atoi(environ['CONTENT_LENGTH'])
439 qs = fp.read(clength)
Guido van Rossum1c9daa81995-09-18 21:52:37 +0000440 else:
Guido van Rossum0147db01996-03-09 03:16:04 +0000441 qs = '' # Unknown content-type
Guido van Rossumafb5e931996-08-08 18:42:12 +0000442 if environ.has_key('QUERY_STRING'):
443 if qs: qs = qs + '&'
444 qs = qs + environ['QUERY_STRING']
445 elif sys.argv[1:]:
446 if qs: qs = qs + '&'
447 qs = qs + sys.argv[1]
Guido van Rossum7aee3841996-03-07 18:00:44 +0000448 environ['QUERY_STRING'] = qs # XXX Shouldn't, really
449 elif environ.has_key('QUERY_STRING'):
450 qs = environ['QUERY_STRING']
451 else:
452 if sys.argv[1:]:
453 qs = sys.argv[1]
454 else:
455 qs = ""
456 environ['QUERY_STRING'] = qs # XXX Shouldn't, really
Guido van Rossum773ab271996-07-23 03:46:24 +0000457 return parse_qs(qs, keep_blank_values)
Guido van Rossume7808771995-08-07 20:12:09 +0000458
459
Guido van Rossum773ab271996-07-23 03:46:24 +0000460def parse_qs(qs, keep_blank_values=None):
461 """Parse a query given as a string argumen
462
463 Arguments:
464
465 qs : URL-encoded query string to be parsed
466
467 keep_blank_values: flag indicating whether blank values in
468 URL encoded queries should be treated as blank strings.
469 A true value inicates that blanks should be retained as
470 blank strings. The default false value indicates that
471 blank values are to be ignored and treated as if they were
472 not included.
473 """
Guido van Rossum0147db01996-03-09 03:16:04 +0000474 import urllib, regsub
Guido van Rossum7aee3841996-03-07 18:00:44 +0000475 name_value_pairs = string.splitfields(qs, '&')
476 dict = {}
477 for name_value in name_value_pairs:
478 nv = string.splitfields(name_value, '=')
479 if len(nv) != 2:
480 continue
481 name = nv[0]
482 value = urllib.unquote(regsub.gsub('+', ' ', nv[1]))
Guido van Rossum773ab271996-07-23 03:46:24 +0000483 if len(value) or keep_blank_values:
Guido van Rossum7aee3841996-03-07 18:00:44 +0000484 if dict.has_key (name):
485 dict[name].append(value)
486 else:
487 dict[name] = [value]
488 return dict
Guido van Rossum9a22de11995-01-12 12:29:47 +0000489
490
Guido van Rossum0147db01996-03-09 03:16:04 +0000491def parse_multipart(fp, pdict):
Guido van Rossum7aee3841996-03-07 18:00:44 +0000492 """Parse multipart input.
Guido van Rossum9a22de11995-01-12 12:29:47 +0000493
Guido van Rossum7aee3841996-03-07 18:00:44 +0000494 Arguments:
495 fp : input file
Guido van Rossum7aee3841996-03-07 18:00:44 +0000496 pdict: dictionary containing other parameters of conten-type header
Guido van Rossum72755611996-03-06 07:20:06 +0000497
Guido van Rossum0147db01996-03-09 03:16:04 +0000498 Returns a dictionary just like parse_qs(): keys are the field names, each
499 value is a list of values for that field. This is easy to use but not
500 much good if you are expecting megabytes to be uploaded -- in that case,
501 use the FieldStorage class instead which is much more flexible. Note
502 that content-type is the raw, unparsed contents of the content-type
503 header.
504
505 XXX This does not parse nested multipart parts -- use FieldStorage for
506 that.
507
508 XXX This should really be subsumed by FieldStorage altogether -- no
509 point in having two implementations of the same parsing algorithm.
Guido van Rossum72755611996-03-06 07:20:06 +0000510
Guido van Rossum7aee3841996-03-07 18:00:44 +0000511 """
512 import mimetools
513 if pdict.has_key('boundary'):
514 boundary = pdict['boundary']
515 else:
516 boundary = ""
517 nextpart = "--" + boundary
518 lastpart = "--" + boundary + "--"
519 partdict = {}
520 terminator = ""
521
522 while terminator != lastpart:
523 bytes = -1
524 data = None
525 if terminator:
526 # At start of next part. Read headers first.
527 headers = mimetools.Message(fp)
528 clength = headers.getheader('content-length')
529 if clength:
530 try:
531 bytes = string.atoi(clength)
532 except string.atoi_error:
533 pass
534 if bytes > 0:
535 data = fp.read(bytes)
536 else:
537 data = ""
538 # Read lines until end of part.
539 lines = []
540 while 1:
541 line = fp.readline()
542 if not line:
543 terminator = lastpart # End outer loop
544 break
545 if line[:2] == "--":
546 terminator = string.strip(line)
547 if terminator in (nextpart, lastpart):
548 break
Guido van Rossum7aee3841996-03-07 18:00:44 +0000549 lines.append(line)
550 # Done with part.
551 if data is None:
552 continue
553 if bytes < 0:
Guido van Rossum99aa2a41996-07-23 17:27:05 +0000554 if lines:
555 # Strip final line terminator
556 line = lines[-1]
557 if line[-2:] == "\r\n":
558 line = line[:-2]
559 elif line[-1:] == "\n":
560 line = line[:-1]
561 lines[-1] = line
562 data = string.joinfields(lines, "")
Guido van Rossum7aee3841996-03-07 18:00:44 +0000563 line = headers['content-disposition']
564 if not line:
565 continue
566 key, params = parse_header(line)
567 if key != 'form-data':
568 continue
569 if params.has_key('name'):
570 name = params['name']
Guido van Rossum72755611996-03-06 07:20:06 +0000571 else:
Guido van Rossum7aee3841996-03-07 18:00:44 +0000572 continue
Guido van Rossum7aee3841996-03-07 18:00:44 +0000573 if partdict.has_key(name):
574 partdict[name].append(data)
575 else:
576 partdict[name] = [data]
Guido van Rossum72755611996-03-06 07:20:06 +0000577
Guido van Rossum7aee3841996-03-07 18:00:44 +0000578 return partdict
Guido van Rossum9a22de11995-01-12 12:29:47 +0000579
580
Guido van Rossum72755611996-03-06 07:20:06 +0000581def parse_header(line):
Guido van Rossum7aee3841996-03-07 18:00:44 +0000582 """Parse a Content-type like header.
583
584 Return the main content-type and a dictionary of options.
585
586 """
587 plist = map(string.strip, string.splitfields(line, ';'))
588 key = string.lower(plist[0])
589 del plist[0]
590 pdict = {}
591 for p in plist:
592 i = string.find(p, '=')
593 if i >= 0:
594 name = string.lower(string.strip(p[:i]))
595 value = string.strip(p[i+1:])
596 if len(value) >= 2 and value[0] == value[-1] == '"':
597 value = value[1:-1]
598 pdict[name] = value
599 return key, pdict
Guido van Rossum72755611996-03-06 07:20:06 +0000600
601
Guido van Rossum243ddcd1996-03-07 06:33:07 +0000602# Classes for field storage
603# =========================
604
605class MiniFieldStorage:
606
Guido van Rossum0147db01996-03-09 03:16:04 +0000607 """Like FieldStorage, for use when no file uploads are possible."""
Guido van Rossum243ddcd1996-03-07 06:33:07 +0000608
Guido van Rossum7aee3841996-03-07 18:00:44 +0000609 # Dummy attributes
610 filename = None
611 list = None
612 type = None
Guido van Rossum773ab271996-07-23 03:46:24 +0000613 file = None
Guido van Rossum4032c2c1996-03-09 04:04:35 +0000614 type_options = {}
Guido van Rossum7aee3841996-03-07 18:00:44 +0000615 disposition = None
616 disposition_options = {}
617 headers = {}
Guido van Rossum243ddcd1996-03-07 06:33:07 +0000618
Guido van Rossum7aee3841996-03-07 18:00:44 +0000619 def __init__(self, name, value):
620 """Constructor from field name and value."""
621 from StringIO import StringIO
622 self.name = name
623 self.value = value
Guido van Rossum773ab271996-07-23 03:46:24 +0000624 # self.file = StringIO(value)
Guido van Rossum7aee3841996-03-07 18:00:44 +0000625
626 def __repr__(self):
627 """Return printable representation."""
628 return "MiniFieldStorage(%s, %s)" % (`self.name`, `self.value`)
Guido van Rossum243ddcd1996-03-07 06:33:07 +0000629
630
631class FieldStorage:
632
Guido van Rossum7aee3841996-03-07 18:00:44 +0000633 """Store a sequence of fields, reading multipart/form-data.
Guido van Rossum243ddcd1996-03-07 06:33:07 +0000634
Guido van Rossum7aee3841996-03-07 18:00:44 +0000635 This class provides naming, typing, files stored on disk, and
636 more. At the top level, it is accessible like a dictionary, whose
637 keys are the field names. (Note: None can occur as a field name.)
638 The items are either a Python list (if there's multiple values) or
639 another FieldStorage or MiniFieldStorage object. If it's a single
640 object, it has the following attributes:
Guido van Rossum243ddcd1996-03-07 06:33:07 +0000641
Guido van Rossum7aee3841996-03-07 18:00:44 +0000642 name: the field name, if specified; otherwise None
Guido van Rossum243ddcd1996-03-07 06:33:07 +0000643
Guido van Rossum7aee3841996-03-07 18:00:44 +0000644 filename: the filename, if specified; otherwise None; this is the
645 client side filename, *not* the file name on which it is
Guido van Rossum0147db01996-03-09 03:16:04 +0000646 stored (that's a temporary file you don't deal with)
Guido van Rossum243ddcd1996-03-07 06:33:07 +0000647
Guido van Rossum7aee3841996-03-07 18:00:44 +0000648 value: the value as a *string*; for file uploads, this
649 transparently reads the file every time you request the value
650
651 file: the file(-like) object from which you can read the data;
652 None if the data is stored a simple string
653
654 type: the content-type, or None if not specified
655
656 type_options: dictionary of options specified on the content-type
657 line
658
659 disposition: content-disposition, or None if not specified
660
661 disposition_options: dictionary of corresponding options
662
663 headers: a dictionary(-like) object (sometimes rfc822.Message or a
664 subclass thereof) containing *all* headers
665
666 The class is subclassable, mostly for the purpose of overriding
667 the make_file() method, which is called internally to come up with
668 a file open for reading and writing. This makes it possible to
669 override the default choice of storing all files in a temporary
670 directory and unlinking them as soon as they have been opened.
671
672 """
673
Guido van Rossum773ab271996-07-23 03:46:24 +0000674 def __init__(self, fp=None, headers=None, outerboundary="",
675 environ=os.environ, keep_blank_values=None):
Guido van Rossum7aee3841996-03-07 18:00:44 +0000676 """Constructor. Read multipart/* until last part.
677
678 Arguments, all optional:
679
680 fp : file pointer; default: sys.stdin
681
682 headers : header dictionary-like object; default:
683 taken from environ as per CGI spec
684
Guido van Rossum773ab271996-07-23 03:46:24 +0000685 outerboundary : terminating multipart boundary
Guido van Rossum7aee3841996-03-07 18:00:44 +0000686 (for internal use only)
687
Guido van Rossum773ab271996-07-23 03:46:24 +0000688 environ : environment dictionary; default: os.environ
689
690 keep_blank_values: flag indicating whether blank values in
691 URL encoded forms should be treated as blank strings.
692 A true value inicates that blanks should be retained as
693 blank strings. The default false value indicates that
694 blank values are to be ignored and treated as if they were
695 not included.
696
Guido van Rossum7aee3841996-03-07 18:00:44 +0000697 """
698 method = None
Guido van Rossum773ab271996-07-23 03:46:24 +0000699 self.keep_blank_values = keep_blank_values
Guido van Rossum7aee3841996-03-07 18:00:44 +0000700 if environ.has_key('REQUEST_METHOD'):
701 method = string.upper(environ['REQUEST_METHOD'])
702 if not fp and method == 'GET':
703 qs = None
704 if environ.has_key('QUERY_STRING'):
705 qs = environ['QUERY_STRING']
706 from StringIO import StringIO
707 fp = StringIO(qs or "")
708 if headers is None:
709 headers = {'content-type':
710 "application/x-www-form-urlencoded"}
711 if headers is None:
712 headers = {}
713 if environ.has_key('CONTENT_TYPE'):
714 headers['content-type'] = environ['CONTENT_TYPE']
715 if environ.has_key('CONTENT_LENGTH'):
716 headers['content-length'] = environ['CONTENT_LENGTH']
717 self.fp = fp or sys.stdin
718 self.headers = headers
719 self.outerboundary = outerboundary
720
721 # Process content-disposition header
722 cdisp, pdict = "", {}
723 if self.headers.has_key('content-disposition'):
724 cdisp, pdict = parse_header(self.headers['content-disposition'])
725 self.disposition = cdisp
726 self.disposition_options = pdict
727 self.name = None
728 if pdict.has_key('name'):
729 self.name = pdict['name']
730 self.filename = None
731 if pdict.has_key('filename'):
732 self.filename = pdict['filename']
733
734 # Process content-type header
735 ctype, pdict = "text/plain", {}
736 if self.headers.has_key('content-type'):
737 ctype, pdict = parse_header(self.headers['content-type'])
738 self.type = ctype
739 self.type_options = pdict
740 self.innerboundary = ""
741 if pdict.has_key('boundary'):
742 self.innerboundary = pdict['boundary']
743 clen = -1
744 if self.headers.has_key('content-length'):
745 try:
746 clen = string.atoi(self.headers['content-length'])
747 except:
748 pass
749 self.length = clen
750
751 self.list = self.file = None
752 self.done = 0
753 self.lines = []
754 if ctype == 'application/x-www-form-urlencoded':
755 self.read_urlencoded()
756 elif ctype[:10] == 'multipart/':
757 self.read_multi()
758 else:
759 self.read_single()
760
761 def __repr__(self):
762 """Return a printable representation."""
763 return "FieldStorage(%s, %s, %s)" % (
764 `self.name`, `self.filename`, `self.value`)
765
766 def __getattr__(self, name):
767 if name != 'value':
768 raise AttributeError, name
769 if self.file:
770 self.file.seek(0)
771 value = self.file.read()
772 self.file.seek(0)
773 elif self.list is not None:
774 value = self.list
775 else:
776 value = None
777 return value
778
779 def __getitem__(self, key):
780 """Dictionary style indexing."""
781 if self.list is None:
782 raise TypeError, "not indexable"
783 found = []
784 for item in self.list:
785 if item.name == key: found.append(item)
786 if not found:
787 raise KeyError, key
Guido van Rossum0147db01996-03-09 03:16:04 +0000788 if len(found) == 1:
789 return found[0]
790 else:
791 return found
Guido van Rossum7aee3841996-03-07 18:00:44 +0000792
793 def keys(self):
794 """Dictionary style keys() method."""
795 if self.list is None:
796 raise TypeError, "not indexable"
797 keys = []
798 for item in self.list:
799 if item.name not in keys: keys.append(item.name)
800 return keys
801
Guido van Rossum0147db01996-03-09 03:16:04 +0000802 def has_key(self, key):
803 """Dictionary style has_key() method."""
804 if self.list is None:
805 raise TypeError, "not indexable"
806 for item in self.list:
807 if item.name == key: return 1
808 return 0
809
Guido van Rossum7aee3841996-03-07 18:00:44 +0000810 def read_urlencoded(self):
811 """Internal: read data in query string format."""
812 qs = self.fp.read(self.length)
Guido van Rossum773ab271996-07-23 03:46:24 +0000813 dict = parse_qs(qs, self.keep_blank_values)
Guido van Rossum7aee3841996-03-07 18:00:44 +0000814 self.list = []
815 for key, valuelist in dict.items():
816 for value in valuelist:
817 self.list.append(MiniFieldStorage(key, value))
818 self.skip_lines()
819
820 def read_multi(self):
821 """Internal: read a part that is itself multipart."""
822 import rfc822
823 self.list = []
824 part = self.__class__(self.fp, {}, self.innerboundary)
825 # Throw first part away
826 while not part.done:
827 headers = rfc822.Message(self.fp)
828 part = self.__class__(self.fp, headers, self.innerboundary)
829 self.list.append(part)
830 self.skip_lines()
831
832 def read_single(self):
833 """Internal: read an atomic part."""
834 if self.length >= 0:
835 self.read_binary()
836 self.skip_lines()
837 else:
838 self.read_lines()
839 self.file.seek(0)
840
841 bufsize = 8*1024 # I/O buffering size for copy to file
842
843 def read_binary(self):
844 """Internal: read binary data."""
845 self.file = self.make_file('b')
846 todo = self.length
847 if todo >= 0:
848 while todo > 0:
849 data = self.fp.read(min(todo, self.bufsize))
850 if not data:
851 self.done = -1
852 break
853 self.file.write(data)
854 todo = todo - len(data)
855
856 def read_lines(self):
857 """Internal: read lines until EOF or outerboundary."""
858 self.file = self.make_file('')
859 if self.outerboundary:
860 self.read_lines_to_outerboundary()
861 else:
862 self.read_lines_to_eof()
863
864 def read_lines_to_eof(self):
865 """Internal: read lines until EOF."""
866 while 1:
867 line = self.fp.readline()
868 if not line:
869 self.done = -1
870 break
871 self.lines.append(line)
Guido van Rossum7aee3841996-03-07 18:00:44 +0000872 self.file.write(line)
873
874 def read_lines_to_outerboundary(self):
875 """Internal: read lines until outerboundary."""
876 next = "--" + self.outerboundary
877 last = next + "--"
878 delim = ""
879 while 1:
880 line = self.fp.readline()
881 if not line:
882 self.done = -1
883 break
884 self.lines.append(line)
885 if line[:2] == "--":
886 strippedline = string.strip(line)
887 if strippedline == next:
888 break
889 if strippedline == last:
890 self.done = 1
891 break
892 if line[-2:] == "\r\n":
Guido van Rossum99aa2a41996-07-23 17:27:05 +0000893 delim = "\r\n"
Guido van Rossum7aee3841996-03-07 18:00:44 +0000894 line = line[:-2]
895 elif line[-1] == "\n":
Guido van Rossum99aa2a41996-07-23 17:27:05 +0000896 delim = "\n"
Guido van Rossum7aee3841996-03-07 18:00:44 +0000897 line = line[:-1]
Guido van Rossum99aa2a41996-07-23 17:27:05 +0000898 else:
899 delim = ""
Guido van Rossum7aee3841996-03-07 18:00:44 +0000900 self.file.write(delim + line)
Guido van Rossum7aee3841996-03-07 18:00:44 +0000901
902 def skip_lines(self):
903 """Internal: skip lines until outer boundary if defined."""
904 if not self.outerboundary or self.done:
905 return
906 next = "--" + self.outerboundary
907 last = next + "--"
908 while 1:
909 line = self.fp.readline()
910 if not line:
911 self.done = -1
912 break
913 self.lines.append(line)
914 if line[:2] == "--":
915 strippedline = string.strip(line)
916 if strippedline == next:
917 break
918 if strippedline == last:
919 self.done = 1
920 break
921
922 def make_file(self, binary):
923 """Overridable: return a readable & writable file.
924
925 The file will be used as follows:
926 - data is written to it
927 - seek(0)
928 - data is read from it
929
930 The 'binary' argument is 'b' if the file should be created in
931 binary mode (on non-Unix systems), '' otherwise.
932
Guido van Rossum4032c2c1996-03-09 04:04:35 +0000933 This version opens a temporary file for reading and writing,
934 and immediately deletes (unlinks) it. The trick (on Unix!) is
935 that the file can still be used, but it can't be opened by
936 another process, and it will automatically be deleted when it
937 is closed or when the current process terminates.
938
939 If you want a more permanent file, you derive a class which
940 overrides this method. If you want a visible temporary file
941 that is nevertheless automatically deleted when the script
942 terminates, try defining a __del__ method in a derived class
943 which unlinks the temporary files you have created.
Guido van Rossum7aee3841996-03-07 18:00:44 +0000944
945 """
Guido van Rossum4032c2c1996-03-09 04:04:35 +0000946 import tempfile
947 tfn = tempfile.mktemp()
948 f = open(tfn, "w%s+" % binary)
949 os.unlink(tfn)
950 return f
Guido van Rossum243ddcd1996-03-07 06:33:07 +0000951
952
Guido van Rossum4032c2c1996-03-09 04:04:35 +0000953# Backwards Compatibility Classes
954# ===============================
Guido van Rossum9a22de11995-01-12 12:29:47 +0000955
956class FormContentDict:
Guido van Rossum7aee3841996-03-07 18:00:44 +0000957 """Basic (multiple values per field) form content as dictionary.
Guido van Rossum72755611996-03-06 07:20:06 +0000958
Guido van Rossum7aee3841996-03-07 18:00:44 +0000959 form = FormContentDict()
960
961 form[key] -> [value, value, ...]
962 form.has_key(key) -> Boolean
963 form.keys() -> [key, key, ...]
964 form.values() -> [[val, val, ...], [val, val, ...], ...]
965 form.items() -> [(key, [val, val, ...]), (key, [val, val, ...]), ...]
966 form.dict == {key: [val, val, ...], ...}
967
968 """
Guido van Rossum773ab271996-07-23 03:46:24 +0000969 def __init__(self, environ=os.environ):
Guido van Rossumafb5e931996-08-08 18:42:12 +0000970 self.dict = parse(environ=environ)
Guido van Rossum7aee3841996-03-07 18:00:44 +0000971 self.query_string = environ['QUERY_STRING']
972 def __getitem__(self,key):
973 return self.dict[key]
974 def keys(self):
975 return self.dict.keys()
976 def has_key(self, key):
977 return self.dict.has_key(key)
978 def values(self):
979 return self.dict.values()
980 def items(self):
981 return self.dict.items()
982 def __len__( self ):
983 return len(self.dict)
Guido van Rossum9a22de11995-01-12 12:29:47 +0000984
985
Guido van Rossum9a22de11995-01-12 12:29:47 +0000986class SvFormContentDict(FormContentDict):
Guido van Rossum7aee3841996-03-07 18:00:44 +0000987 """Strict single-value expecting form content as dictionary.
988
989 IF you only expect a single value for each field, then form[key]
990 will return that single value. It will raise an IndexError if
991 that expectation is not true. IF you expect a field to have
992 possible multiple values, than you can use form.getlist(key) to
993 get all of the values. values() and items() are a compromise:
994 they return single strings where there is a single value, and
995 lists of strings otherwise.
996
997 """
998 def __getitem__(self, key):
999 if len(self.dict[key]) > 1:
1000 raise IndexError, 'expecting a single value'
1001 return self.dict[key][0]
1002 def getlist(self, key):
1003 return self.dict[key]
1004 def values(self):
1005 lis = []
1006 for each in self.dict.values():
1007 if len( each ) == 1 :
1008 lis.append(each[0])
1009 else: lis.append(each)
1010 return lis
1011 def items(self):
1012 lis = []
1013 for key,value in self.dict.items():
1014 if len(value) == 1 :
1015 lis.append((key, value[0]))
1016 else: lis.append((key, value))
1017 return lis
Guido van Rossum9a22de11995-01-12 12:29:47 +00001018
1019
Guido van Rossum9a22de11995-01-12 12:29:47 +00001020class InterpFormContentDict(SvFormContentDict):
Guido van Rossum7aee3841996-03-07 18:00:44 +00001021 """This class is present for backwards compatibility only."""
1022 def __getitem__( self, key ):
1023 v = SvFormContentDict.__getitem__( self, key )
1024 if v[0] in string.digits+'+-.' :
1025 try: return string.atoi( v )
1026 except ValueError:
1027 try: return string.atof( v )
1028 except ValueError: pass
1029 return string.strip(v)
1030 def values( self ):
1031 lis = []
1032 for key in self.keys():
1033 try:
1034 lis.append( self[key] )
1035 except IndexError:
1036 lis.append( self.dict[key] )
1037 return lis
1038 def items( self ):
1039 lis = []
1040 for key in self.keys():
1041 try:
1042 lis.append( (key, self[key]) )
1043 except IndexError:
1044 lis.append( (key, self.dict[key]) )
1045 return lis
Guido van Rossum9a22de11995-01-12 12:29:47 +00001046
1047
Guido van Rossum9a22de11995-01-12 12:29:47 +00001048class FormContent(FormContentDict):
Guido van Rossum7aee3841996-03-07 18:00:44 +00001049 """This class is present for backwards compatibility only."""
Guido van Rossum0147db01996-03-09 03:16:04 +00001050 def values(self, key):
1051 if self.dict.has_key(key) :return self.dict[key]
Guido van Rossum7aee3841996-03-07 18:00:44 +00001052 else: return None
Guido van Rossum0147db01996-03-09 03:16:04 +00001053 def indexed_value(self, key, location):
Guido van Rossum7aee3841996-03-07 18:00:44 +00001054 if self.dict.has_key(key):
1055 if len (self.dict[key]) > location:
1056 return self.dict[key][location]
1057 else: return None
1058 else: return None
Guido van Rossum0147db01996-03-09 03:16:04 +00001059 def value(self, key):
1060 if self.dict.has_key(key): return self.dict[key][0]
Guido van Rossum7aee3841996-03-07 18:00:44 +00001061 else: return None
Guido van Rossum0147db01996-03-09 03:16:04 +00001062 def length(self, key):
1063 return len(self.dict[key])
1064 def stripped(self, key):
1065 if self.dict.has_key(key): return string.strip(self.dict[key][0])
Guido van Rossum7aee3841996-03-07 18:00:44 +00001066 else: return None
1067 def pars(self):
1068 return self.dict
Guido van Rossum9a22de11995-01-12 12:29:47 +00001069
1070
Guido van Rossum72755611996-03-06 07:20:06 +00001071# Test/debug code
1072# ===============
Guido van Rossum9a22de11995-01-12 12:29:47 +00001073
Guido van Rossum773ab271996-07-23 03:46:24 +00001074def test(environ=os.environ):
Guido van Rossum7aee3841996-03-07 18:00:44 +00001075 """Robust test CGI script, usable as main program.
Guido van Rossum9a22de11995-01-12 12:29:47 +00001076
Guido van Rossum7aee3841996-03-07 18:00:44 +00001077 Write minimal HTTP headers and dump all information provided to
1078 the script in HTML form.
1079
1080 """
1081 import traceback
1082 print "Content-type: text/html"
1083 print
1084 sys.stderr = sys.stdout
1085 try:
Guido van Rossum0147db01996-03-09 03:16:04 +00001086 form = FieldStorage() # Replace with other classes to test those
1087 print_form(form)
Guido van Rossum773ab271996-07-23 03:46:24 +00001088 print_environ(environ)
Guido van Rossum7aee3841996-03-07 18:00:44 +00001089 print_directory()
Guido van Rossuma8738a51996-03-14 21:30:28 +00001090 print_arguments()
Guido van Rossum7aee3841996-03-07 18:00:44 +00001091 print_environ_usage()
1092 except:
1093 print "\n\n<PRE>" # Turn off HTML word wrap
1094 traceback.print_exc()
Guido van Rossum9a22de11995-01-12 12:29:47 +00001095
Guido van Rossum773ab271996-07-23 03:46:24 +00001096def print_environ(environ=os.environ):
Guido van Rossum7aee3841996-03-07 18:00:44 +00001097 """Dump the shell environment as HTML."""
1098 keys = environ.keys()
1099 keys.sort()
1100 print
Guido van Rossum503e50b1996-05-28 22:57:20 +00001101 print "<H3>Shell Environment:</H3>"
Guido van Rossum7aee3841996-03-07 18:00:44 +00001102 print "<DL>"
1103 for key in keys:
1104 print "<DT>", escape(key), "<DD>", escape(environ[key])
1105 print "</DL>"
1106 print
Guido van Rossum72755611996-03-06 07:20:06 +00001107
1108def print_form(form):
Guido van Rossum7aee3841996-03-07 18:00:44 +00001109 """Dump the contents of a form as HTML."""
1110 keys = form.keys()
1111 keys.sort()
1112 print
Guido van Rossum503e50b1996-05-28 22:57:20 +00001113 print "<H3>Form Contents:</H3>"
Guido van Rossum7aee3841996-03-07 18:00:44 +00001114 print "<DL>"
1115 for key in keys:
1116 print "<DT>" + escape(key) + ":",
1117 value = form[key]
1118 print "<i>" + escape(`type(value)`) + "</i>"
1119 print "<DD>" + escape(`value`)
1120 print "</DL>"
1121 print
1122
1123def print_directory():
1124 """Dump the current directory as HTML."""
1125 print
1126 print "<H3>Current Working Directory:</H3>"
1127 try:
1128 pwd = os.getcwd()
1129 except os.error, msg:
1130 print "os.error:", escape(str(msg))
1131 else:
1132 print escape(pwd)
1133 print
Guido van Rossum9a22de11995-01-12 12:29:47 +00001134
Guido van Rossuma8738a51996-03-14 21:30:28 +00001135def print_arguments():
1136 print
Guido van Rossum503e50b1996-05-28 22:57:20 +00001137 print "<H3>Command Line Arguments:</H3>"
Guido van Rossuma8738a51996-03-14 21:30:28 +00001138 print
1139 print sys.argv
1140 print
1141
Guido van Rossum9a22de11995-01-12 12:29:47 +00001142def print_environ_usage():
Guido van Rossum7aee3841996-03-07 18:00:44 +00001143 """Dump a list of environment variables used by CGI as HTML."""
1144 print """
Guido van Rossum72755611996-03-06 07:20:06 +00001145<H3>These environment variables could have been set:</H3>
1146<UL>
Guido van Rossum9a22de11995-01-12 12:29:47 +00001147<LI>AUTH_TYPE
1148<LI>CONTENT_LENGTH
1149<LI>CONTENT_TYPE
1150<LI>DATE_GMT
1151<LI>DATE_LOCAL
1152<LI>DOCUMENT_NAME
1153<LI>DOCUMENT_ROOT
1154<LI>DOCUMENT_URI
1155<LI>GATEWAY_INTERFACE
1156<LI>LAST_MODIFIED
1157<LI>PATH
1158<LI>PATH_INFO
1159<LI>PATH_TRANSLATED
1160<LI>QUERY_STRING
1161<LI>REMOTE_ADDR
1162<LI>REMOTE_HOST
1163<LI>REMOTE_IDENT
1164<LI>REMOTE_USER
1165<LI>REQUEST_METHOD
1166<LI>SCRIPT_NAME
1167<LI>SERVER_NAME
1168<LI>SERVER_PORT
1169<LI>SERVER_PROTOCOL
1170<LI>SERVER_ROOT
1171<LI>SERVER_SOFTWARE
1172</UL>
Guido van Rossum7aee3841996-03-07 18:00:44 +00001173In addition, HTTP headers sent by the server may be passed in the
1174environment as well. Here are some common variable names:
1175<UL>
1176<LI>HTTP_ACCEPT
1177<LI>HTTP_CONNECTION
1178<LI>HTTP_HOST
1179<LI>HTTP_PRAGMA
1180<LI>HTTP_REFERER
1181<LI>HTTP_USER_AGENT
1182</UL>
Guido van Rossum9a22de11995-01-12 12:29:47 +00001183"""
1184
Guido van Rossum9a22de11995-01-12 12:29:47 +00001185
Guido van Rossum72755611996-03-06 07:20:06 +00001186# Utilities
1187# =========
Guido van Rossum9a22de11995-01-12 12:29:47 +00001188
Guido van Rossum72755611996-03-06 07:20:06 +00001189def escape(s):
Guido van Rossum7aee3841996-03-07 18:00:44 +00001190 """Replace special characters '&', '<' and '>' by SGML entities."""
Guido van Rossum0147db01996-03-09 03:16:04 +00001191 import regsub
Guido van Rossum7aee3841996-03-07 18:00:44 +00001192 s = regsub.gsub("&", "&amp;", s) # Must be done first!
1193 s = regsub.gsub("<", "&lt;", s)
1194 s = regsub.gsub(">", "&gt;", s)
1195 return s
Guido van Rossum9a22de11995-01-12 12:29:47 +00001196
Guido van Rossum9a22de11995-01-12 12:29:47 +00001197
Guido van Rossum72755611996-03-06 07:20:06 +00001198# Invoke mainline
1199# ===============
1200
1201# Call test() when this file is run as a script (not imported as a module)
1202if __name__ == '__main__':
Guido van Rossum7aee3841996-03-07 18:00:44 +00001203 test()