Parser: Don't wrap <style> or <link> tags in paragraphs
authorBrad Jorsch <bjorsch@wikimedia.org>
Mon, 26 Feb 2018 21:49:08 +0000 (16:49 -0500)
committerBrad Jorsch <bjorsch@wikimedia.org>
Wed, 28 Feb 2018 19:12:49 +0000 (14:12 -0500)
If <style> or <link> tags are by themselves on a line, don't wrap them
in <p> tags. But, at the same time, don't end an existing paragraph if
we find <style> or <link> in the middle (like we would if we just
treated them as block tags).

If <style> or <link> is on a line with other text, though, let it be
wrapped in a paragraph along with that other text.

Bug: T186965
Change-Id: Ide4005842cdab537226aa538cb5f7d8e363ba95d

includes/parser/BlockLevelPass.php
tests/parser/ParserTestRunner.php
tests/parser/parserTests.txt

index 8cf8f85..7f78912 100644 (file)
@@ -329,6 +329,14 @@ class BlockLevelPass {
                                                        $this->lastSection = 'pre';
                                                }
                                                $t = substr( $t, 1 );
+                                       } elseif ( preg_match( '/^(?:<style\\b[^>]*>.*?<\\/style>\s*|<link\\b[^>]*>\s*)+$/iS', $t ) ) {
+                                               # T186965: <style> or <link> by itself on a line shouldn't open or close paragraphs.
+                                               # But it should clear $pendingPTag.
+                                               if ( $pendingPTag ) {
+                                                       $output .= $this->closeParagraph();
+                                                       $pendingPTag = false;
+                                                       $this->lastSection = '';
+                                               }
                                        } else {
                                                # paragraph
                                                if ( trim( $t ) === '' ) {
index d4b1f91..a03f969 100644 (file)
@@ -831,6 +831,19 @@ class ParserTestRunner {
                $parser = $this->getParser( $preprocessor );
                $title = Title::newFromText( $titleText );
 
+               if ( isset( $opts['styletag'] ) ) {
+                       // For testing the behavior of <style> (including those deduplicated
+                       // into <link> tags), add tag hooks to allow them to be generated.
+                       $parser->setHook( 'style', function ( $content, $attributes, $parser ) {
+                               $marker = Parser::MARKER_PREFIX . '-style-' . md5( $content ) . Parser::MARKER_SUFFIX;
+                               $parser->mStripState->addNoWiki( $marker, $content );
+                               return Html::inlineStyle( $marker, 'all', $attributes );
+                       } );
+                       $parser->setHook( 'link', function ( $content, $attributes, $parser ) {
+                               return Html::element( 'link', $attributes );
+                       } );
+               }
+
                if ( isset( $opts['pst'] ) ) {
                        $out = $parser->preSaveTransform( $test['input'], $title, $user, $options );
                        $output = $parser->getOutput();
index e6fa203..4d6efff 100644 (file)
@@ -29899,16 +29899,14 @@ unclosed internal link XSS (T137264)
 <p>[[#%3Cscript%3Ealert(1)%3C/script%3E|</p>
 !! end
 
-# Use $wgRawHtml to inject a <style> tag, since you normally can't in wikitext
-# (Parsoid doesn't support $wgRawHtml==true)
 !! test
 Validating that <style> isn't eaten by tidy (T167349)
 !! options
-wgRawHtml=1
+styletag=1
 !! wikitext
 <div class="foo">
-<html><style>.foo::before { content: "<foo>"; }</style></html>
-<html><style data-mw-foobar="baz">.foo::after { content: "<bar>"; }</style></html>
+<style>.foo::before { content: "<foo>"; }</style>
+<style data-mw-foobar="baz">.foo::after { content: "<bar>"; }</style>
 </div>
 !! html/php+tidy
 <div class="foo">
@@ -29917,6 +29915,86 @@ wgRawHtml=1
 </div>
 !! end
 
+!! test
+Validating that <style> isn't wrapped in a paragraph (T186965)
+!! options
+styletag=1
+!! wikitext
+A style tag, by itself or with other style/link tags, shouldn't be wrapped in a paragraph
+
+<style>.foo::before { content: "<foo>"; }</style>
+
+<style>.foo::before { content: "<foo>"; }</style> <link rel="foo" href="bar"/><style>.foo::before { content: "<foo>"; }</style>
+
+But if it's on a line with other content, let it be wrapped.
+
+<style>.foo::before { content: "<foo>"; }</style> bar
+
+foo <style>.foo::before { content: "<foo>"; }</style>
+
+foo <style>.foo::before { content: "<foo>"; }</style> bar
+
+And the same if we have non-paragraph-breaking whitespace
+
+foo
+<style>.foo::before { content: "<foo>"; }</style>
+bar
+!! html/php
+<p>A style tag, by itself or with other style/link tags, shouldn't be wrapped in a paragraph
+</p>
+<style>.foo::before { content: "<foo>"; }</style>
+<style>.foo::before { content: "<foo>"; }</style> <link rel="foo" href="bar"/><style>.foo::before { content: "<foo>"; }</style>
+<p>But if it's on a line with other content, let it be wrapped.
+</p><p><style>.foo::before { content: "<foo>"; }</style> bar
+</p><p>foo <style>.foo::before { content: "<foo>"; }</style>
+</p><p>foo <style>.foo::before { content: "<foo>"; }</style> bar
+</p><p>And the same if we have non-paragraph-breaking whitespace
+</p><p>foo
+<style>.foo::before { content: "<foo>"; }</style>
+bar
+</p>
+!! end
+
+!! test
+Validating that <link> isn't wrapped in a paragraph (T186965)
+!! options
+styletag=1
+!! wikitext
+A link tag, by itself or with other style/link tags, shouldn't be wrapped in a paragraph
+
+<link rel="foo" href="bar"/>
+
+<link rel="foo" href="bar"/> <style>.foo::before { content: "<foo>"; }</style><link rel="foo" href="bar"/>
+
+But if it's on a line with other content, let it be wrapped.
+
+<link rel="foo" href="bar"/> bar
+
+foo <link rel="foo" href="bar"/>
+
+foo <link rel="foo" href="bar"/> bar
+
+And the same if we have non-paragraph-breaking whitespace
+
+foo
+<link rel="foo" href="bar"/>
+bar
+!! html/php
+<p>A link tag, by itself or with other style/link tags, shouldn't be wrapped in a paragraph
+</p>
+<link rel="foo" href="bar"/>
+<link rel="foo" href="bar"/> <style>.foo::before { content: "<foo>"; }</style><link rel="foo" href="bar"/>
+<p>But if it's on a line with other content, let it be wrapped.
+</p><p><link rel="foo" href="bar"/> bar
+</p><p>foo <link rel="foo" href="bar"/>
+</p><p>foo <link rel="foo" href="bar"/> bar
+</p><p>And the same if we have non-paragraph-breaking whitespace
+</p><p>foo
+<link rel="foo" href="bar"/>
+bar
+</p>
+!! end
+
 !! test
 Decoding of HTML entities in headings and links for IDs and link fragments (T103714)
 !! config