"""FieldStorage.py
This module defines a subclass of the standard Python cgi.FieldStorage class
with an extra method that will allow a FieldStorage to parse a query string
even in a POST request.
"""
import cgi, os, urllib
class FieldStorage(cgi.FieldStorage):
"""Modified FieldStorage class for POST requests with query strings.
Parameters in the query string which have not been sent via POST are
appended to the field list. This is different from the behavior of
Python versions before 2.6 which completely ignored the query string in
POST request, but it's also different from the behavior of the later Python
versions which append values from the query string to values sent via POST
for parameters with the same name. With other words, our FieldStorage class
overrides the query string parameters with the parameters sent via POST.
As recommended by W3C in section B.2.2 of the HTML 4.01 specification,
we also support use of ';' in place of '&' as separator in query strings.
"""
def __init__(self, fp=None, headers=None, outerboundary='',
environ=os.environ, keep_blank_values=False, strict_parsing=False):
method = environ.get('REQUEST_METHOD', 'GET').upper()
qs_on_post = method not in ('GET', 'HEAD') and environ.get(
'QUERY_STRING', None) or None
if qs_on_post:
environ['QUERY_STRING'] = ''
try:
cgi.FieldStorage.__init__(self, fp, headers, outerboundary,
environ, keep_blank_values, strict_parsing)
finally:
if qs_on_post:
environ['QUERY_STRING'] = qs_on_post
if qs_on_post:
self.add_qs(qs_on_post)
def add_qs(self, qs):
"""Add all non-existing parameters from the given query string."""
r = {}
for name_value in qs.split('&'):
for name_value in name_value.split(';'):
nv = name_value.split('=', 2)
if len(nv) != 2:
if self.strict_parsing:
raise ValueError('bad query field: %r' % (name_value,))
continue
name = urllib.unquote(nv[0].replace('+', ' '))
value = urllib.unquote(nv[1].replace('+', ' '))
if len(value) or self.keep_blank_values:
if name in r:
r[name].append(value)
else:
r[name] = [value]
if self.list is None:
self.list = []
for key in r:
if key not in self:
for value in r[key]:
self.list.append(cgi.MiniFieldStorage(key, value))