Opened 7 years ago
Last modified 7 years ago
#29602 new Bug
Jinja2's forceescape filter doesn't work on Django's safe strings
| Reported by: | no | Owned by: | nobody |
|---|---|---|---|
| Component: | Utilities | Version: | 2.0 |
| Severity: | Normal | Keywords: | |
| Cc: | Claude Paroz | Triage Stage: | Accepted |
| Has patch: | no | Needs documentation: | no |
| Needs tests: | no | Patch needs improvement: | no |
| Easy pickings: | no | UI/UX: | no |
Description
Not sure if this is a Django bug, jinja bug, or something I need to change for upgrading to Django 2.0, but since it was a Django commit causes it, I'm reporting here first.
I recently upgraded to Django 2.0, and shortly after had a complaint from one of our users about a page not displaying correctly. I tracked down the issue to a usage of Jinja's forceescape filter.
My usage is that we're displaying a preview of an email that will be sent out, and we do this by using the srcdoc attribute of iframe, so our code looks like:
<iframe srcdoc="{{ rendered_email | forceescape }}"></iframe>
The rendered_email variable is from a call to get_template(template_name).render(ctx), which returns a SafeString object. Which makes sense since a rendered template should be html. And since I want to display the email inside of html again, it needs to be re-escape, logically with the forceescape filter.
However, a change from this ticket/this commit causes the forceescape filter to fail on the jinja side. forcescape calls str() on it's argument to remove the "safety", then re-escapes it, however, the aforementioned commit allow SafeString to bypass the assumption that jinja makes when calling str().
Change History (3)
comment:1 by , 7 years ago
| Cc: | added |
|---|---|
| Summary: | Django 2.0 breaks interop with Jinja2 forceescape filter → Jinja2's forceescape filter doesn't work on Django's safe strings |
comment:2 by , 7 years ago
I agree, it is a bit late in the 2.0 life cycle to revert it; a note in the 2.0 change log would be very helpful for anyone else that's doing a late upgrade like I was (while upgrading I was checking everything in the release notes against our code base). I also assume it's too late in the 2.1 release cycle to fix in some way?
As a work around, I should either be able to use django's force_escape, or manually wrap the variable in Jinja's MarkUp() function so that it works with Jinja's forceescape.
comment:3 by , 7 years ago
| Component: | Template system → Utilities |
|---|---|
| Triage Stage: | Unreviewed → Accepted |
Generally we don't document bugs in the release notes. :-)
It will be interesting to hear Claude's opinion on this issue.
jinja.filters.do_forceescape() uses markupsafe.escape(). Since
str(SafeText)now returns theSafeText, thehasattr(s, '__html__')check inescape()returns True and no escaping happens.I think it's a legitimate issue as the behavior is certainly unexpected (
SafeTextwith the Django template language'sforce_escapefilter works as you would expect), however, I'm not sure what the best way forward is as it's a bit late in the Django 2.0 lifecycle to revert the original change.