Skip to content

Commit fe04be1

Browse files
[JsonPath] Improve escape sequence validation in name selector
1 parent e568dab commit fe04be1

File tree

3 files changed

+29
-54
lines changed

3 files changed

+29
-54
lines changed

src/Symfony/Component/JsonPath/JsonPathUtils.php

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
namespace Symfony\Component\JsonPath;
1313

1414
use Symfony\Component\JsonPath\Exception\InvalidArgumentException;
15+
use Symfony\Component\JsonPath\Exception\JsonCrawlerException;
1516
use Symfony\Component\JsonPath\Tokenizer\JsonPathToken;
1617
use Symfony\Component\JsonPath\Tokenizer\TokenType;
1718
use Symfony\Component\JsonStreamer\Read\Splitter;
@@ -86,8 +87,13 @@ public static function findSmallestDeserializableStringAndPath(array $tokens, mi
8687
];
8788
}
8889

90+
/**
91+
* @throws JsonCrawlerException When an invalid Unicode escape sequence occurs
92+
*/
8993
public static function unescapeString(string $str, string $quoteChar): string
9094
{
95+
self::validateEscapeSequences($str, $quoteChar);
96+
9197
if ('"' === $quoteChar) {
9298
// try JSON decoding first for unicode sequences
9399
$jsonStr = '"'.$str.'"';
@@ -108,7 +114,7 @@ public static function unescapeString(string $str, string $quoteChar): string
108114
"'" => "'",
109115
'\\' => '\\',
110116
'/' => '/',
111-
'b' => "\b",
117+
'b' => "\x08",
112118
'f' => "\f",
113119
'n' => "\n",
114120
'r' => "\r",
@@ -227,4 +233,24 @@ public static function parseCommaSeparatedValues(string $expr): array
227233

228234
return $parts;
229235
}
236+
237+
private static function validateEscapeSequences(string $str, string $quoteChar): void
238+
{
239+
$i = -1;
240+
while (null !== $char = $str[++$i] ?? null) {
241+
if ('\\' !== $char || !isset($str[$i + 1])) {
242+
continue;
243+
}
244+
245+
if (!\in_array($next = $str[$i + 1], [$quoteChar, '\\', '/', 'b', 'f', 'n', 'r', 't', 'u'], true)) {
246+
throw new JsonCrawlerException('', \sprintf('Invalid escape sequence "\\%s" in %s-quoted string', $next, "'" === $quoteChar ? 'single' : 'double'));
247+
}
248+
249+
if ('u' === $next && (!isset($str[$i + 5]) || !ctype_xdigit(substr($str, $i + 2, 4)))) {
250+
throw new JsonCrawlerException('', 'Invalid unicode escape sequence');
251+
}
252+
253+
++$i;
254+
}
255+
}
230256
}

src/Symfony/Component/JsonPath/Tests/JsonCrawlerTest.php

Lines changed: 2 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ public function testEscapedDoubleQuotesInFieldName()
8686
{"a": {"b\\"c": 42}}
8787
JSON);
8888

89-
$result = $crawler->find("$['a']['b\\\"c']");
89+
$result = $crawler->find('$["a"]["b\"c"]');
9090

9191
$this->assertSame(42, $result[0]);
9292
}
@@ -641,10 +641,6 @@ public static function provideSingleQuotedStringProvider(): array
641641
"$['\\u65e5\\u672c']",
642642
['Japan'],
643643
],
644-
[
645-
"$['quote\"here']",
646-
['with quote'],
647-
],
648644
[
649645
"$['M\\u00fcller']",
650646
[],
@@ -658,7 +654,7 @@ public static function provideSingleQuotedStringProvider(): array
658654
['with tab'],
659655
],
660656
[
661-
"$['quote\\\"here']",
657+
"$['quote\"here']",
662658
['with quote'],
663659
],
664660
[
@@ -725,29 +721,6 @@ public static function provideFilterWithUnicodeProvider(): array
725721
];
726722
}
727723

728-
/**
729-
* @dataProvider provideInvalidUnicodeSequenceProvider
730-
*/
731-
public function testInvalidUnicodeSequencesAreProcessedAsLiterals(string $jsonPath)
732-
{
733-
$this->assertIsArray(self::getUnicodeDocumentCrawler()->find($jsonPath), 'invalid unicode sequence should be treated as literal and not throw');
734-
}
735-
736-
public static function provideInvalidUnicodeSequenceProvider(): array
737-
{
738-
return [
739-
[
740-
'$["test\uZZZZ"]',
741-
],
742-
[
743-
'$["test\u123"]',
744-
],
745-
[
746-
'$["test\u"]',
747-
],
748-
];
749-
}
750-
751724
/**
752725
* @dataProvider provideComplexUnicodePath
753726
*/

src/Symfony/Component/JsonPath/Tests/JsonPathComplianceTestSuiteTest.php

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -148,30 +148,6 @@ final class JsonPathComplianceTestSuiteTest extends TestCase
148148
'index selector, leading 0',
149149
'index selector, -0',
150150
'index selector, leading -0',
151-
'name selector, double quotes, escaped line feed',
152-
'name selector, double quotes, invalid escaped single quote',
153-
'name selector, double quotes, question mark escape',
154-
'name selector, double quotes, bell escape',
155-
'name selector, double quotes, vertical tab escape',
156-
'name selector, double quotes, 0 escape',
157-
'name selector, double quotes, x escape',
158-
'name selector, double quotes, n escape',
159-
'name selector, double quotes, unicode escape no hex',
160-
'name selector, double quotes, unicode escape too few hex',
161-
'name selector, double quotes, unicode escape upper u',
162-
'name selector, double quotes, unicode escape upper u long',
163-
'name selector, double quotes, unicode escape plus',
164-
'name selector, double quotes, unicode escape brackets',
165-
'name selector, double quotes, unicode escape brackets long',
166-
'name selector, double quotes, single high surrogate',
167-
'name selector, double quotes, single low surrogate',
168-
'name selector, double quotes, high high surrogate',
169-
'name selector, double quotes, low low surrogate',
170-
'name selector, double quotes, supplementary surrogate',
171-
'name selector, double quotes, surrogate incomplete low',
172-
'name selector, single quotes, escaped backspace',
173-
'name selector, single quotes, escaped line feed',
174-
'name selector, single quotes, invalid escaped double quote',
175151
'slice selector, excessively large from value with negative step',
176152
'slice selector, step, min exact - 1',
177153
'slice selector, step, max exact + 1',

0 commit comments

Comments
 (0)