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.
119 lines
3.7 KiB
119 lines
3.7 KiB
""" |
|
Functions for working with "safe strings": strings that can be displayed safely |
|
without further escaping in HTML. Marking something as a "safe string" means |
|
that the producer of the string has already turned characters that should not |
|
be interpreted by the HTML engine (e.g. '<') into the appropriate entities. |
|
""" |
|
from django.utils.functional import curry, Promise |
|
|
|
class EscapeData(object): |
|
pass |
|
|
|
class EscapeString(str, EscapeData): |
|
""" |
|
A string that should be HTML-escaped when output. |
|
""" |
|
pass |
|
|
|
class EscapeUnicode(unicode, EscapeData): |
|
""" |
|
A unicode object that should be HTML-escaped when output. |
|
""" |
|
pass |
|
|
|
class SafeData(object): |
|
pass |
|
|
|
class SafeString(str, SafeData): |
|
""" |
|
A string subclass that has been specifically marked as "safe" (requires no |
|
further escaping) for HTML output purposes. |
|
""" |
|
def __add__(self, rhs): |
|
""" |
|
Concatenating a safe string with another safe string or safe unicode |
|
object is safe. Otherwise, the result is no longer safe. |
|
""" |
|
t = super(SafeString, self).__add__(rhs) |
|
if isinstance(rhs, SafeUnicode): |
|
return SafeUnicode(t) |
|
elif isinstance(rhs, SafeString): |
|
return SafeString(t) |
|
return t |
|
|
|
def _proxy_method(self, *args, **kwargs): |
|
""" |
|
Wrap a call to a normal unicode method up so that we return safe |
|
results. The method that is being wrapped is passed in the 'method' |
|
argument. |
|
""" |
|
method = kwargs.pop('method') |
|
data = method(self, *args, **kwargs) |
|
if isinstance(data, str): |
|
return SafeString(data) |
|
else: |
|
return SafeUnicode(data) |
|
|
|
decode = curry(_proxy_method, method = str.decode) |
|
|
|
class SafeUnicode(unicode, SafeData): |
|
""" |
|
A unicode subclass that has been specifically marked as "safe" for HTML |
|
output purposes. |
|
""" |
|
def __add__(self, rhs): |
|
""" |
|
Concatenating a safe unicode object with another safe string or safe |
|
unicode object is safe. Otherwise, the result is no longer safe. |
|
""" |
|
t = super(SafeUnicode, self).__add__(rhs) |
|
if isinstance(rhs, SafeData): |
|
return SafeUnicode(t) |
|
return t |
|
|
|
def _proxy_method(self, *args, **kwargs): |
|
""" |
|
Wrap a call to a normal unicode method up so that we return safe |
|
results. The method that is being wrapped is passed in the 'method' |
|
argument. |
|
""" |
|
method = kwargs.pop('method') |
|
data = method(self, *args, **kwargs) |
|
if isinstance(data, str): |
|
return SafeString(data) |
|
else: |
|
return SafeUnicode(data) |
|
|
|
encode = curry(_proxy_method, method = unicode.encode) |
|
|
|
def mark_safe(s): |
|
""" |
|
Explicitly mark a string as safe for (HTML) output purposes. The returned |
|
object can be used everywhere a string or unicode object is appropriate. |
|
|
|
Can be called multiple times on a single string. |
|
""" |
|
if isinstance(s, SafeData): |
|
return s |
|
if isinstance(s, str) or (isinstance(s, Promise) and s._delegate_str): |
|
return SafeString(s) |
|
if isinstance(s, (unicode, Promise)): |
|
return SafeUnicode(s) |
|
return SafeString(str(s)) |
|
|
|
def mark_for_escaping(s): |
|
""" |
|
Explicitly mark a string as requiring HTML escaping upon output. Has no |
|
effect on SafeData subclasses. |
|
|
|
Can be called multiple times on a single string (the resulting escaping is |
|
only applied once). |
|
""" |
|
if isinstance(s, (SafeData, EscapeData)): |
|
return s |
|
if isinstance(s, str) or (isinstance(s, Promise) and s._delegate_str): |
|
return EscapeString(s) |
|
if isinstance(s, (unicode, Promise)): |
|
return EscapeUnicode(s) |
|
return EscapeString(str(s)) |
|
|
|
|