| """ |
| 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)) |
| |