CSSMin: Improve encoding of quotes in embedded SVGs
authorRoan Kattouw <roan.kattouw@gmail.com>
Wed, 13 Sep 2017 19:27:15 +0000 (12:27 -0700)
committerBartosz Dziewoński <matma.rex@gmail.com>
Tue, 19 Sep 2017 18:04:27 +0000 (18:04 +0000)
When a URL (data: or otherwise) contains quotes, don't wrap it in
double quotes (") but in single quotes ('). This then allows
us to unencode double quotes (") in the data URI embedding of SVGs.

Bug: T175318
Change-Id: I3e7eab64e1c3e82066014fb594f82d786983ce90

includes/libs/CSSMin.php
tests/phpunit/includes/libs/CSSMinTest.php

index ee88d0d..adaae17 100644 (file)
@@ -149,6 +149,7 @@ class CSSMin {
                                '%2F' => '/', // Unencode slashes
                                '%3A' => ':', // Unencode colons
                                '%3D' => '=', // Unencode equals signs
+                               '%22' => '"', // Unencode double quotes
                        ] );
                        $uri = 'data:' . $type . ',' . $encoded;
                        if ( !$ie8Compat || strlen( $uri ) < self::DATA_URI_SIZE_LIMIT ) {
@@ -215,7 +216,7 @@ class CSSMin {
                if ( preg_match( '!^[\w\d:@/~.%+;,?&=-]+$!', $url ) ) {
                        return "url($url)";
                } else {
-                       return 'url("' . strtr( $url, [ '\\' => '\\\\', '"' => '\\"' ] ) . '")';
+                       return "url('" . strtr( $url, [ '\\' => '\\\\', "'" => "\\'" ] ) . "')";
                }
        }
 
index b06df97..62f990b 100644 (file)
@@ -242,7 +242,7 @@ class CSSMinTest extends MediaWikiTestCase {
                        [
                                "Don't barf at behavior: url(#default#behaviorName) - T162973",
                                [ 'foo { behavior: url(#default#bar); }', false, '/w/', false ],
-                               'foo { behavior: url("#default#bar"); }',
+                               'foo { behavior: url(\'#default#bar\'); }',
                        ],
                ];
        }
@@ -271,9 +271,9 @@ class CSSMinTest extends MediaWikiTestCase {
                // data: URIs for red.gif, green.gif, circle.svg
                $red   = 'data:image/gif;base64,R0lGODlhAQABAIAAAP8AADAAACwAAAAAAQABAAACAkQBADs=';
                $green = 'data:image/gif;base64,R0lGODlhAQABAIAAAACAADAAACwAAAAAAQABAAACAkQBADs=';
-               $svg = 'data:image/svg+xml,%3C%3Fxml version=%221.0%22 encoding=%22UTF-8%22%3F%3E%0A'
-                       . '%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 width=%228%22 height='
-                       . '%228%22%3E%0A%09%3Ccircle cx=%224%22 cy=%224%22 r=%222%22/%3E%0A%3C/svg%3E%0A';
+               $svg = 'data:image/svg+xml,%3C%3Fxml version="1.0" encoding="UTF-8"%3F%3E%0A'
+                       . '%3Csvg xmlns="http://www.w3.org/2000/svg" width="8" height='
+                       . '"8"%3E%0A%09%3Ccircle cx="4" cy="4" r="2"/%3E%0A%3C/svg%3E%0A';
 
                // @codingStandardsIgnoreStart Generic.Files.LineLength
                return [
@@ -361,7 +361,7 @@ class CSSMinTest extends MediaWikiTestCase {
                        [
                                'SVG files are embedded without base64 encoding and unnecessary IE 6 and 7 fallback',
                                'foo { /* @embed */ background: url(circle.svg); }',
-                               "foo { background: url(\"$svg\"); }",
+                               "foo { background: url('$svg'); }",
                        ],
                        [
                                'Two regular files in one rule',
@@ -444,17 +444,17 @@ class CSSMinTest extends MediaWikiTestCase {
                        [
                                'Background URL (containing parentheses; T60473)',
                                'foo { background: url("//localhost/styles.css?query=(parens)") }',
-                               'foo { background: url("//localhost/styles.css?query=(parens)") }',
+                               'foo { background: url(\'//localhost/styles.css?query=(parens)\') }',
                        ],
                        [
                                'Background URL (double quoted, containing single quotes; T60473)',
                                'foo { background: url("//localhost/styles.css?quote=\'") }',
-                               'foo { background: url("//localhost/styles.css?quote=\'") }',
+                               'foo { background: url(\'//localhost/styles.css?quote=\\\'\') }',
                        ],
                        [
                                'Background URL (single quoted, containing double quotes; T60473)',
                                'foo { background: url(\'//localhost/styles.css?quote="\') }',
-                               'foo { background: url("//localhost/styles.css?quote=\"") }',
+                               'foo { background: url(\'//localhost/styles.css?quote="\') }',
                        ],
                        [
                                'Simple case with comments before url',
@@ -522,15 +522,25 @@ class CSSMinTest extends MediaWikiTestCase {
                                'url(data:image/png;base64,R0lGODlh/+==)',
                        ],
                        [
-                               'URL with quotes',
+                               'URL with single quotes',
                                "https://en.wikipedia.org/wiki/Wendy's",
-                               "url(\"https://en.wikipedia.org/wiki/Wendy's\")",
+                               "url('https://en.wikipedia.org/wiki/Wendy\\'s')",
+                       ],
+                       [
+                               'URL with double quotes',
+                               'https://en.wikipedia.org/wiki/""',
+                               "url('https://en.wikipedia.org/wiki/\"\"')",
                        ],
                        [
                                'URL with parentheses',
                                'https://en.wikipedia.org/wiki/Boston_(band)',
-                               'url("https://en.wikipedia.org/wiki/Boston_(band)")',
+                               "url('https://en.wikipedia.org/wiki/Boston_(band)')",
                        ],
+                       [
+                               'URL with spaces',
+                               'https://en.wikipedia.org/wiki/Foo bar',
+                               "url('https://en.wikipedia.org/wiki/Foo bar')"
+                       ]
                ];
        }