Commit | Line | Data |
---|---|---|
920dae64 AT |
1 | #! /usr/local/bin/python |
2 | ||
3 | # NOTE: the above "/usr/local/bin/python" is NOT a mistake. It is | |
4 | # intentionally NOT "/usr/bin/env python". On many systems | |
5 | # (e.g. Solaris), /usr/local/bin is not in $PATH as passed to CGI | |
6 | # scripts, and /usr/local/bin is the default directory where Python is | |
7 | # installed, so /usr/bin/env would be unable to find python. Granted, | |
8 | # binary installations by Linux vendors often install Python in | |
9 | # /usr/bin. So let those vendors patch cgi.py to match their choice | |
10 | # of installation. | |
11 | ||
12 | """Support module for CGI (Common Gateway Interface) scripts. | |
13 | ||
14 | This module defines a number of utilities for use by CGI scripts | |
15 | written in Python. | |
16 | """ | |
17 | ||
18 | # XXX Perhaps there should be a slimmed version that doesn't contain | |
19 | # all those backwards compatible and debugging classes and functions? | |
20 | ||
21 | # History | |
22 | # ------- | |
23 | # | |
24 | # Michael McLay started this module. Steve Majewski changed the | |
25 | # interface to SvFormContentDict and FormContentDict. The multipart | |
26 | # parsing was inspired by code submitted by Andreas Paepcke. Guido van | |
27 | # Rossum rewrote, reformatted and documented the module and is currently | |
28 | # responsible for its maintenance. | |
29 | # | |
30 | ||
31 | __version__ = "2.6" | |
32 | ||
33 | ||
34 | # Imports | |
35 | # ======= | |
36 | ||
37 | import sys | |
38 | import os | |
39 | import urllib | |
40 | import mimetools | |
41 | import rfc822 | |
42 | import UserDict | |
43 | from StringIO import StringIO | |
44 | ||
45 | __all__ = ["MiniFieldStorage", "FieldStorage", "FormContentDict", | |
46 | "SvFormContentDict", "InterpFormContentDict", "FormContent", | |
47 | "parse", "parse_qs", "parse_qsl", "parse_multipart", | |
48 | "parse_header", "print_exception", "print_environ", | |
49 | "print_form", "print_directory", "print_arguments", | |
50 | "print_environ_usage", "escape"] | |
51 | ||
52 | # Logging support | |
53 | # =============== | |
54 | ||
55 | logfile = "" # Filename to log to, if not empty | |
56 | logfp = None # File object to log to, if not None | |
57 | ||
58 | def initlog(*allargs): | |
59 | """Write a log message, if there is a log file. | |
60 | ||
61 | Even though this function is called initlog(), you should always | |
62 | use log(); log is a variable that is set either to initlog | |
63 | (initially), to dolog (once the log file has been opened), or to | |
64 | nolog (when logging is disabled). | |
65 | ||
66 | The first argument is a format string; the remaining arguments (if | |
67 | any) are arguments to the % operator, so e.g. | |
68 | log("%s: %s", "a", "b") | |
69 | will write "a: b" to the log file, followed by a newline. | |
70 | ||
71 | If the global logfp is not None, it should be a file object to | |
72 | which log data is written. | |
73 | ||
74 | If the global logfp is None, the global logfile may be a string | |
75 | giving a filename to open, in append mode. This file should be | |
76 | world writable!!! If the file can't be opened, logging is | |
77 | silently disabled (since there is no safe place where we could | |
78 | send an error message). | |
79 | ||
80 | """ | |
81 | global logfp, log | |
82 | if logfile and not logfp: | |
83 | try: | |
84 | logfp = open(logfile, "a") | |
85 | except IOError: | |
86 | pass | |
87 | if not logfp: | |
88 | log = nolog | |
89 | else: | |
90 | log = dolog | |
91 | log(*allargs) | |
92 | ||
93 | def dolog(fmt, *args): | |
94 | """Write a log message to the log file. See initlog() for docs.""" | |
95 | logfp.write(fmt%args + "\n") | |
96 | ||
97 | def nolog(*allargs): | |
98 | """Dummy function, assigned to log when logging is disabled.""" | |
99 | pass | |
100 | ||
101 | log = initlog # The current logging function | |
102 | ||
103 | ||
104 | # Parsing functions | |
105 | # ================= | |
106 | ||
107 | # Maximum input we will accept when REQUEST_METHOD is POST | |
108 | # 0 ==> unlimited input | |
109 | maxlen = 0 | |
110 | ||
111 | def parse(fp=None, environ=os.environ, keep_blank_values=0, strict_parsing=0): | |
112 | """Parse a query in the environment or from a file (default stdin) | |
113 | ||
114 | Arguments, all optional: | |
115 | ||
116 | fp : file pointer; default: sys.stdin | |
117 | ||
118 | environ : environment dictionary; default: os.environ | |
119 | ||
120 | keep_blank_values: flag indicating whether blank values in | |
121 | URL encoded forms should be treated as blank strings. | |
122 | A true value indicates that blanks should be retained as | |
123 | blank strings. The default false value indicates that | |
124 | blank values are to be ignored and treated as if they were | |
125 | not included. | |
126 | ||
127 | strict_parsing: flag indicating what to do with parsing errors. | |
128 | If false (the default), errors are silently ignored. | |
129 | If true, errors raise a ValueError exception. | |
130 | """ | |
131 | if fp is None: | |
132 | fp = sys.stdin | |
133 | if not 'REQUEST_METHOD' in environ: | |
134 | environ['REQUEST_METHOD'] = 'GET' # For testing stand-alone | |
135 | if environ['REQUEST_METHOD'] == 'POST': | |
136 | ctype, pdict = parse_header(environ['CONTENT_TYPE']) | |
137 | if ctype == 'multipart/form-data': | |
138 | return parse_multipart(fp, pdict) | |
139 | elif ctype == 'application/x-www-form-urlencoded': | |
140 | clength = int(environ['CONTENT_LENGTH']) | |
141 | if maxlen and clength > maxlen: | |
142 | raise ValueError, 'Maximum content length exceeded' | |
143 | qs = fp.read(clength) | |
144 | else: | |
145 | qs = '' # Unknown content-type | |
146 | if 'QUERY_STRING' in environ: | |
147 | if qs: qs = qs + '&' | |
148 | qs = qs + environ['QUERY_STRING'] | |
149 | elif sys.argv[1:]: | |
150 | if qs: qs = qs + '&' | |
151 | qs = qs + sys.argv[1] | |
152 | environ['QUERY_STRING'] = qs # XXX Shouldn't, really | |
153 | elif 'QUERY_STRING' in environ: | |
154 | qs = environ['QUERY_STRING'] | |
155 | else: | |
156 | if sys.argv[1:]: | |
157 | qs = sys.argv[1] | |
158 | else: | |
159 | qs = "" | |
160 | environ['QUERY_STRING'] = qs # XXX Shouldn't, really | |
161 | return parse_qs(qs, keep_blank_values, strict_parsing) | |
162 | ||
163 | ||
164 | def parse_qs(qs, keep_blank_values=0, strict_parsing=0): | |
165 | """Parse a query given as a string argument. | |
166 | ||
167 | Arguments: | |
168 | ||
169 | qs: URL-encoded query string to be parsed | |
170 | ||
171 | keep_blank_values: flag indicating whether blank values in | |
172 | URL encoded queries should be treated as blank strings. | |
173 | A true value indicates that blanks should be retained as | |
174 | blank strings. The default false value indicates that | |
175 | blank values are to be ignored and treated as if they were | |
176 | not included. | |
177 | ||
178 | strict_parsing: flag indicating what to do with parsing errors. | |
179 | If false (the default), errors are silently ignored. | |
180 | If true, errors raise a ValueError exception. | |
181 | """ | |
182 | dict = {} | |
183 | for name, value in parse_qsl(qs, keep_blank_values, strict_parsing): | |
184 | if name in dict: | |
185 | dict[name].append(value) | |
186 | else: | |
187 | dict[name] = [value] | |
188 | return dict | |
189 | ||
190 | def parse_qsl(qs, keep_blank_values=0, strict_parsing=0): | |
191 | """Parse a query given as a string argument. | |
192 | ||
193 | Arguments: | |
194 | ||
195 | qs: URL-encoded query string to be parsed | |
196 | ||
197 | keep_blank_values: flag indicating whether blank values in | |
198 | URL encoded queries should be treated as blank strings. A | |
199 | true value indicates that blanks should be retained as blank | |
200 | strings. The default false value indicates that blank values | |
201 | are to be ignored and treated as if they were not included. | |
202 | ||
203 | strict_parsing: flag indicating what to do with parsing errors. If | |
204 | false (the default), errors are silently ignored. If true, | |
205 | errors raise a ValueError exception. | |
206 | ||
207 | Returns a list, as G-d intended. | |
208 | """ | |
209 | pairs = [s2 for s1 in qs.split('&') for s2 in s1.split(';')] | |
210 | r = [] | |
211 | for name_value in pairs: | |
212 | if not name_value and not strict_parsing: | |
213 | continue | |
214 | nv = name_value.split('=', 1) | |
215 | if len(nv) != 2: | |
216 | if strict_parsing: | |
217 | raise ValueError, "bad query field: %r" % (name_value,) | |
218 | # Handle case of a control-name with no equal sign | |
219 | if keep_blank_values: | |
220 | nv.append('') | |
221 | else: | |
222 | continue | |
223 | if len(nv[1]) or keep_blank_values: | |
224 | name = urllib.unquote(nv[0].replace('+', ' ')) | |
225 | value = urllib.unquote(nv[1].replace('+', ' ')) | |
226 | r.append((name, value)) | |
227 | ||
228 | return r | |
229 | ||
230 | ||
231 | def parse_multipart(fp, pdict): | |
232 | """Parse multipart input. | |
233 | ||
234 | Arguments: | |
235 | fp : input file | |
236 | pdict: dictionary containing other parameters of conten-type header | |
237 | ||
238 | Returns a dictionary just like parse_qs(): keys are the field names, each | |
239 | value is a list of values for that field. This is easy to use but not | |
240 | much good if you are expecting megabytes to be uploaded -- in that case, | |
241 | use the FieldStorage class instead which is much more flexible. Note | |
242 | that content-type is the raw, unparsed contents of the content-type | |
243 | header. | |
244 | ||
245 | XXX This does not parse nested multipart parts -- use FieldStorage for | |
246 | that. | |
247 | ||
248 | XXX This should really be subsumed by FieldStorage altogether -- no | |
249 | point in having two implementations of the same parsing algorithm. | |
250 | ||
251 | """ | |
252 | boundary = "" | |
253 | if 'boundary' in pdict: | |
254 | boundary = pdict['boundary'] | |
255 | if not valid_boundary(boundary): | |
256 | raise ValueError, ('Invalid boundary in multipart form: %r' | |
257 | % (boundary,)) | |
258 | ||
259 | nextpart = "--" + boundary | |
260 | lastpart = "--" + boundary + "--" | |
261 | partdict = {} | |
262 | terminator = "" | |
263 | ||
264 | while terminator != lastpart: | |
265 | bytes = -1 | |
266 | data = None | |
267 | if terminator: | |
268 | # At start of next part. Read headers first. | |
269 | headers = mimetools.Message(fp) | |
270 | clength = headers.getheader('content-length') | |
271 | if clength: | |
272 | try: | |
273 | bytes = int(clength) | |
274 | except ValueError: | |
275 | pass | |
276 | if bytes > 0: | |
277 | if maxlen and bytes > maxlen: | |
278 | raise ValueError, 'Maximum content length exceeded' | |
279 | data = fp.read(bytes) | |
280 | else: | |
281 | data = "" | |
282 | # Read lines until end of part. | |
283 | lines = [] | |
284 | while 1: | |
285 | line = fp.readline() | |
286 | if not line: | |
287 | terminator = lastpart # End outer loop | |
288 | break | |
289 | if line[:2] == "--": | |
290 | terminator = line.strip() | |
291 | if terminator in (nextpart, lastpart): | |
292 | break | |
293 | lines.append(line) | |
294 | # Done with part. | |
295 | if data is None: | |
296 | continue | |
297 | if bytes < 0: | |
298 | if lines: | |
299 | # Strip final line terminator | |
300 | line = lines[-1] | |
301 | if line[-2:] == "\r\n": | |
302 | line = line[:-2] | |
303 | elif line[-1:] == "\n": | |
304 | line = line[:-1] | |
305 | lines[-1] = line | |
306 | data = "".join(lines) | |
307 | line = headers['content-disposition'] | |
308 | if not line: | |
309 | continue | |
310 | key, params = parse_header(line) | |
311 | if key != 'form-data': | |
312 | continue | |
313 | if 'name' in params: | |
314 | name = params['name'] | |
315 | else: | |
316 | continue | |
317 | if name in partdict: | |
318 | partdict[name].append(data) | |
319 | else: | |
320 | partdict[name] = [data] | |
321 | ||
322 | return partdict | |
323 | ||
324 | ||
325 | def parse_header(line): | |
326 | """Parse a Content-type like header. | |
327 | ||
328 | Return the main content-type and a dictionary of options. | |
329 | ||
330 | """ | |
331 | plist = map(lambda x: x.strip(), line.split(';')) | |
332 | key = plist.pop(0).lower() | |
333 | pdict = {} | |
334 | for p in plist: | |
335 | i = p.find('=') | |
336 | if i >= 0: | |
337 | name = p[:i].strip().lower() | |
338 | value = p[i+1:].strip() | |
339 | if len(value) >= 2 and value[0] == value[-1] == '"': | |
340 | value = value[1:-1] | |
341 | value = value.replace('\\\\', '\\').replace('\\"', '"') | |
342 | pdict[name] = value | |
343 | return key, pdict | |
344 | ||
345 | ||
346 | # Classes for field storage | |
347 | # ========================= | |
348 | ||
349 | class MiniFieldStorage: | |
350 | ||
351 | """Like FieldStorage, for use when no file uploads are possible.""" | |
352 | ||
353 | # Dummy attributes | |
354 | filename = None | |
355 | list = None | |
356 | type = None | |
357 | file = None | |
358 | type_options = {} | |
359 | disposition = None | |
360 | disposition_options = {} | |
361 | headers = {} | |
362 | ||
363 | def __init__(self, name, value): | |
364 | """Constructor from field name and value.""" | |
365 | self.name = name | |
366 | self.value = value | |
367 | # self.file = StringIO(value) | |
368 | ||
369 | def __repr__(self): | |
370 | """Return printable representation.""" | |
371 | return "MiniFieldStorage(%r, %r)" % (self.name, self.value) | |
372 | ||
373 | ||
374 | class FieldStorage: | |
375 | ||
376 | """Store a sequence of fields, reading multipart/form-data. | |
377 | ||
378 | This class provides naming, typing, files stored on disk, and | |
379 | more. At the top level, it is accessible like a dictionary, whose | |
380 | keys are the field names. (Note: None can occur as a field name.) | |
381 | The items are either a Python list (if there's multiple values) or | |
382 | another FieldStorage or MiniFieldStorage object. If it's a single | |
383 | object, it has the following attributes: | |
384 | ||
385 | name: the field name, if specified; otherwise None | |
386 | ||
387 | filename: the filename, if specified; otherwise None; this is the | |
388 | client side filename, *not* the file name on which it is | |
389 | stored (that's a temporary file you don't deal with) | |
390 | ||
391 | value: the value as a *string*; for file uploads, this | |
392 | transparently reads the file every time you request the value | |
393 | ||
394 | file: the file(-like) object from which you can read the data; | |
395 | None if the data is stored a simple string | |
396 | ||
397 | type: the content-type, or None if not specified | |
398 | ||
399 | type_options: dictionary of options specified on the content-type | |
400 | line | |
401 | ||
402 | disposition: content-disposition, or None if not specified | |
403 | ||
404 | disposition_options: dictionary of corresponding options | |
405 | ||
406 | headers: a dictionary(-like) object (sometimes rfc822.Message or a | |
407 | subclass thereof) containing *all* headers | |
408 | ||
409 | The class is subclassable, mostly for the purpose of overriding | |
410 | the make_file() method, which is called internally to come up with | |
411 | a file open for reading and writing. This makes it possible to | |
412 | override the default choice of storing all files in a temporary | |
413 | directory and unlinking them as soon as they have been opened. | |
414 | ||
415 | """ | |
416 | ||
417 | def __init__(self, fp=None, headers=None, outerboundary="", | |
418 | environ=os.environ, keep_blank_values=0, strict_parsing=0): | |
419 | """Constructor. Read multipart/* until last part. | |
420 | ||
421 | Arguments, all optional: | |
422 | ||
423 | fp : file pointer; default: sys.stdin | |
424 | (not used when the request method is GET) | |
425 | ||
426 | headers : header dictionary-like object; default: | |
427 | taken from environ as per CGI spec | |
428 | ||
429 | outerboundary : terminating multipart boundary | |
430 | (for internal use only) | |
431 | ||
432 | environ : environment dictionary; default: os.environ | |
433 | ||
434 | keep_blank_values: flag indicating whether blank values in | |
435 | URL encoded forms should be treated as blank strings. | |
436 | A true value indicates that blanks should be retained as | |
437 | blank strings. The default false value indicates that | |
438 | blank values are to be ignored and treated as if they were | |
439 | not included. | |
440 | ||
441 | strict_parsing: flag indicating what to do with parsing errors. | |
442 | If false (the default), errors are silently ignored. | |
443 | If true, errors raise a ValueError exception. | |
444 | ||
445 | """ | |
446 | method = 'GET' | |
447 | self.keep_blank_values = keep_blank_values | |
448 | self.strict_parsing = strict_parsing | |
449 | if 'REQUEST_METHOD' in environ: | |
450 | method = environ['REQUEST_METHOD'].upper() | |
451 | if method == 'GET' or method == 'HEAD': | |
452 | if 'QUERY_STRING' in environ: | |
453 | qs = environ['QUERY_STRING'] | |
454 | elif sys.argv[1:]: | |
455 | qs = sys.argv[1] | |
456 | else: | |
457 | qs = "" | |
458 | fp = StringIO(qs) | |
459 | if headers is None: | |
460 | headers = {'content-type': | |
461 | "application/x-www-form-urlencoded"} | |
462 | if headers is None: | |
463 | headers = {} | |
464 | if method == 'POST': | |
465 | # Set default content-type for POST to what's traditional | |
466 | headers['content-type'] = "application/x-www-form-urlencoded" | |
467 | if 'CONTENT_TYPE' in environ: | |
468 | headers['content-type'] = environ['CONTENT_TYPE'] | |
469 | if 'CONTENT_LENGTH' in environ: | |
470 | headers['content-length'] = environ['CONTENT_LENGTH'] | |
471 | self.fp = fp or sys.stdin | |
472 | self.headers = headers | |
473 | self.outerboundary = outerboundary | |
474 | ||
475 | # Process content-disposition header | |
476 | cdisp, pdict = "", {} | |
477 | if 'content-disposition' in self.headers: | |
478 | cdisp, pdict = parse_header(self.headers['content-disposition']) | |
479 | self.disposition = cdisp | |
480 | self.disposition_options = pdict | |
481 | self.name = None | |
482 | if 'name' in pdict: | |
483 | self.name = pdict['name'] | |
484 | self.filename = None | |
485 | if 'filename' in pdict: | |
486 | self.filename = pdict['filename'] | |
487 | ||
488 | # Process content-type header | |
489 | # | |
490 | # Honor any existing content-type header. But if there is no | |
491 | # content-type header, use some sensible defaults. Assume | |
492 | # outerboundary is "" at the outer level, but something non-false | |
493 | # inside a multi-part. The default for an inner part is text/plain, | |
494 | # but for an outer part it should be urlencoded. This should catch | |
495 | # bogus clients which erroneously forget to include a content-type | |
496 | # header. | |
497 | # | |
498 | # See below for what we do if there does exist a content-type header, | |
499 | # but it happens to be something we don't understand. | |
500 | if 'content-type' in self.headers: | |
501 | ctype, pdict = parse_header(self.headers['content-type']) | |
502 | elif self.outerboundary or method != 'POST': | |
503 | ctype, pdict = "text/plain", {} | |
504 | else: | |
505 | ctype, pdict = 'application/x-www-form-urlencoded', {} | |
506 | self.type = ctype | |
507 | self.type_options = pdict | |
508 | self.innerboundary = "" | |
509 | if 'boundary' in pdict: | |
510 | self.innerboundary = pdict['boundary'] | |
511 | clen = -1 | |
512 | if 'content-length' in self.headers: | |
513 | try: | |
514 | clen = int(self.headers['content-length']) | |
515 | except ValueError: | |
516 | pass | |
517 | if maxlen and clen > maxlen: | |
518 | raise ValueError, 'Maximum content length exceeded' | |
519 | self.length = clen | |
520 | ||
521 | self.list = self.file = None | |
522 | self.done = 0 | |
523 | if ctype == 'application/x-www-form-urlencoded': | |
524 | self.read_urlencoded() | |
525 | elif ctype[:10] == 'multipart/': | |
526 | self.read_multi(environ, keep_blank_values, strict_parsing) | |
527 | else: | |
528 | self.read_single() | |
529 | ||
530 | def __repr__(self): | |
531 | """Return a printable representation.""" | |
532 | return "FieldStorage(%r, %r, %r)" % ( | |
533 | self.name, self.filename, self.value) | |
534 | ||
535 | def __iter__(self): | |
536 | return iter(self.keys()) | |
537 | ||
538 | def __getattr__(self, name): | |
539 | if name != 'value': | |
540 | raise AttributeError, name | |
541 | if self.file: | |
542 | self.file.seek(0) | |
543 | value = self.file.read() | |
544 | self.file.seek(0) | |
545 | elif self.list is not None: | |
546 | value = self.list | |
547 | else: | |
548 | value = None | |
549 | return value | |
550 | ||
551 | def __getitem__(self, key): | |
552 | """Dictionary style indexing.""" | |
553 | if self.list is None: | |
554 | raise TypeError, "not indexable" | |
555 | found = [] | |
556 | for item in self.list: | |
557 | if item.name == key: found.append(item) | |
558 | if not found: | |
559 | raise KeyError, key | |
560 | if len(found) == 1: | |
561 | return found[0] | |
562 | else: | |
563 | return found | |
564 | ||
565 | def getvalue(self, key, default=None): | |
566 | """Dictionary style get() method, including 'value' lookup.""" | |
567 | if key in self: | |
568 | value = self[key] | |
569 | if type(value) is type([]): | |
570 | return map(lambda v: v.value, value) | |
571 | else: | |
572 | return value.value | |
573 | else: | |
574 | return default | |
575 | ||
576 | def getfirst(self, key, default=None): | |
577 | """ Return the first value received.""" | |
578 | if key in self: | |
579 | value = self[key] | |
580 | if type(value) is type([]): | |
581 | return value[0].value | |
582 | else: | |
583 | return value.value | |
584 | else: | |
585 | return default | |
586 | ||
587 | def getlist(self, key): | |
588 | """ Return list of received values.""" | |
589 | if key in self: | |
590 | value = self[key] | |
591 | if type(value) is type([]): | |
592 | return map(lambda v: v.value, value) | |
593 | else: | |
594 | return [value.value] | |
595 | else: | |
596 | return [] | |
597 | ||
598 | def keys(self): | |
599 | """Dictionary style keys() method.""" | |
600 | if self.list is None: | |
601 | raise TypeError, "not indexable" | |
602 | keys = [] | |
603 | for item in self.list: | |
604 | if item.name not in keys: keys.append(item.name) | |
605 | return keys | |
606 | ||
607 | def has_key(self, key): | |
608 | """Dictionary style has_key() method.""" | |
609 | if self.list is None: | |
610 | raise TypeError, "not indexable" | |
611 | for item in self.list: | |
612 | if item.name == key: return True | |
613 | return False | |
614 | ||
615 | def __contains__(self, key): | |
616 | """Dictionary style __contains__ method.""" | |
617 | if self.list is None: | |
618 | raise TypeError, "not indexable" | |
619 | for item in self.list: | |
620 | if item.name == key: return True | |
621 | return False | |
622 | ||
623 | def __len__(self): | |
624 | """Dictionary style len(x) support.""" | |
625 | return len(self.keys()) | |
626 | ||
627 | def read_urlencoded(self): | |
628 | """Internal: read data in query string format.""" | |
629 | qs = self.fp.read(self.length) | |
630 | self.list = list = [] | |
631 | for key, value in parse_qsl(qs, self.keep_blank_values, | |
632 | self.strict_parsing): | |
633 | list.append(MiniFieldStorage(key, value)) | |
634 | self.skip_lines() | |
635 | ||
636 | FieldStorageClass = None | |
637 | ||
638 | def read_multi(self, environ, keep_blank_values, strict_parsing): | |
639 | """Internal: read a part that is itself multipart.""" | |
640 | ib = self.innerboundary | |
641 | if not valid_boundary(ib): | |
642 | raise ValueError, 'Invalid boundary in multipart form: %r' % (ib,) | |
643 | self.list = [] | |
644 | klass = self.FieldStorageClass or self.__class__ | |
645 | part = klass(self.fp, {}, ib, | |
646 | environ, keep_blank_values, strict_parsing) | |
647 | # Throw first part away | |
648 | while not part.done: | |
649 | headers = rfc822.Message(self.fp) | |
650 | part = klass(self.fp, headers, ib, | |
651 | environ, keep_blank_values, strict_parsing) | |
652 | self.list.append(part) | |
653 | self.skip_lines() | |
654 | ||
655 | def read_single(self): | |
656 | """Internal: read an atomic part.""" | |
657 | if self.length >= 0: | |
658 | self.read_binary() | |
659 | self.skip_lines() | |
660 | else: | |
661 | self.read_lines() | |
662 | self.file.seek(0) | |
663 | ||
664 | bufsize = 8*1024 # I/O buffering size for copy to file | |
665 | ||
666 | def read_binary(self): | |
667 | """Internal: read binary data.""" | |
668 | self.file = self.make_file('b') | |
669 | todo = self.length | |
670 | if todo >= 0: | |
671 | while todo > 0: | |
672 | data = self.fp.read(min(todo, self.bufsize)) | |
673 | if not data: | |
674 | self.done = -1 | |
675 | break | |
676 | self.file.write(data) | |
677 | todo = todo - len(data) | |
678 | ||
679 | def read_lines(self): | |
680 | """Internal: read lines until EOF or outerboundary.""" | |
681 | self.file = self.__file = StringIO() | |
682 | if self.outerboundary: | |
683 | self.read_lines_to_outerboundary() | |
684 | else: | |
685 | self.read_lines_to_eof() | |
686 | ||
687 | def __write(self, line): | |
688 | if self.__file is not None: | |
689 | if self.__file.tell() + len(line) > 1000: | |
690 | self.file = self.make_file('') | |
691 | self.file.write(self.__file.getvalue()) | |
692 | self.__file = None | |
693 | self.file.write(line) | |
694 | ||
695 | def read_lines_to_eof(self): | |
696 | """Internal: read lines until EOF.""" | |
697 | while 1: | |
698 | line = self.fp.readline() | |
699 | if not line: | |
700 | self.done = -1 | |
701 | break | |
702 | self.__write(line) | |
703 | ||
704 | def read_lines_to_outerboundary(self): | |
705 | """Internal: read lines until outerboundary.""" | |
706 | next = "--" + self.outerboundary | |
707 | last = next + "--" | |
708 | delim = "" | |
709 | while 1: | |
710 | line = self.fp.readline() | |
711 | if not line: | |
712 | self.done = -1 | |
713 | break | |
714 | if line[:2] == "--": | |
715 | strippedline = line.strip() | |
716 | if strippedline == next: | |
717 | break | |
718 | if strippedline == last: | |
719 | self.done = 1 | |
720 | break | |
721 | odelim = delim | |
722 | if line[-2:] == "\r\n": | |
723 | delim = "\r\n" | |
724 | line = line[:-2] | |
725 | elif line[-1] == "\n": | |
726 | delim = "\n" | |
727 | line = line[:-1] | |
728 | else: | |
729 | delim = "" | |
730 | self.__write(odelim + line) | |
731 | ||
732 | def skip_lines(self): | |
733 | """Internal: skip lines until outer boundary if defined.""" | |
734 | if not self.outerboundary or self.done: | |
735 | return | |
736 | next = "--" + self.outerboundary | |
737 | last = next + "--" | |
738 | while 1: | |
739 | line = self.fp.readline() | |
740 | if not line: | |
741 | self.done = -1 | |
742 | break | |
743 | if line[:2] == "--": | |
744 | strippedline = line.strip() | |
745 | if strippedline == next: | |
746 | break | |
747 | if strippedline == last: | |
748 | self.done = 1 | |
749 | break | |
750 | ||
751 | def make_file(self, binary=None): | |
752 | """Overridable: return a readable & writable file. | |
753 | ||
754 | The file will be used as follows: | |
755 | - data is written to it | |
756 | - seek(0) | |
757 | - data is read from it | |
758 | ||
759 | The 'binary' argument is unused -- the file is always opened | |
760 | in binary mode. | |
761 | ||
762 | This version opens a temporary file for reading and writing, | |
763 | and immediately deletes (unlinks) it. The trick (on Unix!) is | |
764 | that the file can still be used, but it can't be opened by | |
765 | another process, and it will automatically be deleted when it | |
766 | is closed or when the current process terminates. | |
767 | ||
768 | If you want a more permanent file, you derive a class which | |
769 | overrides this method. If you want a visible temporary file | |
770 | that is nevertheless automatically deleted when the script | |
771 | terminates, try defining a __del__ method in a derived class | |
772 | which unlinks the temporary files you have created. | |
773 | ||
774 | """ | |
775 | import tempfile | |
776 | return tempfile.TemporaryFile("w+b") | |
777 | ||
778 | ||
779 | ||
780 | # Backwards Compatibility Classes | |
781 | # =============================== | |
782 | ||
783 | class FormContentDict(UserDict.UserDict): | |
784 | """Form content as dictionary with a list of values per field. | |
785 | ||
786 | form = FormContentDict() | |
787 | ||
788 | form[key] -> [value, value, ...] | |
789 | key in form -> Boolean | |
790 | form.keys() -> [key, key, ...] | |
791 | form.values() -> [[val, val, ...], [val, val, ...], ...] | |
792 | form.items() -> [(key, [val, val, ...]), (key, [val, val, ...]), ...] | |
793 | form.dict == {key: [val, val, ...], ...} | |
794 | ||
795 | """ | |
796 | def __init__(self, environ=os.environ): | |
797 | self.dict = self.data = parse(environ=environ) | |
798 | self.query_string = environ['QUERY_STRING'] | |
799 | ||
800 | ||
801 | class SvFormContentDict(FormContentDict): | |
802 | """Form content as dictionary expecting a single value per field. | |
803 | ||
804 | If you only expect a single value for each field, then form[key] | |
805 | will return that single value. It will raise an IndexError if | |
806 | that expectation is not true. If you expect a field to have | |
807 | possible multiple values, than you can use form.getlist(key) to | |
808 | get all of the values. values() and items() are a compromise: | |
809 | they return single strings where there is a single value, and | |
810 | lists of strings otherwise. | |
811 | ||
812 | """ | |
813 | def __getitem__(self, key): | |
814 | if len(self.dict[key]) > 1: | |
815 | raise IndexError, 'expecting a single value' | |
816 | return self.dict[key][0] | |
817 | def getlist(self, key): | |
818 | return self.dict[key] | |
819 | def values(self): | |
820 | result = [] | |
821 | for value in self.dict.values(): | |
822 | if len(value) == 1: | |
823 | result.append(value[0]) | |
824 | else: result.append(value) | |
825 | return result | |
826 | def items(self): | |
827 | result = [] | |
828 | for key, value in self.dict.items(): | |
829 | if len(value) == 1: | |
830 | result.append((key, value[0])) | |
831 | else: result.append((key, value)) | |
832 | return result | |
833 | ||
834 | ||
835 | class InterpFormContentDict(SvFormContentDict): | |
836 | """This class is present for backwards compatibility only.""" | |
837 | def __getitem__(self, key): | |
838 | v = SvFormContentDict.__getitem__(self, key) | |
839 | if v[0] in '0123456789+-.': | |
840 | try: return int(v) | |
841 | except ValueError: | |
842 | try: return float(v) | |
843 | except ValueError: pass | |
844 | return v.strip() | |
845 | def values(self): | |
846 | result = [] | |
847 | for key in self.keys(): | |
848 | try: | |
849 | result.append(self[key]) | |
850 | except IndexError: | |
851 | result.append(self.dict[key]) | |
852 | return result | |
853 | def items(self): | |
854 | result = [] | |
855 | for key in self.keys(): | |
856 | try: | |
857 | result.append((key, self[key])) | |
858 | except IndexError: | |
859 | result.append((key, self.dict[key])) | |
860 | return result | |
861 | ||
862 | ||
863 | class FormContent(FormContentDict): | |
864 | """This class is present for backwards compatibility only.""" | |
865 | def values(self, key): | |
866 | if key in self.dict :return self.dict[key] | |
867 | else: return None | |
868 | def indexed_value(self, key, location): | |
869 | if key in self.dict: | |
870 | if len(self.dict[key]) > location: | |
871 | return self.dict[key][location] | |
872 | else: return None | |
873 | else: return None | |
874 | def value(self, key): | |
875 | if key in self.dict: return self.dict[key][0] | |
876 | else: return None | |
877 | def length(self, key): | |
878 | return len(self.dict[key]) | |
879 | def stripped(self, key): | |
880 | if key in self.dict: return self.dict[key][0].strip() | |
881 | else: return None | |
882 | def pars(self): | |
883 | return self.dict | |
884 | ||
885 | ||
886 | # Test/debug code | |
887 | # =============== | |
888 | ||
889 | def test(environ=os.environ): | |
890 | """Robust test CGI script, usable as main program. | |
891 | ||
892 | Write minimal HTTP headers and dump all information provided to | |
893 | the script in HTML form. | |
894 | ||
895 | """ | |
896 | print "Content-type: text/html" | |
897 | ||
898 | sys.stderr = sys.stdout | |
899 | try: | |
900 | form = FieldStorage() # Replace with other classes to test those | |
901 | print_directory() | |
902 | print_arguments() | |
903 | print_form(form) | |
904 | print_environ(environ) | |
905 | print_environ_usage() | |
906 | def f(): | |
907 | exec "testing print_exception() -- <I>italics?</I>" | |
908 | def g(f=f): | |
909 | f() | |
910 | print "<H3>What follows is a test, not an actual exception:</H3>" | |
911 | g() | |
912 | except: | |
913 | print_exception() | |
914 | ||
915 | print "<H1>Second try with a small maxlen...</H1>" | |
916 | ||
917 | global maxlen | |
918 | maxlen = 50 | |
919 | try: | |
920 | form = FieldStorage() # Replace with other classes to test those | |
921 | print_directory() | |
922 | print_arguments() | |
923 | print_form(form) | |
924 | print_environ(environ) | |
925 | except: | |
926 | print_exception() | |
927 | ||
928 | def print_exception(type=None, value=None, tb=None, limit=None): | |
929 | if type is None: | |
930 | type, value, tb = sys.exc_info() | |
931 | import traceback | |
932 | ||
933 | print "<H3>Traceback (most recent call last):</H3>" | |
934 | list = traceback.format_tb(tb, limit) + \ | |
935 | traceback.format_exception_only(type, value) | |
936 | print "<PRE>%s<B>%s</B></PRE>" % ( | |
937 | escape("".join(list[:-1])), | |
938 | escape(list[-1]), | |
939 | ) | |
940 | del tb | |
941 | ||
942 | def print_environ(environ=os.environ): | |
943 | """Dump the shell environment as HTML.""" | |
944 | keys = environ.keys() | |
945 | keys.sort() | |
946 | ||
947 | print "<H3>Shell Environment:</H3>" | |
948 | print "<DL>" | |
949 | for key in keys: | |
950 | print "<DT>", escape(key), "<DD>", escape(environ[key]) | |
951 | print "</DL>" | |
952 | ||
953 | ||
954 | def print_form(form): | |
955 | """Dump the contents of a form as HTML.""" | |
956 | keys = form.keys() | |
957 | keys.sort() | |
958 | ||
959 | print "<H3>Form Contents:</H3>" | |
960 | if not keys: | |
961 | print "<P>No form fields." | |
962 | print "<DL>" | |
963 | for key in keys: | |
964 | print "<DT>" + escape(key) + ":", | |
965 | value = form[key] | |
966 | print "<i>" + escape(repr(type(value))) + "</i>" | |
967 | print "<DD>" + escape(repr(value)) | |
968 | print "</DL>" | |
969 | ||
970 | ||
971 | def print_directory(): | |
972 | """Dump the current directory as HTML.""" | |
973 | ||
974 | print "<H3>Current Working Directory:</H3>" | |
975 | try: | |
976 | pwd = os.getcwd() | |
977 | except os.error, msg: | |
978 | print "os.error:", escape(str(msg)) | |
979 | else: | |
980 | print escape(pwd) | |
981 | ||
982 | ||
983 | def print_arguments(): | |
984 | ||
985 | print "<H3>Command Line Arguments:</H3>" | |
986 | ||
987 | print sys.argv | |
988 | ||
989 | ||
990 | def print_environ_usage(): | |
991 | """Dump a list of environment variables used by CGI as HTML.""" | |
992 | print """ | |
993 | <H3>These environment variables could have been set:</H3> | |
994 | <UL> | |
995 | <LI>AUTH_TYPE | |
996 | <LI>CONTENT_LENGTH | |
997 | <LI>CONTENT_TYPE | |
998 | <LI>DATE_GMT | |
999 | <LI>DATE_LOCAL | |
1000 | <LI>DOCUMENT_NAME | |
1001 | <LI>DOCUMENT_ROOT | |
1002 | <LI>DOCUMENT_URI | |
1003 | <LI>GATEWAY_INTERFACE | |
1004 | <LI>LAST_MODIFIED | |
1005 | <LI>PATH | |
1006 | <LI>PATH_INFO | |
1007 | <LI>PATH_TRANSLATED | |
1008 | <LI>QUERY_STRING | |
1009 | <LI>REMOTE_ADDR | |
1010 | <LI>REMOTE_HOST | |
1011 | <LI>REMOTE_IDENT | |
1012 | <LI>REMOTE_USER | |
1013 | <LI>REQUEST_METHOD | |
1014 | <LI>SCRIPT_NAME | |
1015 | <LI>SERVER_NAME | |
1016 | <LI>SERVER_PORT | |
1017 | <LI>SERVER_PROTOCOL | |
1018 | <LI>SERVER_ROOT | |
1019 | <LI>SERVER_SOFTWARE | |
1020 | </UL> | |
1021 | In addition, HTTP headers sent by the server may be passed in the | |
1022 | environment as well. Here are some common variable names: | |
1023 | <UL> | |
1024 | <LI>HTTP_ACCEPT | |
1025 | <LI>HTTP_CONNECTION | |
1026 | <LI>HTTP_HOST | |
1027 | <LI>HTTP_PRAGMA | |
1028 | <LI>HTTP_REFERER | |
1029 | <LI>HTTP_USER_AGENT | |
1030 | </UL> | |
1031 | """ | |
1032 | ||
1033 | ||
1034 | # Utilities | |
1035 | # ========= | |
1036 | ||
1037 | def escape(s, quote=None): | |
1038 | """Replace special characters '&', '<' and '>' by SGML entities.""" | |
1039 | s = s.replace("&", "&") # Must be done first! | |
1040 | s = s.replace("<", "<") | |
1041 | s = s.replace(">", ">") | |
1042 | if quote: | |
1043 | s = s.replace('"', """) | |
1044 | return s | |
1045 | ||
1046 | def valid_boundary(s, _vb_pattern="^[ -~]{0,200}[!-~]$"): | |
1047 | import re | |
1048 | return re.match(_vb_pattern, s) | |
1049 | ||
1050 | # Invoke mainline | |
1051 | # =============== | |
1052 | ||
1053 | # Call test() when this file is run as a script (not imported as a module) | |
1054 | if __name__ == '__main__': | |
1055 | test() |