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
Pull Requests:How to create a pull request

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().

According to the ticket's flags, the next step(s) to move this issue forward are:

  • To provide a patch by sending a pull request. Claim the ticket when you start working so that someone else doesn't duplicate effort. Before sending a pull request, review your work against the patch review checklist. Check the "Has patch" flag on the ticket after sending a pull request and include a link to the pull request in the ticket comment when making that update. The usual format is: [https://github.com/django/django/pull/#### PR].

Change History (3)

comment:1 by Tim Graham, 7 years ago

Cc: Claude Paroz added
Summary: Django 2.0 breaks interop with Jinja2 forceescape filterJinja2's forceescape filter doesn't work on Django's safe strings

jinja.filters.do_forceescape() uses markupsafe.escape(). Since str(SafeText) now returns the SafeText, the hasattr(s, '__html__') check in escape() returns True and no escaping happens.

I think it's a legitimate issue as the behavior is certainly unexpected (SafeText with the Django template language's force_escape filter 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.

comment:2 by no, 7 years ago

I agree, it is a bit late in the 2.0 life cycle to revert it; but 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.

Last edited 7 years ago by no (previous) (diff)

comment:3 by Tim Graham, 7 years ago

Component: Template systemUtilities
Triage Stage: UnreviewedAccepted

Generally we don't document bugs in the release notes. :-)

It will be interesting to hear Claude's opinion on this issue.

Note: See TracTickets for help on using tickets.
Back to Top