Conversion of http escape characters

Michael McLay (mclay@eeel.nist.gov)
Tue, 14 Jun 94 12:40:36 EDT

N.G.Smith writes:
> I am a python beginner, so go easy.
>
> Is there a neat canned solution to the problem of converting the escaped
> characters used in http back to normal characters?
>
> e.g. The string 'foo%41bar' -> 'fooAbar' (0x41 == ASCII letter 'A')
>
> The perl solution is something like this...
>
> $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
>
> ... but python's hex() has the opposite effect to that required, i.e. it
> converts a number to a hex string, rather than converting a hex string to
> a number.

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

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

# class FormContent parses the name/value pairs that are returned
# to a server's CGI by GET, POST, or PUT methods of a WWW FORM
# FormContent includes access methods for dictionary entries for each name.
#
import string
import regsub
import sys
import os

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"

# The constructor for FormContent uses the content of a form to create a
# dictionary of name/value pairs.

class FormContent:
def __init__(self):
if os.environ['QUERY_STRING'] != '':
self.qs = os.environ['QUERY_STRING']
else:
self.qs = sys.stdin.readline()

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 test():
gs = FormContent()
print gs.values('uid')

#test()