Edgewall Software

Ticket #2455: dont_escape_wiki_text_beforehand-r2636.patch

File dont_escape_wiki_text_beforehand-r2636.patch, 7.7 KB (added by cboos, 3 years ago)

Don't HTML escape the wiki text before parsing. The HTML escaping is instead done as a normal formatting step.

  • trac/Search.py

    diff -r c8cc0c3edd29 trac/Search.py
    a b  
    238238 
    239239    def _format_link(self, formatter, ns, query, label): 
    240240        if query and query[0] == '?': 
    241             href = formatter.href.search() + \ 
    242                    query.replace('&', '&').replace(' ', '+') 
     241            href = formatter.href.search() + query.replace(' ', '+') 
    243242        else: 
    244243            href = formatter.href.search(q=query) 
    245244        return '<a class="search" href="%s">%s</a>' % (escape(href), label) 
  • trac/ticket/query.py

    diff -r c8cc0c3edd29 trac/ticket/query.py
    a b  
    609609    def _format_link(self, formatter, ns, query, label): 
    610610        if query[0] == '?': 
    611611            return '<a class="query" href="%s">%s</a>' \ 
    612                    % (escape(formatter.href.query()) + query.replace(' ', '+'), 
     612                   % (escape(formatter.href.query() + query.replace(' ', '+')), 
    613613                      label) 
    614614        else: 
    615615            from trac.ticket.query import Query, QuerySyntaxError 
    616616            try: 
    617                 query = Query.from_string(formatter.env, unescape(query)) 
     617                query = Query.from_string(formatter.env, query) 
    618618                return '<a class="query" href="%s">%s</a>' \ 
    619619                       % (escape(query.get_href()), label) 
    620620            except QuerySyntaxError, e: 
  • trac/wiki/formatter.py

    diff -r c8cc0c3edd29 trac/wiki/formatter.py
    a b  
    137137    QUOTED_STRING = r"'[^']+'|\"[^\"]+\"" 
    138138 
    139139    SHREF_TARGET_FIRST = r"[\w/?!#@]" 
    140     SHREF_TARGET_MIDDLE = r"(?:\|(?=[^|\s])|&(?!lt;|gt;)|[^|&\s])" 
     140    SHREF_TARGET_MIDDLE = r"(?:\|(?=[^|\s])|[^|<>\s])" 
    141141    SHREF_TARGET_LAST = r"[a-zA-Z0-9/=]" # we don't want "_" 
    142142 
    143143    LHREF_RELATIVE_TARGET = r"[/.][^\s[\]]*" 
     
    147147    # between _pre_rules and _post_rules 
    148148 
    149149    _pre_rules = [ 
     150        r"(?P<htmlescape>[&<>])", 
    150151        # Font styles 
    151152        r"(?P<bolditalic>%s)" % BOLDITALIC_TOKEN, 
    152153        r"(?P<bold>%s)" % BOLD_TOKEN, 
     
    296297 
    297298    def _make_link(self, ns, target, match, label): 
    298299        if ns in self.link_resolvers: 
    299             return self.link_resolvers[ns](self, ns, target, label) 
     300            return self.link_resolvers[ns](self, ns, target, 
     301                                           util.escape(label, False)) 
    300302        elif target.startswith('//') or ns == "mailto": 
    301303            return self._make_ext_link(ns+':'+target, label) 
    302304        else: 
    303             return match 
     305            return util.escape(match) 
    304306 
    305307    def _make_ext_link(self, url, text, title=''): 
    306         title_attr = title and ' title="%s"' % title or '' 
     308        url = util.escape(url) 
     309        title_attr = title and ' title="%s"' % util.escape(title) or '' 
    307310        if Formatter.img_re.search(url) and self.flavor != 'oneliner': 
    308             return '<img src="%s" alt="%s" />' % (url, title or text) 
     311            return '<img src="%s" alt="%s" />' % (url, 
     312                                                  util.escape(title or text)) 
    309313        if not url.startswith(self._local): 
    310314            return '<a class="ext-link" href="%s"%s><span class="icon">' \ 
    311315                   '</span>%s</a>' % (url, title_attr, text) 
     
    313317            return '<a href="%s"%s>%s</a>' % (url, title_attr, text) 
    314318 
    315319    def _make_relative_link(self, url, text): 
     320        url, text = util.escape(url), util.escape(text) 
    316321        if Formatter.img_re.search(url) and self.flavor != 'oneliner': 
    317322            return '<img src="%s" alt="%s" />' % (url, text) 
    318323        if url.startswith('//'): # only the protocol will be kept 
     
    364369        # the tickethref regexp 
    365370        return match 
    366371 
     372    def _htmlescape_formatter(self, match, fullmatch): 
     373        return match == "&" and "&amp;" or match == "<" and "&lt;" or "&gt;" 
     374 
    367375    def _macro_formatter(self, match, fullmatch): 
    368376        name = fullmatch.group('macroname') 
    369377        if name in ['br', 'BR']: 
    370378            return '<br />' 
    371379        args = fullmatch.group('macroargs') 
    372         args = util.unescape(args) 
    373380        try: 
    374381            macro = WikiProcessor(self.env, name) 
    375382            return macro.process(self.req, args, 1) 
     
    389396        depth = min(len(fullmatch.group('hdepth')), 5) 
    390397        heading = match[depth + 1:len(match) - depth - 1] 
    391398 
    392         text = wiki_to_oneliner(util.unescape(heading), self.env, self.db, 
    393                                 self._absurls) 
     399        text = wiki_to_oneliner(heading, self.env, self.db, self._absurls) 
    394400        sans_markup = re.sub(r'</?\w+(?: .*?)?>', '', text) 
    395401 
    396402        anchor = self._anchor_re.sub('', sans_markup.decode('utf-8')) 
     
    599605                self.close_def_list() 
    600606                continue 
    601607 
    602             line = util.escape(line, False) 
    603608            if escape_newlines: 
    604609                line += ' [[BR]]' 
    605610            self.in_list_item = False 
     
    646651    # Override a few formatters to disable some wiki syntax in "oneliner"-mode 
    647652    def _list_formatter(self, match, fullmatch): return match 
    648653    def _indent_formatter(self, match, fullmatch): return match 
    649     def _heading_formatter(self, match, fullmatch): return match 
    650     def _definition_formatter(self, match, fullmatch): return match 
     654    def _heading_formatter(self, match, fullmatch): 
     655        return util.escape(match, False) 
     656    def _definition_formatter(self, match, fullmatch): 
     657        return util.escape(match, False) 
    651658    def _table_cell_formatter(self, match, fullmatch): return match 
    652659    def _last_table_cell_formatter(self, match, fullmatch): return match 
    653660 
     
    687694        if shorten: 
    688695            result = util.shorten_line(result) 
    689696 
    690         result = re.sub(self.rules, self.replace, util.escape(result, False)) 
     697        result = re.sub(self.rules, self.replace, result) 
    691698        result = result.replace('[...]', '[&hellip;]') 
    692699        if result.endswith('...'): 
    693700            result = result[:-3] + '&hellip;' 
     
    739746        depth = min(len(fullmatch.group('hdepth')), 5) 
    740747        heading = match[depth + 1:len(match) - depth - 1] 
    741748        anchor = self._anchors[-1] 
    742         text = wiki_to_oneliner(util.unescape(heading), self.env, self.db, 
    743                                 self._absurls) 
     749        text = wiki_to_oneliner(heading, self.env, self.db, self._absurls) 
    744750        text = re.sub(r'</?a(?: .*?)?>', '', text) # Strip out link tags 
    745751        self.outline.append((depth, '<a href="#%s">%s</a>' % (anchor, text))) 
    746752 
  • trac/wiki/tests/wiki-tests.txt

    diff -r c8cc0c3edd29 trac/wiki/tests/wiki-tests.txt
    a b  
    115115ticket:1 
    116116This ticket is the first one 
    117117changeset:123> 
     118changeset:123& 
    118119------------------------------ 
    119120<p> 
    120121Add-on to <a class="missing changeset" href="/changeset/123" rel="nofollow">changeset:123</a>: 
     
    122123<a class="missing ticket" href="/ticket/1" rel="nofollow">ticket:1</a> 
    123124This ticket is the first one 
    124125<a class="missing changeset" href="/changeset/123" rel="nofollow">changeset:123</a>&gt; 
     126<a class="missing changeset" href="/changeset/123" rel="nofollow">changeset:123</a>&amp; 
    125127</p> 
    126128------------------------------ 
    127129Add-on to <a class="missing changeset" href="/changeset/123" rel="nofollow">changeset:123</a>: 
     
    129131<a class="missing ticket" href="/ticket/1" rel="nofollow">ticket:1</a> 
    130132This ticket is the first one 
    131133<a class="missing changeset" href="/changeset/123" rel="nofollow">changeset:123</a>&gt; 
     134<a class="missing changeset" href="/changeset/123" rel="nofollow">changeset:123</a>&amp; 
    132135============================== 
    133136CamelCase AlabamA ABc AlaBamA FooBar 
    134137------------------------------