Ticket #2359: 01-core-changes.diff
| File 01-core-changes.diff, 60.8 kB (added by mtredinnick, 2 years ago) |
|---|
-
a/django/forms/__init__.py
old new 1 1 from django.core import validators 2 2 from django.core.exceptions import PermissionDenied 3 3 from django.utils.html import escape 4 from django.utils.safestring import mark_safe 4 5 from django.conf import settings 5 6 from django.utils.translation import gettext, gettext_lazy, ngettext 6 7 … … 175 176 176 177 def html_error_list(self): 177 178 if self.errors(): 178 return '<ul class="errorlist"><li>%s</li></ul>' % '</li><li>'.join([escape(e) for e in self.errors()])179 return mark_safe('<ul class="errorlist"><li>%s</li></ul>' % '</li><li>'.join([escape(e) for e in self.errors()])) 179 180 else: 180 return ''181 return mark_safe('') 181 182 182 183 def get_id(self): 183 184 return self.formfield.get_id() … … 209 210 return bool(len(self.errors())) 210 211 211 212 def html_combined_error_list(self): 212 return ''.join([field.html_error_list() for field in self.formfield_dict.values() if hasattr(field, 'errors')])213 return mark_safe(''.join([field.html_error_list() for field in self.formfield_dict.values() if hasattr(field, 'errors')])) 213 214 214 215 class InlineObjectCollection(object): 215 216 "An object that acts like a sparse list of form field collections." … … 393 394 maxlength = 'maxlength="%s" ' % self.maxlength 394 395 if isinstance(data, unicode): 395 396 data = data.encode(settings.DEFAULT_CHARSET) 396 return '<input type="%s" id="%s" class="v%s%s" name="%s" size="%s" value="%s" %s/>' % \397 return mark_safe('<input type="%s" id="%s" class="v%s%s" name="%s" size="%s" value="%s" %s/>' % \ 397 398 (self.input_type, self.get_id(), self.__class__.__name__, self.is_required and ' required' or '', 398 self.field_name, self.length, escape(data), maxlength) 399 self.field_name, self.length, escape(data), maxlength)) 399 400 400 401 def html2python(data): 401 402 return data … … 419 420 data = '' 420 421 if isinstance(data, unicode): 421 422 data = data.encode(settings.DEFAULT_CHARSET) 422 return '<textarea id="%s" class="v%s%s" name="%s" rows="%s" cols="%s">%s</textarea>' % \423 return mark_safe('<textarea id="%s" class="v%s%s" name="%s" rows="%s" cols="%s">%s</textarea>' % \ 423 424 (self.get_id(), self.__class__.__name__, self.is_required and ' required' or '', 424 self.field_name, self.rows, self.cols, escape(data)) 425 self.field_name, self.rows, self.cols, escape(data))) 425 426 426 427 class HiddenField(FormField): 427 428 def __init__(self, field_name, is_required=False, validator_list=None): … … 430 431 self.validator_list = validator_list[:] 431 432 432 433 def render(self, data): 433 return '<input type="hidden" id="%s" name="%s" value="%s" />' % \434 (self.get_id(), self.field_name, escape(data)) 434 return mark_safe('<input type="hidden" id="%s" name="%s" value="%s" />' % \ 435 (self.get_id(), self.field_name, escape(data))) 435 436 436 437 class CheckboxField(FormField): 437 438 def __init__(self, field_name, checked_by_default=False, validator_list=None): … … 445 446 checked_html = '' 446 447 if data or (data is '' and self.checked_by_default): 447 448 checked_html = ' checked="checked"' 448 return '<input type="checkbox" id="%s" class="v%s" name="%s"%s />' % \449 return mark_safe('<input type="checkbox" id="%s" class="v%s" name="%s"%s />' % \ 449 450 (self.get_id(), self.__class__.__name__, 450 self.field_name, checked_html) 451 self.field_name, checked_html)) 451 452 452 453 def html2python(data): 453 454 "Convert value from browser ('on' or '') to a Python boolean" … … 478 479 selected_html = ' selected="selected"' 479 480 output.append(' <option value="%s"%s>%s</option>' % (escape(value), selected_html, escape(display_name))) 480 481 output.append(' </select>') 481 return '\n'.join(output)482 return mark_safe('\n'.join(output)) 482 483 483 484 def isValidChoice(self, data, form): 484 485 str_data = str(data) … … 531 532 output = ['<ul%s>' % (self.ul_class and ' class="%s"' % self.ul_class or '')] 532 533 output.extend(['<li>%s %s</li>' % (d['field'], d['label']) for d in self.datalist]) 533 534 output.append('</ul>') 534 return ''.join(output)535 return mark_safe(''.join(output)) 535 536 def __iter__(self): 536 537 for d in self.datalist: 537 538 yield d … … 546 547 datalist.append({ 547 548 'value': value, 548 549 'name': display_name, 549 'field': '<input type="radio" id="%s" name="%s" value="%s"%s/>' % \550 (self.get_id() + '_' + str(i), self.field_name, value, selected_html) ,551 'label': '<label for="%s">%s</label>' % \550 'field': mark_safe('<input type="radio" id="%s" name="%s" value="%s"%s/>' % \ 551 (self.get_id() + '_' + str(i), self.field_name, value, selected_html)), 552 'label': mark_safe('<label for="%s">%s</label>' % \ 552 553 (self.get_id() + '_' + str(i), display_name), 553 })554 )}) 554 555 return RadioFieldRenderer(datalist, self.ul_class) 555 556 556 557 def isValidChoice(self, data, form): … … 589 590 selected_html = ' selected="selected"' 590 591 output.append(' <option value="%s"%s>%s</option>' % (escape(value), selected_html, escape(choice))) 591 592 output.append(' </select>') 592 return '\n'.join(output)593 return mark_safe('\n'.join(output)) 593 594 594 595 def isValidChoice(self, field_data, all_data): 595 596 # data is something like ['1', '2', '3'] … … 640 641 field_name = '%s%s' % (self.field_name, value) 641 642 output.append('<li><input type="checkbox" id="%s" class="v%s" name="%s"%s /> <label for="%s">%s</label></li>' % \ 642 643 (self.get_id() + value , self.__class__.__name__, field_name, checked_html, 643 self.get_id() + value, choice))644 self.get_id() + value, escape(choice))) 644 645 output.append('</ul>') 645 return '\n'.join(output)646 return mark_safe('\n'.join(output)) 646 647 647 648 #################### 648 649 # FILE UPLOADS # … … 663 664 raise validators.CriticalValidationError, gettext("The submitted file is empty.") 664 665 665 666 def render(self, data): 666 return '<input type="file" id="%s" class="v%s" name="%s" />' % \667 (self.get_id(), self.__class__.__name__, self.field_name) 667 return mark_safe('<input type="file" id="%s" class="v%s" name="%s" />' % \ 668 (self.get_id(), self.__class__.__name__, self.field_name)) 668 669 669 670 def html2python(data): 670 671 if data is None: -
a/django/template/__init__.py
old new 60 60 from django.template.context import Context, RequestContext, ContextPopException 61 61 from django.utils.functional import curry 62 62 from django.utils.text import smart_split 63 from django.utils.safestring import SafeData, EscapeData, mark_safe, mark_for_escaping 64 from django.utils.html import escape 63 65 64 66 __all__ = ('Template', 'Context', 'RequestContext', 'compile_string') 65 67 … … 558 560 arg_vals.append(arg) 559 561 else: 560 562 arg_vals.append(resolve_variable(arg, context)) 561 obj = func(obj, *arg_vals) 563 if getattr(func, 'needs_autoescape', False): 564 new_obj = func(obj, autoescape = context.autoescape, *arg_vals) 565 else: 566 new_obj = func(obj, *arg_vals) 567 if getattr(func, 'is_safe', False) and isinstance(obj, SafeData): 568 obj = mark_safe(new_obj) 569 elif isinstance(obj, EscapeData): 570 obj = mark_for_escaping(new_obj) 571 else: 572 obj = new_obj 573 562 574 return obj 563 575 564 576 def args_check(name, func, provided): … … 744 756 745 757 def render(self, context): 746 758 output = self.filter_expression.resolve(context) 747 return self.encode_output(output) 759 encoded_output = self.encode_output(output) 760 if (context.autoescape and not isinstance(encoded_output, SafeData)) or isinstance(encoded_output, EscapeData): 761 return escape(encoded_output) 762 else: 763 return encoded_output 748 764 749 765 class DebugVariableNode(VariableNode): 750 766 def render(self, context): … … 754 770 if not hasattr(e, 'source'): 755 771 e.source = self.source 756 772 raise 757 return self.encode_output(output) 773 encoded_output = self.encode_output(output) 774 if context.autoescape and not isinstance(encoded_output, SafeData): 775 return escape(encoded_output) 776 else: 777 return encoded_output 758 778 759 779 def generic_tag_compiler(params, defaults, name, node_class, parser, token): 760 780 "Returns a template.Node subclass." -
a/django/template/context.py
old new 9 9 10 10 class Context(object): 11 11 "A stack container for variable context" 12 13 autoescape = False 14 12 15 def __init__(self, dict_=None): 13 16 dict_ = dict_ or {} 14 17 self.dicts = [dict_] … … 95 98 processors = tuple(processors) 96 99 for processor in get_standard_processors() + processors: 97 100 self.update(processor(request)) 101 -
a/django/template/defaultfilters.py
old new 3 3 from django.template import resolve_variable, Library 4 4 from django.conf import settings 5 5 from django.utils.translation import gettext 6 from django.utils.safestring import mark_safe, SafeData 6 7 import re 7 8 import random as random_module 8 9 … … 16 17 def addslashes(value): 17 18 "Adds slashes - useful for passing strings to JavaScript, for example." 18 19 return value.replace('"', '\\"').replace("'", "\\'") 20 addslashes.is_safe = True 19 21 20 22 def capfirst(value): 21 23 "Capitalizes the first character of the value" 22 24 value = str(value) 23 25 return value and value[0].upper() + value[1:] 26 capfirst.is_safe = True 24 27 25 28 def fix_ampersands(value): 26 29 "Replaces ampersands with ``&`` entities" 27 30 from django.utils.html import fix_ampersands 28 31 return fix_ampersands(value) 32 fix_ampersands.is_safe = True 29 33 30 34 def floatformat(text): 31 35 """ … … 40 44 if m: 41 45 return '%.1f' % f 42 46 else: 43 return '%d' % int(f) 47 return mark_safe('%d' % int(f)) 48 floatformat.is_safe = True 44 49 45 def linenumbers(value ):50 def linenumbers(value, autoescape = None): 46 51 "Displays text with line numbers" 47 52 from django.utils.html import escape 48 53 lines = value.split('\n') 49 54 # Find the maximum width of the line count, for use with zero padding string format command 50 55 width = str(len(str(len(lines)))) 51 for i, line in enumerate(lines): 52 lines[i] = ("%0" + width + "d. %s") % (i + 1, escape(line)) 53 return '\n'.join(lines) 56 if not autoescape or isinstance(value, SafeData): 57 for i, line in enumerate(lines): 58 lines[i] = ("%0" + width + "d. %s") % (i + 1, line) 59 else: 60 for i, line in enumerate(lines): 61 lines[i] = ("%0" + width + "d. %s") % (i + 1, escape(line)) 62 return mark_safe('\n'.join(lines)) 63 linenumbers.is_safe = True 64 linenumbers.needs_autoescape = True 54 65 55 66 def lower(value): 56 67 "Converts a string into all lowercase" 57 68 return value.lower() 69 lower.is_safe = True 58 70 59 71 def make_list(value): 60 72 """ … … 62 74 digits. For a string, it's a list of characters. 63 75 """ 64 76 return list(str(value)) 77 make_list.is_safe = False 65 78 66 79 def slugify(value): 67 80 "Converts to lowercase, removes non-alpha chars and converts spaces to hyphens" 68 81 value = re.sub('[^\w\s-]', '', value).strip().lower() 69 return re.sub('[-\s]+', '-', value) 82 return mark_safe(re.sub('[-\s]+', '-', value)) 83 slugify.is_safe = True 70 84 71 85 def stringformat(value, arg): 72 86 """ … … 81 95 return ("%" + arg) % value 82 96 except (ValueError, TypeError): 83 97 return "" 98 stringformat.is_safe = True 84 99 85 100 def title(value): 86 101 "Converts a string into titlecase" 87 102 return re.sub("([a-z])'([A-Z])", lambda m: m.group(0).lower(), value.title()) 103 title.is_safe = False 88 104 89 105 def truncatewords(value, arg): 90 106 """ … … 100 116 if not isinstance(value, basestring): 101 117 value = str(value) 102 118 return truncate_words(value, length) 119 truncatewords.is_safe = True 103 120 104 121 def upper(value): 105 122 "Converts a string into all uppercase" 106 123 return value.upper() 124 upper.is_safe = False 107 125 108 126 def urlencode(value): 109 127 "Escapes a value for use in a URL" 110 128 import urllib 111 129 return urllib.quote(value) 130 urlencode.is_safe = False 112 131 113 132 def urlize(value): 114 133 "Converts URLs in plain text into clickable links" 115 134 from django.utils.html import urlize 116 return urlize(value, nofollow=True) 135 return mark_safe(urlize(value, nofollow=True)) 136 urlize.is_safe = True 117 137 118 138 def urlizetrunc(value, limit): 119 139 """ … … 123 143 Argument: Length to truncate URLs to. 124 144 """ 125 145 from django.utils.html import urlize 126 return urlize(value, trim_url_limit=int(limit), nofollow=True) 146 return mark_safe(urlize(value, trim_url_limit=int(limit), nofollow=True)) 147 urlize.is_safe = True 127 148 128 149 def wordcount(value): 129 150 "Returns the number of words" 130 151 return len(value.split()) 152 wordcount.is_safe = False 131 153 132 154 def wordwrap(value, arg): 133 155 """ … … 137 159 """ 138 160 from django.utils.text import wrap 139 161 return wrap(str(value), int(arg)) 162 wordwrap.is_safe = True 140 163 141 164 def ljust(value, arg): 142 165 """ … … 145 168 Argument: field size 146 169 """ 147 170 return str(value).ljust(int(arg)) 171 ljust.is_safe = True 148 172 149 173 def rjust(value, arg): 150 174 """ … … 153 177 Argument: field size 154 178 """ 155 179 return str(value).rjust(int(arg)) 180 rjust.is_safe = True 156 181 157 182 def center(value, arg): 158 183 "Centers the value in a field of a given width" 159 184 return str(value).center(int(arg)) 185 center.is_safe = True 160 186 161 187 def cut(value, arg): 162 188 "Removes all values of arg from the given string" 163 189 return value.replace(arg, '') 190 cut.is_safe = False 164 191 165 192 ################### 166 193 # HTML STRINGS # 167 194 ################### 168 195 169 196 def escape(value): 170 "Escapes a string's HTML" 197 "Marks the value as a string that should not be auto-escaped." 198 from django.utils.safestring import mark_for_escaping 199 return mark_for_escaping(value) 200 escape.is_safe = True 201 202 def force_escape(value): 203 """Escapes a string's HTML. This returns a new string containing the escaped 204 characters (as opposed to "escape", which marks the content for later 205 possible escaping).""" 171 206 from django.utils.html import escape 172 return escape(value) 207 return mark_safe(escape(value)) 208 force_escape.is_safe = True 173 209 174 def linebreaks(value ):210 def linebreaks(value, autoescape = None): 175 211 "Converts newlines into <p> and <br />s" 176 212 from django.utils.html import linebreaks 177 return linebreaks(value) 213 autoescape = autoescape and not isinstance(value, SafeData) 214 return mark_safe(linebreaks(value, autoescape)) 215 linebreaks.is_safe = True 216 linebreaks.needs_autoescape = True 178 217 179 def linebreaksbr(value ):218 def linebreaksbr(value, autoescape = None): 180 219 "Converts newlines into <br />s" 181 return value.replace('\n', '<br />') 220 if autoescape and not isinstance(value, SafeData): 221 from django.utils.html import escape 222 data = escape(value) 223 else: 224 data = value 225 return mark_safe(data.replace('\n', '<br />')) 226 linebreaksbr.is_safe = True 227 linebreaksbr.needs_autoescape = True 228 229 def safe(value): 230 "Marks the value as a string that should not be auto-escaped." 231 from django.utils.safestring import mark_safe 232 return mark_safe(value) 233 safe.is_safe = True 182 234 183 235 def removetags(value, tags): 184 236 "Removes a space separated list of [X]HTML tags from the output" … … 189 241 value = starttag_re.sub('', value) 190 242 value = endtag_re.sub('', value) 191 243 return value 244 removetags.is_safe = True 192 245 193 246 def striptags(value): 194 247 "Strips all [X]HTML tags" … … 196 249 if not isinstance(value, basestring): 197 250 value = str(value) 198 251 return strip_tags(value) 252 striptags.is_safe = True 199 253 200 254 ################### 201 255 # LISTS # … … 209 263 decorated = [(resolve_variable('var.' + arg, {'var' : item}), item) for item in value] 210 264 decorated.sort() 211 265 return [item[1] for item in decorated] 266 dictsort.is_safe = False 212 267 213 268 def dictsortreversed(value, arg): 214 269 """ … … 219 274 decorated.sort() 220 275 decorated.reverse() 221 276 return [item[1] for item in decorated] 277 dictsortreversed.is_safe = False 222 278 223 279 def first(value): 224 280 "Returns the first item in a list" … … 226 282 return value[0] 227 283 except IndexError: 228 284 return '' 285 first.is_safe = True 229 286 230 287 def join(value, arg): 231 288 "Joins a list with a string, like Python's ``str.join(list)``" 232 289 try: 233 returnarg.join(map(str, value))290 data = arg.join(map(str, value)) 234 291 except AttributeError: # fail silently but nicely 235 292 return value 293 safe_args = reduce(lambda lhs, rhs: lhs and isinstance(rhs, SafeData), value, True) 294 if safe_args: 295 return mark_safe(data) 296 else: 297 return data 298 join.is_safe = True 236 299 237 300 def length(value): 238 301 "Returns the length of the value - useful for lists" 239 302 return len(value) 303 length.is_safe = False 240 304 241 305 def length_is(value, arg): 242 306 "Returns a boolean of whether the value's length is the argument" 243 307 return len(value) == int(arg) 308 length.is_safe = False 244 309 245 310 def random(value): 246 311 "Returns a random item from the list" 247 312 return random_module.choice(value) 313 length.is_safe = True 248 314 249 315 def slice_(value, arg): 250 316 """ … … 265 331 266 332 except (ValueError, TypeError): 267 333 return value # Fail silently. 334 slice_.is_safe = True 268 335 269 def unordered_list(value ):336 def unordered_list(value, autoescape = None): 270 337 """ 271 338 Recursively takes a self-nested list and returns an HTML unordered list -- 272 339 WITHOUT opening and closing <ul> tags. … … 287 354 </ul> 288 355 </li> 289 356 """ 357 if autoescape: 358 from django.utils.html import conditional_escape 359 escaper = conditional_escape 360 else: 361 escaper = lambda x: x 362 290 363 def _helper(value, tabs): 291 364 indent = '\t' * tabs 292 365 if value[1]: 293 return '%s<li>%s\n%s<ul>\n%s\n%s</ul>\n%s</li>' % (indent, value[0], indent,366 return '%s<li>%s\n%s<ul>\n%s\n%s</ul>\n%s</li>' % (indent, escaper(value[0]), indent, 294 367 '\n'.join([_helper(v, tabs+1) for v in value[1]]), indent, indent) 295 368 else: 296 return '%s<li>%s</li>' % (indent, value[0]) 297 return _helper(value, 1) 369 return '%s<li>%s</li>' % (indent, escaper(value[0])) 370 return mark_safe(_helper(value, 1)) 371 unordered_list.is_safe = True 372 unordered_list.needs_autoescape = True 298 373 299 374 ################### 300 375 # INTEGERS # … … 303 378 def add(value, arg): 304 379 "Adds the arg to the value" 305 380 return int(value) + int(arg) 381 add.is_safe = False 306 382 307 383 def get_digit(value, arg): 308 384 """ … … 322 398 return int(str(value)[-arg]) 323 399 except IndexError: 324 400 return 0 401 get_digit.is_safe = False 325 402 326 403 ################### 327 404 # DATES # … … 335 412 if arg is None: 336 413 arg = settings.DATE_FORMAT 337 414 return format(value, arg) 415 date.is_safe = False 338 416 339 417 def time(value, arg=None): 340 418 "Formats a time according to the given format" … … 344 422 if arg is None: 345 423 arg = settings.TIME_FORMAT 346 424 return time_format(value, arg) 425 time.is_safe = False 347 426 348 427 def timesince(value, arg=None): 349 428 'Formats a date as the time since that date (i.e. "4 days, 6 hours")' … … 353 432 if arg: 354 433 return timesince(arg, value) 355 434 return timesince(value) 435 timesince.is_safe = False 356 436 357 437 def timeuntil(value, arg=None): 358 438 'Formats a date as the time until that date (i.e. "4 days, 6 hours")' … … 363 443 if arg: 364 444 return timesince(arg, value) 365 445 return timesince(datetime.now(), value) 446 timeuntil.is_safe = False 366 447 367 448 ################### 368 449 # LOGIC # … … 371 452 def default(value, arg): 372 453 "If value is unavailable, use given default" 373 454 return value or arg 455 default.is_safe = False 374 456 375 457 def default_if_none(value, arg): 376 458 "If value is None, use given default" 377 459 if value is None: 378 460 return arg 379 461 return value 462 default_if_none.is_safe = False 380 463 381 464 def divisibleby(value, arg): 382 465 "Returns true if the value is devisible by the argument" 383 466 return int(value) % int(arg) == 0 467 divisibleby.is_safe = False 384 468 385 469 def yesno(value, arg=None): 386 470 """ … … 411 495 if value: 412 496 return yes 413 497 return no 498 yesno.is_safe = False 414 499 415 500 ################### 416 501 # MISC # … … 429 514 if bytes < 1024 * 1024 * 1024: 430 515 return "%.1f MB" % (bytes / (1024 * 1024)) 431 516 return "%.1f GB" % (bytes / (1024 * 1024 * 1024)) 517 filesizeformat.is_safe = True 432 518 433 519 def pluralize(value, arg='s'): 434 520 """ … … 456 542 except TypeError: # len() of unsized object 457 543 pass 458 544 return singular_suffix 545 pluralize.is_safe = False 459 546 460 547 def phone2numeric(value): 461 548 "Takes a phone number and converts it in to its numerical equivalent" 462 549 from django.utils.text import phone2numeric 463 550 return phone2numeric(value) 551 phone2numeric.is_safe = True 464 552 465 553 def pprint(value): 466 554 "A wrapper around pprint.pprint -- for debugging, really" … … 469 557 return pformat(value) 470 558 except Exception, e: 471 559 return "Error in formatting:%s" % e 560 pprint.is_safe = True 472 561 473 562 # Syntax: register.filter(name of filter, callback) 474 563 register.filter(add) … … 487 576 register.filter(first) 488 577 register.filter(fix_ampersands) 489 578 register.filter(floatformat) 579 register.filter(force_escape) 490 580 register.filter(get_digit) 491 581 register.filter(join) 492 582 register.filter(length) … … 503 593 register.filter(removetags) 504 594 register.filter(random) 505 595 register.filter(rjust) 596 register.filter(safe) 506 597 register.filter('slice', slice_) 507 598 register.filter(slugify) 508 599 register.filter(stringformat) -
a/django/template/defaulttags.py
old new 4 4 from django.template import TemplateSyntaxError, VariableDoesNotExist, BLOCK_TAG_START, BLOCK_TAG_END, VARIABLE_TAG_START, VARIABLE_TAG_END, SINGLE_BRACE_START, SINGLE_BRACE_END 5 5 from django.template import get_library, Library, InvalidTemplateLibrary 6 6 from django.conf import settings 7 from django.utils.safestring import mark_safe 7 8 import sys 8 9 9 10 register = Library() 10 11 12 class AutoEscapeControlNode(Node): 13 """Implements the actions of both the autoescape and noautescape tags.""" 14 def __init__(self, setting, nodelist): 15 self.setting, self.nodelist = setting, nodelist 16 17 def render(self, context): 18 old_setting = context.autoescape 19 context.autoescape = self.setting 20 output = self.nodelist.render(context) 21 context.autoescape = old_setting 22 if self.setting: 23 return mark_safe(output) 24 else: 25 return output 26 11 27 class CommentNode(Node): 12 28 def render(self, context): 13 29 return '' … … 37 53 def render(self, context): 38 54 output = self.nodelist.render(context) 39 55 # apply filters 40 return self.filter_expr.resolve(Context({'var': output})) 56 ctxt = Context({'var': output}) 57 ctxt.autoescape = context.autoescape 58 return self.filter_expr.resolve(ctxt) 41 59 42 60 class FirstOfNode(Node): 43 61 def __init__(self, vars): … … 218 236 return '' 219 237 output = [] # list of dictionaries in the format {'grouper': 'key', 'list': [list of contents]} 220 238 for obj in obj_list: 221 grouper = self.expression.resolve(Context({'var': obj})) 239 ctxt = Context({'var': obj}) 240 ctxt.autoescape = context.autoescape 241 grouper = self.expression.resolve(ctxt) 222 242 # TODO: Is this a sensible way to determine equality? 223 243 if output and repr(output[-1]['grouper']) == repr(grouper): 224 244 output[-1]['list'].append(obj) … … 318 338 return str(int(round(ratio))) 319 339 320 340 #@register.tag 341 def autoescape(parser, token): 342 """ 343 Force autoescape behaviour for this block. 344 """ 345 nodelist = parser.parse(('endautoescape',)) 346 parser.delete_first_token() 347 return AutoEscapeControlNode(True, nodelist) 348 autoescape = register.tag(autoescape) 349 350 #@register.tag 321 351 def comment(parser, token): 322 352 """ 323 353 Ignore everything between ``{% comment %}`` and ``{% endcomment %}`` … … 411 441 412 442 Sample usage:: 413 443 414 {% filter escape|lower %}444 {% filter force_escape|lower %} 415 445 This text will be HTML-escaped, and will appear in lowercase. 416 446 {% endfilter %} 417 447 """ 418 448 _, rest = token.contents.split(None, 1) 419 449 filter_expr = parser.compile_filter("var|%s" % (rest)) 450 for func, unused in filter_expr.filters: 451 if func.__name__ in ('escape', 'safe'): 452 raise TemplateSyntaxError('"filter %s" is not permitted. Use the "autoescape" tag instead.' % func.__name__) 420 453 nodelist = parser.parse(('endfilter',)) 421 454 parser.delete_first_token() 422 455 return FilterNode(filter_expr, nodelist) … … 646 679 ifchanged = register.tag(ifchanged) 647 680 648 681 #@register.tag 682 def noautoescape(parser, token): 683 """ 684 Force autoescape behaviour to be disabled for this block. 685 """ 686 nodelist = parser.parse(('endnoautoescape',)) 687 parser.delete_first_token() 688 return AutoEscapeControlNode(False, nodelist) 689 autoescape = register.tag(noautoescape) 690 691 #@register.tag 649 692 def ssi(parser, token): 650 693 """ 651 694 Output the contents of a given file into the page. -
a/django/utils/html.py
old new 1 1 "HTML utilities suitable for global use." 2 2 3 3 import re, string 4 from django.utils.safestring import SafeData 4 5 5 6 # Configuration for urlize() function 6 7 LEADING_PUNCTUATION = ['(', '<', '<'] … … 27 28 html = str(html) 28 29 return html.replace('&', '&').replace('<', '<').replace('>', '>').replace('"', '"').replace("'", ''') 29 30 30 def linebreaks(value): 31 def conditional_escape(html): 32 "Similar to escape(), except that it does not operate on pre-escaped strings" 33 if isinstance(html, SafeData): 34 return html 35 else: 36 return escape(html) 37 38 def linebreaks(value, autoescape = False): 31 39 "Converts newlines into <p> and <br />s" 32 40 value = re.sub(r'\r\n|\r|\n', '\n', value) # normalize newlines 33 41 paras = re.split('\n{2,}', value) 34 paras = ['<p>%s</p>' % p.strip().replace('\n', '<br />') for p in paras] 42 if autoescape: 43 paras = ['<p>%s</p>' % escape(p.strip()).replace('\n', '<br />') for p in paras] 44 else: 45 paras = ['<p>%s</p>' % p.strip().replace('\n', '<br />') for p in paras] 35 46 return '\n\n'.join(paras) 36 47 37 48 def strip_tags(value): -
/dev/null
old new 1 """ 2 Functions for working with "safe strings": strings that can be displayed safely 3 without further escaping in HTML. Here, a "safe string" means that the producer 4 of the string has already turned characters that should not be interpreted by 5 the HTML engine (e.g. '<') into the appropriate entities. 6 """ 7 from django.utils.functional import curry 8 9 class EscapeData(object): 10 pass 11 12 class EscapeString(str, EscapeData): 13 """ 14 A string that should be HTML-escaped when output. 15 """ 16 pass 17 18 class EscapeUnicode(unicode, EscapeData): 19 """ 20 A unicode object that should be HTML-escaped when output. 21 """ 22 pass 23 24 class SafeData(object): 25 pass 26 27 class SafeString(str, SafeData): 28 """ 29 A string subclass that has been specifically marked as "safe" for HTML 30 output purposes. 31 """ 32 def __add__(self, rhs): 33 """ 34 Concatenating a safe string with another safe string or safe unicode 35 object is safe. Otherwise, the result is no longer safe. 36 """ 37 if isinstance(rhs, SafeUnicode): 38 return SafeUnicode(self + rhs) 39 elif isinstance(rhs, SafeString): 40 return SafeString(self, rhs) 41 else: 42 return super(SafeString, self).__add__(rhs) 43 44 class SafeUnicode(unicode, SafeData): 45 """ 46 A unicode subclass that has been specifically marked as "safe" for HTML 47 output purposes. 48 """ 49 def __add__(self, rhs): 50 """ 51 Concatenating a safe unicode object with another safe string or safe 52 unicode object is safe. Otherwise, the result is no longer safe. 53 """ 54 if isinstance(rhs, SafeData): 55 return SafeUnicode(self + rhs) 56 else: 57 return super(SafeUnicode, self).__add__(rhs) 58 59 def _proxy_method(self, *args, **kwargs): 60 """ 61 Wrap a call to a normal unicode method up so that we return safe 62 results. The method that is being wrapped is passed in the 'method' 63 argument. 64 """ 65 method = kwargs.pop('method') 66 data = method(self, *args, **kwargs) 67 if isinstance(data, str): 68 return SafeString(data) 69 else: 70 return SafeUnicode(data) 71 72 encode = curry(_proxy_method, method = unicode.encode) 73 decode = curry(_proxy_method, method = unicode.decode) 74 75 76 def mark_safe(s): 77 """ 78 Explicitly mark a string as safe for (HTML) output purposes. The returned 79 object can be used everywhere a string or unicode object is appropriate. 80 81 Can safely be called multiple times on a single string. 82 """ 83 if isinstance(s, SafeData): 84 return s 85 if isinstance(s, str): 86 return SafeString(s) 87 if isinstance(s, unicode): 88 return SafeUnicode(s) 89 return SafeString(str(s)) 90 91 def mark_for_escaping(s): 92 """ 93 Explicitly mark a string as requiring HTML escaping upon output. Has no 94 effect on SafeData subclasses. 95 96 Can be safely called multiple times on a single string (the effect is only 97 applied once). 98 """ 99 if isinstance(s, SafeData) or isinstance(s, EscapeData): 100 return s 101 if isinstance(s, str): 102 return EscapeString(s) 103 if isinstance(s, unicode): 104 return EscapeUnicode(s) 105 return EscapeString(str(s)) 106 -
a/docs/templates.txt
old new 243 243 two similarly-named ``{% block %}`` tags in a template, that template's parent 244 244 wouldn't know which one of the blocks' content to use. 245 245 246 Automatic HTML escaping 247 ======================= 248 249 A very real problem when creating HTML (and other) output using templates and 250 variable substitution is the possibility of accidently inserting some variable 251 value that affects the resulting HTML. For example, a template fragment like 252 253 :: 254 255 Hello, {{ name }}. 256 257 seems like a harmless way to display the user's name. However, if you are 258 displaying data that the user entered directly and they entered their name as 259 260 :: 261 262 <script>alert('hello')</script> 263 264 this would always display a Javascript alert box whenever the page was loaded. 265 Similarly, if you were displaying some data generated by another process and 266 it contained a '<' symbol, you couldn't just dump this straight into your 267 HTML, because it would be treated as the start of an element. The effects of 268 these sorts of problems can vary from merely annoying to allowing exploits via 269 `Cross Site Scripting`_ (XSS) attacks. 270 271 .. _Cross Site Scripting: http://en.wikipedia.org/wiki/Cross-site_scripting 272 273 In order to provide some protection against these problems, Django provides an 274 auto-escaping template tag. Inside this tag, any data that comes from template 275 variables is examined to see if it contains one of the five HTML characters 276 (<, >, ', " and &) that often need escaping and those characters are converted 277 to their respective HTML entities. 278 279 Because some variables will contain data that is *intended* to be rendered 280 as HTML, template tag and filter writers can mark their output strings as 281 requiring no further escaping. For example, the ``unordered_list`` filter is 282 designed to return raw HTML and we want the template processor to simply 283 display the results as returned, without applying any escaping. That is taken 284 care of by the filter. The template author need do nothing special in that 285 case. 286 287 By default, auto-escaping is not in effect. To enable it inside your template, 288 wrap the affected content in the ``autoescape`` tag, like so:: 289 290 {% autoescape %} 291 Hello {{ name }} 292 {% endautoescape %} 293 294 Since the auto-escaping tag passes its effect onto templates that extend the 295 current one as well as templates included via the ``include`` tag (just like 296 all block tags), if you wrap your main HTML content in an ``autoescape`` tag, 297 you will have automatic escaping applied to all of your content. 298 299 At times, you might want to disable auto-escaping when it would otherwise be 300 in effect. You can do this with the ``noautoescape`` tag. For example:: 301 302 {% autoescape %} 303 Hello {{ name }} 304 305 {% noautoescape %} 306 This will not be auto-escaped: {{ data }}. 307 308 Nor this: {{ other_data }} 309 {% endnoautoescape %} 310 {% endautoescape %} 311 312 For individual variables, the ``safe`` filter can also be used. 313 314 Generally, you will not need to worry about auto-escaping very much. Enable it 315 in your base template once you are entering the main HTML region and then 316 write your templates normally. The view developers and custom filter authors 317 need to think about when their data should not be escaped and mark it 318 appropriately. They are in a better position to know when that should happen 319 than the template author, so it is their responsibility. By default, when 320 auto-escaping is enabled, all output is escaped unless the template processor 321 is explicitly told otherwise. 322 246 323 Using the built-in reference 247 324 ============================ 248 325 … … 318 395 Built-in tag reference 319 396 ---------------------- 320 397 398 autoescape 399 ~~~~~~~~~~ 400
