Skip to content

[JsonPath] Improve escape sequence validation in name selector #60802

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: 7.3
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 27 additions & 1 deletion src/Symfony/Component/JsonPath/JsonPathUtils.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
namespace Symfony\Component\JsonPath;

use Symfony\Component\JsonPath\Exception\InvalidArgumentException;
use Symfony\Component\JsonPath\Exception\JsonCrawlerException;
use Symfony\Component\JsonPath\Tokenizer\JsonPathToken;
use Symfony\Component\JsonPath\Tokenizer\TokenType;
use Symfony\Component\JsonStreamer\Read\Splitter;
Expand Down Expand Up @@ -86,8 +87,13 @@ public static function findSmallestDeserializableStringAndPath(array $tokens, mi
];
}

/**
* @throws JsonCrawlerException When an invalid Unicode escape sequence occurs
*/
public static function unescapeString(string $str, string $quoteChar): string
{
self::validateEscapeSequences($str, $quoteChar);

if ('"' === $quoteChar) {
// try JSON decoding first for unicode sequences
$jsonStr = '"'.$str.'"';
Expand All @@ -108,7 +114,7 @@ public static function unescapeString(string $str, string $quoteChar): string
"'" => "'",
'\\' => '\\',
'/' => '/',
'b' => "\b",
'b' => "\x08",
'f' => "\f",
'n' => "\n",
'r' => "\r",
Expand Down Expand Up @@ -227,4 +233,24 @@ public static function parseCommaSeparatedValues(string $expr): array

return $parts;
}

private static function validateEscapeSequences(string $str, string $quoteChar): void
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would it make sense to merge the new loop with the existing one? can we do everything in one pass?

{
$i = -1;
while (null !== $char = $str[++$i] ?? null) {
if ('\\' !== $char || !isset($str[$i + 1])) {
continue;
}

if (!\in_array($next = $str[$i + 1], [$quoteChar, '\\', '/', 'b', 'f', 'n', 'r', 't', 'u'], true)) {
throw new JsonCrawlerException('', \sprintf('Invalid escape sequence "\\%s" in %s-quoted string', $next, "'" === $quoteChar ? 'single' : 'double'));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm quite sure this case could be detected during the unescaping loop, as this exception corresponds to the default => $char.$str[$i + 1], // keep the backslash branch in the match, which could become a throwing branch.

}

if ('u' === $next && (!isset($str[$i + 5]) || !ctype_xdigit(substr($str, $i + 2, 4)))) {
throw new JsonCrawlerException('', 'Invalid unicode escape sequence');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unescapeUnicodeSequence could be responsible for this validation instead of treating invalid sequences as literal (which would become dead code if we validate in a previous loop)

}

++$i;
}
}
}
31 changes: 2 additions & 29 deletions src/Symfony/Component/JsonPath/Tests/JsonCrawlerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ public function testEscapedDoubleQuotesInFieldName()
{"a": {"b\\"c": 42}}
JSON);

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

$this->assertSame(42, $result[0]);
}
Expand Down Expand Up @@ -641,10 +641,6 @@ public static function provideSingleQuotedStringProvider(): array
"$['\\u65e5\\u672c']",
['Japan'],
],
[
"$['quote\"here']",
['with quote'],
],
[
"$['M\\u00fcller']",
[],
Expand All @@ -658,7 +654,7 @@ public static function provideSingleQuotedStringProvider(): array
['with tab'],
],
[
"$['quote\\\"here']",
"$['quote\"here']",
['with quote'],
],
[
Expand Down Expand Up @@ -725,29 +721,6 @@ public static function provideFilterWithUnicodeProvider(): array
];
}

/**
* @dataProvider provideInvalidUnicodeSequenceProvider
*/
public function testInvalidUnicodeSequencesAreProcessedAsLiterals(string $jsonPath)
{
$this->assertIsArray(self::getUnicodeDocumentCrawler()->find($jsonPath), 'invalid unicode sequence should be treated as literal and not throw');
}

public static function provideInvalidUnicodeSequenceProvider(): array
{
return [
[
'$["test\uZZZZ"]',
],
[
'$["test\u123"]',
],
[
'$["test\u"]',
],
];
}

/**
* @dataProvider provideComplexUnicodePath
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,30 +148,6 @@ final class JsonPathComplianceTestSuiteTest extends TestCase
'index selector, leading 0',
'index selector, -0',
'index selector, leading -0',
'name selector, double quotes, escaped line feed',
'name selector, double quotes, invalid escaped single quote',
'name selector, double quotes, question mark escape',
'name selector, double quotes, bell escape',
'name selector, double quotes, vertical tab escape',
'name selector, double quotes, 0 escape',
'name selector, double quotes, x escape',
'name selector, double quotes, n escape',
'name selector, double quotes, unicode escape no hex',
'name selector, double quotes, unicode escape too few hex',
'name selector, double quotes, unicode escape upper u',
'name selector, double quotes, unicode escape upper u long',
'name selector, double quotes, unicode escape plus',
'name selector, double quotes, unicode escape brackets',
'name selector, double quotes, unicode escape brackets long',
'name selector, double quotes, single high surrogate',
'name selector, double quotes, single low surrogate',
'name selector, double quotes, high high surrogate',
'name selector, double quotes, low low surrogate',
'name selector, double quotes, supplementary surrogate',
'name selector, double quotes, surrogate incomplete low',
'name selector, single quotes, escaped backspace',
'name selector, single quotes, escaped line feed',
'name selector, single quotes, invalid escaped double quote',
'slice selector, excessively large from value with negative step',
'slice selector, step, min exact - 1',
'slice selector, step, max exact + 1',
Expand Down
Loading
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy