cookie.py 3.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. from __future__ import unicode_literals
  2. from django.utils.encoding import force_str
  3. from django.utils import six
  4. from django.utils.six.moves import http_cookies
  5. # Some versions of Python 2.7 and later won't need this encoding bug fix:
  6. _cookie_encodes_correctly = http_cookies.SimpleCookie().value_encode(';') == (';', '"\\073"')
  7. # See ticket #13007, http://bugs.python.org/issue2193 and http://trac.edgewall.org/ticket/2256
  8. _tc = http_cookies.SimpleCookie()
  9. try:
  10. _tc.load(str('foo:bar=1'))
  11. _cookie_allows_colon_in_names = True
  12. except http_cookies.CookieError:
  13. _cookie_allows_colon_in_names = False
  14. if _cookie_encodes_correctly and _cookie_allows_colon_in_names:
  15. SimpleCookie = http_cookies.SimpleCookie
  16. else:
  17. Morsel = http_cookies.Morsel
  18. class SimpleCookie(http_cookies.SimpleCookie):
  19. if not _cookie_encodes_correctly:
  20. def value_encode(self, val):
  21. # Some browsers do not support quoted-string from RFC 2109,
  22. # including some versions of Safari and Internet Explorer.
  23. # These browsers split on ';', and some versions of Safari
  24. # are known to split on ', '. Therefore, we encode ';' and ','
  25. # SimpleCookie already does the hard work of encoding and decoding.
  26. # It uses octal sequences like '\\012' for newline etc.
  27. # and non-ASCII chars. We just make use of this mechanism, to
  28. # avoid introducing two encoding schemes which would be confusing
  29. # and especially awkward for javascript.
  30. # NB, contrary to Python docs, value_encode returns a tuple containing
  31. # (real val, encoded_val)
  32. val, encoded = super(SimpleCookie, self).value_encode(val)
  33. encoded = encoded.replace(";", "\\073").replace(",", "\\054")
  34. # If encoded now contains any quoted chars, we need double quotes
  35. # around the whole string.
  36. if "\\" in encoded and not encoded.startswith('"'):
  37. encoded = '"' + encoded + '"'
  38. return val, encoded
  39. if not _cookie_allows_colon_in_names:
  40. def load(self, rawdata):
  41. self.bad_cookies = set()
  42. if six.PY2 and isinstance(rawdata, six.text_type):
  43. rawdata = force_str(rawdata)
  44. super(SimpleCookie, self).load(rawdata)
  45. for key in self.bad_cookies:
  46. del self[key]
  47. # override private __set() method:
  48. # (needed for using our Morsel, and for laxness with CookieError
  49. def _BaseCookie__set(self, key, real_value, coded_value):
  50. key = force_str(key)
  51. try:
  52. M = self.get(key, Morsel())
  53. M.set(key, real_value, coded_value)
  54. dict.__setitem__(self, key, M)
  55. except http_cookies.CookieError:
  56. if not hasattr(self, 'bad_cookies'):
  57. self.bad_cookies = set()
  58. self.bad_cookies.add(key)
  59. dict.__setitem__(self, key, http_cookies.Morsel())
  60. def parse_cookie(cookie):
  61. if cookie == '':
  62. return {}
  63. if not isinstance(cookie, http_cookies.BaseCookie):
  64. try:
  65. c = SimpleCookie()
  66. c.load(cookie)
  67. except http_cookies.CookieError:
  68. # Invalid cookie
  69. return {}
  70. else:
  71. c = cookie
  72. cookiedict = {}
  73. for key in c.keys():
  74. cookiedict[key] = c.get(key).value
  75. return cookiedict