Hi, I'd like to revive the discussion about autoescape (note that it is *not* on by default). I have brought the patches up to date (see the notes in the ticket, #2359), and I'm starting to use this now in my own projects (with the exception of the admin patch which I have no use for). I can only report that it works great--thanks, Malcolm!
It currently lacks newforms support, but I don't expect any problems with it. You basically have to wrap mark_safe around the strings that represent rendered html code. newforms are only a bit moving around too fast to get proper hold of ;-) --> http://code.djangoproject.com/ticket/2359 Cheers, Michael Malcolm Tredinnick: > I have put an initial version of the auto-escaping patch I mentioned > yesterday into ticket #2359. I'll briefly describe what it does below. > The patch includes changes to the core and a test suite for the > auto-escaping changes (which is about half the patch). > > My reason for posting this first pass is that there are a few issues > that have come up that I would like to get some consensus on now, rather > than after I have ported the rest of the core over to use this stuff. If > I need to change some things, this is the easiest time to do it. There > is no documentation patch in this pass because, again, I don't really > feel like having to re-edit practically the whole doc change if we > decide to rename some things. This email acts as a documentation proxy > for the moment. > > The whole implementation is very close to Simon Willison's original > proposal [1]. With one exception, I have only modified it where there > were technical requirements to do so. I'm going to assume familiarity > with that throughout. His proposal really is very good and it seems to > meet all the sensible requirements brought up in the three threads > listed at the bottom of that page (the two older threads are probably > more informative than the most recent one, for those wanting to get up > to speed here). > > [1] http://code.djangoproject.com/wiki/AutoEscaping > > A summary of the points I'd like opinions on is at the end of the email. > > What does this add? > ------------------- > (1) An "autoescape" template tag that turns automatic escaping on or off > throughout its scope. > > (2) A "noescape" filter that marks its result as safe for use without > further escaping (see the description of "safe strings" below). > > (3) SafeContext and SafeRequestContext classes that act like Context and > RequestContext, except that they automatically enable auto-escaping in > the templates they are applied to (you can also set context.autoescape > on any Context-derived instance, just as in Simon's proposal). > > (4) A "mark_safe()" method to mark strings as not requiring further > escaping. > > How does it work? > ----------------- > When a variable is evaluated in a context in a template, it is > considered to be either "safe" or not (Simon used the term "escaped", > but that seemed less universally true than "safe"). By default, strings > are not marked as safe. > > When automatic escaping is enabled, either because {% autoescape on %} > is in effect, or because a SafeContext class is being used, all strings > that are not marked as safe are escaped at rendering time (here, > "escaped" means "conservative HTML escaping": &, <, >, " and ' are > converted to entities always). > > Any string marked as safe (or passed through the "noescape" filter) is > not automatically escaped. > > When automatic escaping is disabled in the template, all variable > results are output without further escaping, unless the "escape" filter > is applied to them (this is the same behaviour as currently in Django). > > Because some filters are designed to return raw markup, the mark_safe() > function exists so that the returned strings can be designated as safe. > For example, {{ var|markdown }} returns raw HTML and the result is not > subject to any further auto-escaping. > > Some filters (e.g. unordered_list) wrap HTML around raw content. If > auto-escaping is enabled, these filters will escape the content before > wrapping it in the HTML tags (the returned result is a safe string in > all cases). So such filters are auto-escaping-aware. > > Filters that accept text strings as input and return text strings are > marked (with the "is_safe" attribute) as to whether or not they return a > safe string whenever they are passed a safe string as input. This has > the effect of preserving "safeness" for those filters. Note that this > attribute is a *guarantee* of preserving safeness, so a filter like > "cut" has is_safe = False: {{ var|cut:"&" }} could turn an escaped > string into a monster. If a safe string is passed into a filter that is > not marked as safe and auto-escaping is enabled, the resulting string > will be escaped. If the is_safe attribute is not attached to a function, > it is assumed to be not safe. > > Because of the is_safe attribute, it will be possible to change the > automatically generated documentation in the admin interface to annotate > each filter with it's "safeness" guarantee. > > The "noescape" filter acts as a way to annotate the result of a filter > chain as safe. So, although "cut" is not a safe filter, we know that > cut:"x" is safe (it can't harm our HTML-escaped strings) and thus > {{ var|cut:"x"|noescape }} will prevent further escaping of the result, > even in auto-escaping-enabled situations. The "noescape" filter does > nothing except mark the result as safe -- the string output is identical > to the input. > > Is it backwards compatible? > --------------------------- > Mostly. > > Auto-escaping is not turned on by default (Adrian made a statement in > [2] and I'm going with that preference at the moment). If you pass a > normal Context or Context-derived class into a template and do not use > the autoescape tag, it will be very close to what happens today. > > [2] > http://groups.google.com/group/django-developers/msg/5a57f37667e1e941? > > > Four filters had their behaviour slightly changed. > > Three of these are: linebreaks, linebreaksbr and linenumbers. All three > now respect the current auto-escaping setting on their input content > (before applying breaks or numbering). Previously, linenumbers would > always escape and linebreaks and linebreaksbr would never escape. So, > the main change for somebody not enabling auto-escaping here is that the > linenumbers filter will not escape the output any longer. > > The fourth filter is "escape". To make forward porting easier and so > that template designers do not have to feel restricted in their use of > the escape filter, I implemented it so that applying "escape" to a safe > string has no effect. Since "escape" itself makes the result safe, > applying escape multiple times in a chain has the same effect as > applying it exactly once. > > Previously (var = "&"): {{ var|escape|escape }} => &amp; > Now: {{ var|escape|escape }} => & > > This particular case of chaining "escape" is obviously not common (I > would hope). > > All of the default filters (template/defaultfilters.py) and the markup > filters have been ported in this patch. I have not done anything else > under contrib/ or the i18n filters. > > Points to note > -------------- > (1) Because "is_safe" has to be valid for all arguments, the "pluralize" > filter is not safe at the moment. The bizarre {{ var|puralize:"&" }} is > an example of the problem case. I'm thinking of fixing this so that we > check for unsafe characters in the argument(s) and then return safe > strings on safe input and no unsafe args. > > (2) Because of the way "noescape" works, it was not really possible to > make {% filter noescape %} work in an auto-escaping block (the contents > were escaped long before the filter tag was applied). Fortunately, this > particular filter tag construct is equivalent to {% autoescape off %}, > so there's no functionality loss. A TemplateSyntaxError is raised if the > illegal construct is used. > > (3) Filters that take non-string arguments (e.g. "join") or return > something other than a string (e.g. "length") have is_safe = False. This > is convention more than requirement, but it makes things explicit. > > Performance impact > ------------------- > Obviously we are doing a little bit more work here, even in the > non-auto-escaping paths (just testing what the auto-escape setting is, > for example). As far as I can work out, the performance impact is very > minor, but I do not have a really good performance test suite for this > at the moment. > > One simple test: running the tests/othertests/template.py file 100 times > takes 21.0436 seconds before these changes and 21.1674 seconds > afterwards -- averaged over five runs on my desktop machine. This tests > the "no escaping" path. That's a slowdown 0.6% (and that was almost > within the "noise" of the various runs). These tests aren't particularly > comprehensive, but they do test the templating code a reasonable amount > (although not the filters very much at all). > > What are the issues at the moment? > ---------------------------------- > Now we get to the things I want to sort out before going much further. > > (1) Any violent (or even just passionate) objections to using terms like > "safe" and mark_safe()? > - Should we use Simon's original proposal of escaped and > mark_escaped()? I feel "safe" is a bit more consistent with the > behaviour (an opposite-but-similar term to Perl's "tainted"). > > (2) Is the new behaviour of "escape" reasonable (i.e. it does nothing on > safe strings)? > - The only drawback of this is that there is no way to give an > escaped version of a safe string in the templates. That is, > there is no opposite to the "noescape" filter. > > - If we make "escape" apply to safe strings as well, then views > must be very consistent about variables always having the same > "safeness" state. Otherwise, the template would have to escape > sometimes and not escape other times and it has no way of > knowing when. The current implementation lets you whack an > escape filter on there and it will work always. > > - Current behaviour also makes forward porting easier (you don't > have to run around removing all the escape filters in your code > immediately). > > (3) Auto-escaping inherits down through template inclusions. That is, if > you extend a template that has auto-escaping enabled, you get > auto-escaping enabled (obviously the autoescape template tag can control > this). Anybody have a strong reason not to do this? > - Personally, I think this is a no-brainer, but I've been wrong > plenty of times before. > > (4) Should generic views use SafeContext by default? > - I haven't touched this yet, but it's not an insane idea. I > guess most people will divide along the same lines as those > wanting auto-escaping on or off by default. The waverers will be > those favouring consistency over all. I'm not a big enough > generic views user to really have a vote in this one. > > (5) Adrian, Jacob: do you guys still want "off by default"? > - I *really* don't care what the answer is here, but I would > rather not have to change things after porting everything under > contrib/ . > > - For people thinking it's auto-escaping or nothing, {% > autoescape on %} at the beginning of a template (and {% > endautoescape %}) at the end is not a huge imposition. > > Feedback obviously welcome and appreciated. > > Regards, > Malcolm > > > > -- noris network AG - Deutschherrnstraße 15-19 - D-90429 Nürnberg - Tel +49-911-9352-0 - Fax +49-911-9352-100 http://www.noris.de - The IT-Outsourcing Company --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Django developers" group. To post to this group, send email to [email protected] To unsubscribe from this group, send email to [EMAIL PROTECTED] For more options, visit this group at http://groups.google.com/group/django-developers?hl=en -~----------~----~----~----~------~----~------~--~---
