Don't replace !! in elements
authorArlo Breault <abreault@wikimedia.org>
Fri, 5 Feb 2016 16:00:56 +0000 (08:00 -0800)
committerTim Starling <tstarling@wikimedia.org>
Wed, 6 Apr 2016 06:23:48 +0000 (06:23 +0000)
 * 55313f4e almost got it right, but missed the str_replacing table
   headings.

 * Thankfully, this was doubly broken before that patch since the
   StringUtils::explodeMarkup would have skipped the || which would
   go on to be explode by table cell attribute parsing. The test case
   provided would look like,

   <table>
   <tr>
   <th class="">|">ha</div> ho
   </th></tr></table>

   Suffice it to say, noone is using this in production.

 * Note that we can't just entity encode the ! since that would break
   style attributes with !important.

 * Also note, Parsoid already gets this right.

 * Adds a StringUtils::replaceMarkup

Change-Id: Iab3ae4518fcb307b795d57eece420ba48af0a3bf

includes/libs/StringUtils.php
includes/parser/Parser.php
tests/parser/parserTests.txt

index d2226b6..057495e 100644 (file)
@@ -288,6 +288,31 @@ class StringUtils {
                return $items;
        }
 
+       /**
+        * More or less "markup-safe" str_replace()
+        * Ignores any instances of the separator inside `<...>`
+        * @param string $search
+        * @param string $replace
+        * @param string $text
+        * @return string
+        */
+       static function replaceMarkup( $search, $replace, $text ) {
+               $placeholder = "\x00";
+
+               // Remove placeholder instances
+               $text = str_replace( $placeholder, '', $text );
+
+               // Replace instances of the separator inside HTML-like tags with the placeholder
+               $replacer = new DoubleReplacer( $search, $placeholder );
+               $cleaned = StringUtils::delimiterReplaceCallback( '<', '>', $replacer->cb(), $text );
+
+               // Explode, then put the replaced separators back in
+               $cleaned = str_replace( $search, $replace, $cleaned );
+               $text = str_replace( $placeholder, $search, $cleaned );
+
+               return $text;
+       }
+
        /**
         * Escape a string to make it suitable for inclusion in a preg_replace()
         * replacement parameter.
index 5ee0c5a..d2e4bf0 100644 (file)
@@ -1115,7 +1115,7 @@ class Parser {
 
                                // Implies both are valid for table headings.
                                if ( $first_character === '!' ) {
-                                       $line = str_replace( '!!', '||', $line );
+                                       $line = StringUtils::replaceMarkup( '!!', '||', $line );
                                }
 
                                # Split up multiple cells on the same line.
index 691113d..23bdbde 100644 (file)
@@ -6333,6 +6333,24 @@ parsoid=wt2html,html2html
 <td data-parsoid='{"startTagSrc":"| ","attrSepSrc":"|","autoInsertedEnd":true}'><a rel="mw:ExtLink" href="ftp://|x||"></a>" onmouseover="alert(document.cookie)">test</td></tr></tbody></table>
 !! end
 
+!! test
+Element attributes with double ! should not be broken up by <th>
+!! wikitext
+{|
+! hi <div class="!!">ha</div> ho
+|}
+!! html/php
+<table>
+<tr>
+<th> hi <div class="!!">ha</div> ho
+</th></tr></table>
+
+!! html/parsoid
+<table>
+<tbody><tr><th> hi <div class="!!" data-parsoid='{"stx":"html"}'>ha</div> ho</th></tr>
+</tbody></table>
+!! end
+
 !! test
 ! and || in element attributes should not be parsed as <th>/<td>
 !! wikitext