You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

safestring.py 4.3 KiB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. """
  2. Functions for working with "safe strings": strings that can be displayed safely
  3. without further escaping in HTML. Marking something as a "safe string" means
  4. that the producer of the string has already turned characters that should not
  5. be interpreted by the HTML engine (e.g. '<') into the appropriate entities.
  6. """
  7. from django.utils import six
  8. from django.utils.functional import Promise, curry
  9. class EscapeData(object):
  10. pass
  11. class EscapeBytes(bytes, EscapeData):
  12. """
  13. A byte string that should be HTML-escaped when output.
  14. """
  15. pass
  16. class EscapeText(six.text_type, EscapeData):
  17. """
  18. A unicode string object that should be HTML-escaped when output.
  19. """
  20. pass
  21. if six.PY3:
  22. EscapeString = EscapeText
  23. else:
  24. EscapeString = EscapeBytes
  25. # backwards compatibility for Python 2
  26. EscapeUnicode = EscapeText
  27. class SafeData(object):
  28. def __html__(self):
  29. """
  30. Returns the html representation of a string for interoperability.
  31. This allows other template engines to understand Django's SafeData.
  32. """
  33. return self
  34. class SafeBytes(bytes, SafeData):
  35. """
  36. A bytes subclass that has been specifically marked as "safe" (requires no
  37. further escaping) for HTML output purposes.
  38. """
  39. def __add__(self, rhs):
  40. """
  41. Concatenating a safe byte string with another safe byte string or safe
  42. unicode string is safe. Otherwise, the result is no longer safe.
  43. """
  44. t = super(SafeBytes, self).__add__(rhs)
  45. if isinstance(rhs, SafeText):
  46. return SafeText(t)
  47. elif isinstance(rhs, SafeBytes):
  48. return SafeBytes(t)
  49. return t
  50. def _proxy_method(self, *args, **kwargs):
  51. """
  52. Wrap a call to a normal unicode method up so that we return safe
  53. results. The method that is being wrapped is passed in the 'method'
  54. argument.
  55. """
  56. method = kwargs.pop('method')
  57. data = method(self, *args, **kwargs)
  58. if isinstance(data, bytes):
  59. return SafeBytes(data)
  60. else:
  61. return SafeText(data)
  62. decode = curry(_proxy_method, method=bytes.decode)
  63. class SafeText(six.text_type, SafeData):
  64. """
  65. A unicode (Python 2) / str (Python 3) subclass that has been specifically
  66. marked as "safe" for HTML output purposes.
  67. """
  68. def __add__(self, rhs):
  69. """
  70. Concatenating a safe unicode string with another safe byte string or
  71. safe unicode string is safe. Otherwise, the result is no longer safe.
  72. """
  73. t = super(SafeText, self).__add__(rhs)
  74. if isinstance(rhs, SafeData):
  75. return SafeText(t)
  76. return t
  77. def _proxy_method(self, *args, **kwargs):
  78. """
  79. Wrap a call to a normal unicode method up so that we return safe
  80. results. The method that is being wrapped is passed in the 'method'
  81. argument.
  82. """
  83. method = kwargs.pop('method')
  84. data = method(self, *args, **kwargs)
  85. if isinstance(data, bytes):
  86. return SafeBytes(data)
  87. else:
  88. return SafeText(data)
  89. encode = curry(_proxy_method, method=six.text_type.encode)
  90. if six.PY3:
  91. SafeString = SafeText
  92. else:
  93. SafeString = SafeBytes
  94. # backwards compatibility for Python 2
  95. SafeUnicode = SafeText
  96. def mark_safe(s):
  97. """
  98. Explicitly mark a string as safe for (HTML) output purposes. The returned
  99. object can be used everywhere a string or unicode object is appropriate.
  100. Can be called multiple times on a single string.
  101. """
  102. if hasattr(s, '__html__'):
  103. return s
  104. if isinstance(s, bytes) or (isinstance(s, Promise) and s._delegate_bytes):
  105. return SafeBytes(s)
  106. if isinstance(s, (six.text_type, Promise)):
  107. return SafeText(s)
  108. return SafeString(str(s))
  109. def mark_for_escaping(s):
  110. """
  111. Explicitly mark a string as requiring HTML escaping upon output. Has no
  112. effect on SafeData subclasses.
  113. Can be called multiple times on a single string (the resulting escaping is
  114. only applied once).
  115. """
  116. if hasattr(s, '__html__') or isinstance(s, EscapeData):
  117. return s
  118. if isinstance(s, bytes) or (isinstance(s, Promise) and s._delegate_bytes):
  119. return EscapeBytes(s)
  120. if isinstance(s, (six.text_type, Promise)):
  121. return EscapeText(s)
  122. return EscapeString(str(s))