Fix pretty JSON when strings end with backslashes
authorKevin Israel <pleasestand@live.com>
Thu, 28 Mar 2013 02:04:58 +0000 (22:04 -0400)
committerKevin Israel <pleasestand@live.com>
Sat, 30 Mar 2013 20:23:24 +0000 (16:23 -0400)
If a string encoded as part of the output ends in a backslash
(e.g. an edit token), FormatJson::prettyPrint() may incorrectly
treat the unescaped double quote marking the end of the string as
a character that is part of the string.

This is a serious problem in that the "pretty" output may not
necessarily be valid JSON; a later string literal might contain
one or more of these tokens: :[{,]}

To fix the bug, I exploit strtr's behavior when it is given an
associative array having keys of the same length to skip over
escaped backslashes while replacing escaped double quotes with "\x01".

I also updated the corresponding unit test.

Change-Id: I159105b6493c14b82cd0a41a95e04bfed744931e

includes/json/FormatJson.php
tests/phpunit/includes/json/FormatJsonTest.php

index 013d589..bdf98d5 100644 (file)
@@ -168,7 +168,7 @@ class FormatJson {
        private static function prettyPrint( $json ) {
                $buf = '';
                $indent = 0;
-               $json = str_replace( '\"', "\x01", $json );
+               $json = strtr( $json, array( '\\\\' => '\\\\', '\"' => "\x01" ) );
                for ( $i = 0, $n = strlen( $json ); $i < $n; $i += $skip ) {
                        $skip = 1;
                        switch ( $json[$i] ) {
index 9e25e18..0782e4e 100644 (file)
@@ -6,7 +6,7 @@ class FormatJsonTest extends MediaWikiTestCase {
                $obj = array(
                        'emptyObject' => new stdClass,
                        'emptyArray' => array(),
-                       'string' => 'foobar',
+                       'string' => 'foobar\\',
                        'filledArray' => array(
                                array(
                                        123,
@@ -24,7 +24,7 @@ class FormatJsonTest extends MediaWikiTestCase {
     "emptyArray": [
 
     ],
-    "string": "foobar",
+    "string": "foobar\\\\",
     "filledArray": [
         [
             123,