diff options
Diffstat (limited to 'Lib/cgi.py')
-rwxr-xr-x | Lib/cgi.py | 278 |
1 files changed, 278 insertions, 0 deletions
diff --git a/Lib/cgi.py b/Lib/cgi.py new file mode 100755 index 0000000..d412109 --- /dev/null +++ b/Lib/cgi.py @@ -0,0 +1,278 @@ +#!/usr/local/bin/python +# +# A class for wrapping the WWW Forms Common Gateway Interface (CGI) +# Michael McLay, NIST mclay@eeel.nist.gov 6/14/94 +# +# modified by Steve Majewski <sdm7g@Virginia.EDU> 12/5/94 +# + +# Several classes to parse the name/value pairs that are passed to +# a server's CGI by GET, POST or PUT methods by a WWW FORM. This +# module is based on Mike McLay's original cgi.py after discussing +# changes with him and others on the comp.lang.python newsgroup, and +# at the NIST Python workshop. +# +# The rationale for changes was: +# The original FormContent class was almost, but not quite like +# a dictionary object. Besides adding some extra access methods, +# it had a values() method with different arguments and semantics +# from the standard values() method of a mapping object. Also, +# it provided several different access methods that may be necessary +# or useful, but made it a little more confusing to figure out how +# to use. Also, we wanted to make the most typical cases the simplest +# and most convenient access methods. ( Most form fields just return +# a single value, and in practice, a lot of code was just assuming +# a single value and ignoring all others. On the other hand, the +# protocol allows multiple values to be returned. +# +# The new base class (FormContentDict) is just like a dictionary. +# In fact, if you just want a dictionary, all of the stuff that was +# in __init__ has been extracted into a cgi.parse() function that will +# return the "raw" dictionary, but having a class allows you to customize +# it further. +# Mike McLay's original FormContent class is reimplemented as a +# subclass of FormContentDict. +# There are two additional sub-classes, but I'm not yet too sure +# whether they are what I want. +# + +import string,regsub,sys,os,urllib +# since os.environ may often be used in cgi code, we name it in this module. +from os import environ + + +def parse(): + if environ['REQUEST_METHOD'] == 'POST': + qs = sys.stdin.read(string.atoi(environ['CONTENT_LENGTH'])) + environ['QUERY_STRING'] = qs + else: + qs = environ['QUERY_STRING'] + name_value_pairs = string.splitfields(qs, '&') + dict = {} + for name_value in name_value_pairs: + nv = string.splitfields(name_value, '=') + if len(nv) != 2: + continue + name = nv[0] + value = urllib.unquote(regsub.gsub('+',' ',nv[1])) + if len(value): + if dict.has_key (name): + dict[name].append(value) + else: + dict[name] = [value] + return dict + + + +# The FormContent constructor creates a dictionary from the name/value pairs +# passed through the CGI interface. + + +# +# form['key'] +# form.__getitem__('key') +# form.has_key('key') +# form.keys() +# form.values() +# form.items() +# form.dict + +class FormContentDict: + def __init__( self ): + self.dict = parse() + self.query_string = environ['QUERY_STRING'] + def __getitem__(self,key): + return self.dict[key] + def keys(self): + return self.dict.keys() + def has_key(self, key): + return self.dict.has_key(key) + def values(self): + return self.dict.values() + def items(self): + return self.dict.items() + def __len__( self ): + return len(self.dict) + + +# This is the "strict" single-value expecting version. +# IF you only expect a single value for each field, then form[key] +# will return that single value ( the [0]-th ), and raise an +# IndexError if that expectation is not true. +# IF you expect a field to have possible multiple values, than you +# can use form.getlist( key ) to get all of the values. +# values() and items() are a compromise: they return single strings +# where there is a single value, and lists of strings otherwise. + +class SvFormContentDict(FormContentDict): + def __getitem__( self, key ): + if len( self.dict[key] ) > 1 : + raise IndexError, 'expecting a single value' + return self.dict[key][0] + def getlist( self, key ): + return self.dict[key] + def values( self ): + lis = [] + for each in self.dict.values() : + if len( each ) == 1 : + lis.append( each[0] ) + else: lis.append( each ) + return lis + def items( self ): + lis = [] + for key,value in self.dict.items(): + if len(value) == 1 : + lis.append( (key,value[0]) ) + else: lis.append( (key,value) ) + return lis + + +# And this sub-class is similar to the above, but it will attempt to +# interpret numerical values. This is here as mostly as an example, +# but I think the real way to handle typed-data from a form may be +# to make an additional table driver parsing stage that has a table +# of allowed input patterns and the output conversion types - it +# would signal type-errors on parse, not on access. +class InterpFormContentDict(SvFormContentDict): + def __getitem__( self, key ): + v = SvFormContentDict.__getitem__( self, key ) + if v[0] in string.digits+'+-.' : + try: return string.atoi( v ) + except ValueError: + try: return string.atof( v ) + except ValueError: pass + return string.strip(v) + def values( self ): + lis = [] + for key in self.keys(): + try: + lis.append( self[key] ) + except IndexError: + lis.append( self.dict[key] ) + return lis + def items( self ): + lis = [] + for key in self.keys(): + try: + lis.append( (key, self[key]) ) + except IndexError: + lis.append( (key, self.dict[key]) ) + return lis + + +# class FormContent parses the name/value pairs that are passed to a +# server's CGI by GET, POST, or PUT methods by a WWW FORM. several +# specialized FormContent dictionary access methods have been added +# for convenience. + +# function return value +# +# form.keys() all keys in dictionary +# form.has_key('key') test keys existance +# form[key] returns list associated with key +# form.values('key') key's list (same as form.[key]) +# form.indexed_value('key' index) nth element in key's value list +# form.value(key) key's unstripped value +# form.length(key) number of elements in key's list +# form.stripped(key) key's value with whitespace stripped +# form.pars() full dictionary + + + +class FormContent(FormContentDict): +# This is the original FormContent semantics of values, +# not the dictionary like semantics. + def values(self,key): + if self.dict.has_key(key):return self.dict[key] + else: return None + def indexed_value(self,key, location): + if self.dict.has_key(key): + if len (self.dict[key]) > location: + return self.dict[key][location] + else: return None + else: return None + def value(self,key): + if self.dict.has_key(key):return self.dict[key][0] + else: return None + def length(self,key): + return len (self.dict[key]) + def stripped(self,key): + if self.dict.has_key(key):return string.strip(self.dict[key][0]) + else: return None + def pars(self): + return self.dict + + + + + + +def print_environ_usage(): + print """ +<H3>These operating system environment variables could have been +set:</H3> <UL> +<LI>AUTH_TYPE +<LI>CONTENT_LENGTH +<LI>CONTENT_TYPE +<LI>DATE_GMT +<LI>DATE_LOCAL +<LI>DOCUMENT_NAME +<LI>DOCUMENT_ROOT +<LI>DOCUMENT_URI +<LI>GATEWAY_INTERFACE +<LI>LAST_MODIFIED +<LI>PATH +<LI>PATH_INFO +<LI>PATH_TRANSLATED +<LI>QUERY_STRING +<LI>REMOTE_ADDR +<LI>REMOTE_HOST +<LI>REMOTE_IDENT +<LI>REMOTE_USER +<LI>REQUEST_METHOD +<LI>SCRIPT_NAME +<LI>SERVER_NAME +<LI>SERVER_PORT +<LI>SERVER_PROTOCOL +<LI>SERVER_ROOT +<LI>SERVER_SOFTWARE +</UL> +""" + +def print_environ(): + skeys = environ.keys() + skeys.sort() + print '<h3> The following environment variables were set by the CGI script: </H3>' + print '<dl>' + for key in skeys: + print '<dt>',key, '<dd>', environ[key] + print '</dl>' + +def print_form( form ): + print '<h3> The following name/value pairs were entered in the form:</h3>' + print '<dl>' + skeys = form.keys() + skeys.sort() + for key in skeys: + print '<dt>',key, ' : <i> ',escape(`type(form[key])`),' </i>','<dd>', form[key] + print '</dl>' + +def escape( s ): + return regsub.gsub( '<', '<', regsub.gsub( '>' , '>', s )) + +def test( what ): + label = escape(str(what)) + print 'Content-type: text/html\n\n' + print '<HEADER>\n<TITLE>' + label + '</TITLE>\n</HEADER>\n' + print '<BODY>\n' + print "<H1>" + label +"</H1>\n" + form = what() + print_form( form ) + print_environ() + print_environ_usage() + print '</body>' + +if __name__ == '__main__' : + test_classes = ( FormContent, FormContentDict, SvFormContentDict, InterpFormContentDict ) + test( test_classes[0] ) # by default, test compatibility with + # old version, change index to test others. |