cgi.py (was Re: Conversion of http escape characters)

Michael McLay (mclay@eeel.nist.gov)
Wed, 15 Jun 94 09:33:47 EDT

N.G.Smith writes:
> In article <9406141640.AA02288@edison.eeel.nist.gov> mclay@eeel.nist.gov (Michael McLay) writes:
> >N.G.Smith writes:
> > > Is there a neat canned solution to the problem of converting the escaped
> > > characters used in http back to normal characters?
> >
> >Here's my www.py module. It masks the CGI interface inside a class named
> >FormContent. The constructor includes the algorithm that parses the
> >name/value pairs and then the escaped characters that are returned by
> >httpd.
> >
> >Michael
>
> Thanks for the code.
>
> >class FormContent:
> > def __init__(self):
> > if os.environ['QUERY_STRING'] != '':
> > self.qs = os.environ['QUERY_STRING']
> > else:
> > self.qs = sys.stdin.readline()
>
> But, is this bit safe as far as the http specification is concerned?

It works, but only because NCSA's httpd set QUERY_STRING for POST and
GET methods. Your suggestion is a good improvement and does follow
http better than my implementation.

> I'm no expert, but as I understood it, shouldn't it be ...
>
> if os.environ['REQUEST_METHOD'] == 'POST':
> self.qs = sys.stdin.read(int(os.environ['CONTENT_LENGTH']))
> else:
> self.qs = os.environ['QUERY_STRING']

This is better accept int() should be string.atoi()

Thanks for the suggestion. I've also changed the name of my script
to cgi.py.

Michael

--------------------------cgi.py------------------------------------
# A class for wrapping the WWW Forms Common Gateway Interface (CGI)
# Michael McLay, NIST mclay@eeel.nist.gov 6/14/94

import string
import regsub
import sys
import os
import string

# class FormContent parses the name/value pairs that are passed to a
# server's CGI by GET, POST, or PUT methods by when a WWW FORM is used.
# several access methods to FormContent's dictionary have been added
# for convenience.

# The FormContent constructor creates a dictionary from the name/value pairs
# passed through the CGI interface.

class FormContent:
def __init__(self):
if os.environ['REQUEST_METHOD'] == 'POST':
self.qs = sys.stdin.read(string.atoi(
os.environ['CONTENT_LENGTH']))

else:
self.qs = os.environ['QUERY_STRING']

name_value_pairs = string.splitfields(self.qs, '&')
self.t = {}
for name_value in name_value_pairs:

nv = string.splitfields(name_value, '=')
name = nv[0]
value = nv[1]

#Decode all escaped characters and save values
#in lists which are indexed in a dictionary by
#the name. Ignore blank pairs with blank values
if len(value):
value = regsub.gsub('\+',' ',value)
splits = string.splitfields(value,'%')
value = splits[0]
for i in splits[1:]:
nibble = ord(i[0])
if nibble >= 65: digit = nibble - 55
else: digit = nibble - 48
digit = digit << 4
nibble = ord(i[1])
if nibble >= 65:
digit = digit + nibble - 55
else: digit = digit + nibble - 48
if len(i) > 2:
value = value+chr(digit)+i[2:]
else: value = value+chr(digit)

if self.t.has_key (name):
lo = self.t[name]
lo.append(value)
else:
li = [value]
self.t[name] = li

def pars(self):
return self.t
def keys(self):
return self.t.keys()
def has_key(self, key):
return self.t.has_key(key)
def values(self,key):
if self.t.has_key(key):return self.t[key]
else: return None
def indexed_value(self,key, location):
if self.t.has_key(key):
if len (self.t[key]) > location:
return self.t[key][location]
else: return None
else: return None
def value(self,key):
if self.t.has_key(key):return self.t[key][0]
else: return None
def length(self,key):
return len (self.t[key])
def stripped(self,key):
if self.t.has_key(key):return string.strip(self.t[key][0])
else: return None

def print_header(str):
print 'Content-type: text/html\n\n'
print '<HEADER>\n<TITLE>' + str + '</TITLE>\n</HEADER>\n'

def print_title(str):
print "<H1>" +str+"</H1>\n"

def test():
gs = FormContent()
print gs.values('uid')

#test()