Index: django/core/cache/__init__.py
===================================================================
--- django/core/cache/__init__.py	(revision 6668)
+++ django/core/cache/__init__.py	(working copy)
@@ -15,9 +15,10 @@
 See docs/cache.txt for information on the public API.
 """
 
-from cgi import parse_qsl
 from django.conf import settings
 from django.core.cache.backends.base import InvalidCacheBackendError
+# For bugfixes not in Python < 2.3.5
+from django.utils._cgi import parse_qsl
 
 BACKENDS = {
     # name for use in settings file --> name of module in "backends" directory
@@ -41,7 +42,7 @@
     host = rest[2:]
     qpos = rest.find('?')
     if qpos != -1:
-        params = dict(parse_qsl(rest[qpos+1:]))
+        params = dict(parse_qsl(rest[qpos+1:], True)) # keep_blank_values=True
         host = rest[2:qpos]
     else:
         params = {}
Index: django/http/__init__.py
===================================================================
--- django/http/__init__.py	(revision 6668)
+++ django/http/__init__.py	(working copy)
@@ -13,7 +13,8 @@
     # The mod_python version is more efficient, so try importing it first.
     from mod_python.util import parse_qsl
 except ImportError:
-    from cgi import parse_qsl
+    # For bugfixes not in Python < 2.3.5
+    from django.utils._cgi import parse_qsl
 
 class Http404(Exception):
     pass
@@ -100,7 +101,8 @@
 def parse_file_upload(header_dict, post_data):
     "Returns a tuple of (POST QueryDict, FILES MultiValueDict)"
     import email, email.Message
-    from cgi import parse_header
+    # For bugfixes not in Python < 2.3.5
+    from django.utils._cgi import parse_header
     raw_message = '\r\n'.join(['%s:%s' % pair for pair in header_dict.items()])
     raw_message += '\r\n\r\n' + post_data
     msg = email.message_from_string(raw_message)
Index: django/utils/_cgi.py
===================================================================
--- django/utils/_cgi.py	(revision 0)
+++ django/utils/_cgi.py	(revision 0)
@@ -0,0 +1,104 @@
+"""
+Provides updated (to 2.5.1) versions of the standard cgi.parse_qs,
+cgi.parse_qsl and cgi.parse_header functions for Python < 2.3.5.
+The last two have had bugfixes since then.
+"""
+
+# Relevant revisions from Python svn:
+#
+# 34965 = Python 2.3.3
+# 35532   Change parse_qsl() to accept control-name's with no equal sign
+#         (e.g., "name") when keep_blank_values is true.
+# 35974 = Python 2.3.4
+# 36582   Don't return spurious empty fields if 'keep_empty_values' is True.
+# 36995   Let cgi.parse_header() properly unquote headers.
+# 37906 = Python 2.4
+# 38447 = Python 2.3.5
+
+import urllib
+
+def parse_qs(qs, keep_blank_values=0, strict_parsing=0):
+    """Parse a query given as a string argument.
+
+        Arguments:
+
+        qs: URL-encoded query string to be parsed
+
+        keep_blank_values: flag indicating whether blank values in
+            URL encoded queries should be treated as blank strings.
+            A true value indicates that blanks should be retained as
+            blank strings.  The default false value indicates that
+            blank values are to be ignored and treated as if they were
+            not included.
+
+        strict_parsing: flag indicating what to do with parsing errors.
+            If false (the default), errors are silently ignored.
+            If true, errors raise a ValueError exception.
+    """
+    dict = {}
+    for name, value in parse_qsl(qs, keep_blank_values, strict_parsing):
+        if name in dict:
+            dict[name].append(value)
+        else:
+            dict[name] = [value]
+    return dict
+
+def parse_qsl(qs, keep_blank_values=0, strict_parsing=0):
+    """Parse a query given as a string argument.
+
+    Arguments:
+
+    qs: URL-encoded query string to be parsed
+
+    keep_blank_values: flag indicating whether blank values in
+        URL encoded queries should be treated as blank strings.  A
+        true value indicates that blanks should be retained as blank
+        strings.  The default false value indicates that blank values
+        are to be ignored and treated as if they were  not included.
+
+    strict_parsing: flag indicating what to do with parsing errors. If
+        false (the default), errors are silently ignored. If true,
+        errors raise a ValueError exception.
+
+    Returns a list, as G-d intended.
+    """
+    pairs = [s2 for s1 in qs.split('&') for s2 in s1.split(';')]
+    r = []
+    for name_value in pairs:
+        if not name_value and not strict_parsing:
+            continue
+        nv = name_value.split('=', 1)
+        if len(nv) != 2:
+            if strict_parsing:
+                raise ValueError, "bad query field: %r" % (name_value,)
+            # Handle case of a control-name with no equal sign
+            if keep_blank_values:
+                nv.append('')
+            else:
+                continue
+        if len(nv[1]) or keep_blank_values:
+            name = urllib.unquote(nv[0].replace('+', ' '))
+            value = urllib.unquote(nv[1].replace('+', ' '))
+            r.append((name, value))
+
+    return r
+
+def parse_header(line):
+    """Parse a Content-type like header.
+
+    Return the main content-type and a dictionary of options.
+
+    """
+    plist = [x.strip() for x in line.split(';')]
+    key = plist.pop(0).lower()
+    pdict = {}
+    for p in plist:
+        i = p.find('=')
+        if i >= 0:
+            name = p[:i].strip().lower()
+            value = p[i+1:].strip()
+            if len(value) >= 2 and value[0] == value[-1] == '"':
+                value = value[1:-1]
+                value = value.replace('\\\\', '\\').replace('\\"', '"')
+            pdict[name] = value
+    return key, pdict
Index: django/utils/simplejson/jsonfilter.py
===================================================================
--- django/utils/simplejson/jsonfilter.py	(revision 6668)
+++ django/utils/simplejson/jsonfilter.py	(working copy)
@@ -1,5 +1,6 @@
 from django.utils import simplejson
-import cgi
+# For bugfixes not in Python < 2.3.5
+from django.utils._cgi import parse_qs
 
 class JSONFilter(object):
     def __init__(self, app, mime_type='text/x-json'):
@@ -19,7 +20,8 @@
                 data = environ['wsgi.input'].read(*map(int, args))
                 environ['jsonfilter.json'] = simplejson.loads(data)
         res = simplejson.dumps(self.app(environ, json_start_response))
-        jsonp = cgi.parse_qs(environ.get('QUERY_STRING', '')).get('jsonp')
+        # In the line below: keep_blank_values=True
+        jsonp = parse_qs(environ.get('QUERY_STRING', ''), True).get('jsonp')
         if jsonp:
             content_type = 'text/javascript'
             res = ''.join(jsonp + ['(', res, ')'])
