Commits

Anonymous committed 8cc270e

Fixed #13007 -- Made cookie parsing resilent to the presence of cookies with invalid characters in their names. Thanks Warlax for the report, Ubercore for his work on a fix and Jannis and Luke for review and guidance.

Comments (0)

Files changed (2)

django/http/__init__.py

 _morsel_supports_httponly = Cookie.Morsel._reserved.has_key('httponly')
 # Some versions of Python 2.7 and later won't need this encoding bug fix:
 _cookie_encodes_correctly = Cookie.SimpleCookie().value_encode(';') == (';', '"\\073"')
+# See ticket #13007, http://bugs.python.org/issue2193 and http://trac.edgewall.org/ticket/2256
+_tc = Cookie.SimpleCookie()
+_tc.load('f:oo')
+_cookie_allows_colon_in_names = 'Set-Cookie: f:oo=' in _tc.output()
 
-if _morsel_supports_httponly and _cookie_encodes_correctly:
+if _morsel_supports_httponly and _cookie_encodes_correctly and _cookie_allows_colon_in_names:
     SimpleCookie = Cookie.SimpleCookie
 else:
     if not _morsel_supports_httponly:
 
                 return val, encoded
 
+        if not _cookie_allows_colon_in_names:
+            def load(self, rawdata, ignore_parse_errors=False):
+                if ignore_parse_errors:
+                    self.bad_cookies = []
+                    self._BaseCookie__set = self._loose_set
+                super(SimpleCookie, self).load(rawdata)
+                if ignore_parse_errors:
+                    self._BaseCookie__set = self._strict_set
+                    for key in self.bad_cookies:
+                        del self[key]
+
+            _strict_set = Cookie.BaseCookie._BaseCookie__set
+
+            def _loose_set(self, key, real_value, coded_value):
+                try:
+                    self._strict_set(key, real_value, coded_value)
+                except Cookie.CookieError:
+                    self.bad_cookies.append(key)
+                    dict.__setitem__(self, key, None)
+
+
 class CompatCookie(SimpleCookie):
     def __init__(self, *args, **kwargs):
         super(CompatCookie, self).__init__(*args, **kwargs)
     if not isinstance(cookie, Cookie.BaseCookie):
         try:
             c = SimpleCookie()
-            c.load(cookie)
+            c.load(cookie, ignore_parse_errors=True)
         except Cookie.CookieError:
             # Invalid cookie
             return {}

tests/regressiontests/httpwrappers/tests.py

 import copy
 import pickle
 
-from django.http import QueryDict, HttpResponse, SimpleCookie, BadHeaderError
+from django.http import (QueryDict, HttpResponse, SimpleCookie, BadHeaderError,
+        parse_cookie)
 from django.utils import unittest
 
 class QueryDictTests(unittest.TestCase):
         c2 = SimpleCookie()
         c2.load(c.output())
         self.assertEqual(c['test'].value, c2['test'].value)
+
+    def test_nonstandard_keys(self):
+        """
+        Test that a single non-standard cookie name doesn't affect all cookies. Ticket #13007.
+        """
+        self.assertTrue('good_cookie' in parse_cookie('good_cookie=yes;bad:cookie=yes').keys())