Skip to content

Commit da30001

Browse files
committed
Use _encodeStringElement for string encoding
Replace direct Uri.encodeComponent calls with a centralized _encodeStringElement in QueryBuilder string-handling methods (whereStartsWith, whereEqualTo, whereNotEqualTo, whereContains, and search) to ensure quotes and backslashes are JSON-escaped correctly when building queries. Add a unit test to verify percent-encoded sequences (%5C%22 and %5C%5C) appear in the built query and that raw `"`/`\` do not, preventing invalid JSON after server URL-decoding.
1 parent 923c81f commit da30001

2 files changed

Lines changed: 30 additions & 6 deletions

File tree

packages/dart/lib/src/network/parse_query.dart

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ class QueryBuilder<T extends ParseObject> {
129129
String prefix, {
130130
bool caseSensitive = false,
131131
}) {
132-
prefix = Uri.encodeComponent(prefix);
132+
prefix = _encodeStringElement(prefix);
133133

134134
if (caseSensitive) {
135135
queries.add(
@@ -155,7 +155,7 @@ class QueryBuilder<T extends ParseObject> {
155155
String prefix, {
156156
bool caseSensitive = false,
157157
}) {
158-
prefix = Uri.encodeComponent(prefix);
158+
prefix = _encodeStringElement(prefix);
159159

160160
if (caseSensitive) {
161161
queries.add(
@@ -178,7 +178,7 @@ class QueryBuilder<T extends ParseObject> {
178178
/// to be equal to the provided [value]
179179
void whereEqualTo(String column, dynamic value) {
180180
if (value is String) {
181-
value = Uri.encodeComponent(value);
181+
value = _encodeStringElement(value);
182182
}
183183

184184
queries.add(
@@ -237,7 +237,7 @@ class QueryBuilder<T extends ParseObject> {
237237
/// to be not equal to the provided [value]
238238
void whereNotEqualTo(String column, dynamic value) {
239239
if (value is String) {
240-
value = Uri.encodeComponent(value);
240+
value = _encodeStringElement(value);
241241
}
242242

243243
queries.add(
@@ -356,7 +356,7 @@ class QueryBuilder<T extends ParseObject> {
356356
String substring, {
357357
bool caseSensitive = false,
358358
}) {
359-
substring = Uri.encodeComponent(substring);
359+
substring = _encodeStringElement(substring);
360360

361361
if (caseSensitive) {
362362
queries.add(
@@ -385,7 +385,7 @@ class QueryBuilder<T extends ParseObject> {
385385
bool orderByScore = true,
386386
bool diacriticSensitive = false,
387387
}) {
388-
searchTerm = Uri.encodeComponent(searchTerm);
388+
searchTerm = _encodeStringElement(searchTerm);
389389

390390
queries.add(
391391
MapEntry<String, dynamic>(

packages/dart/test/src/network/parse_query_test.dart

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -757,5 +757,29 @@ void main() {
757757
final queryString = queryBuilder.buildQuery();
758758
expect(queryString, contains('"\$in":[1,2,3]'));
759759
});
760+
761+
test(
762+
'scalar where methods JSON-escape quotes and backslashes in String values',
763+
() {
764+
final queryBuilder = QueryBuilder.name('Diet_Plans');
765+
766+
queryBuilder.whereEqualTo('title', 'He said "hi"');
767+
queryBuilder.whereNotEqualTo('note', r'C:\path');
768+
queryBuilder.whereStartsWith('name', 'quote"prefix');
769+
queryBuilder.whereContains('body', r'back\slash');
770+
771+
final queryString = queryBuilder.buildQuery();
772+
773+
// `"` and `\` must come through percent-encoded as `\"` / `\\` so the
774+
// JSON stays valid after the server URL-decodes the query.
775+
expect(queryString, contains('%5C%22'));
776+
expect(queryString, contains('%5C%5C'));
777+
778+
// Raw `"` and `\` inside the values would break JSON parsing.
779+
expect(queryString.contains('"He said "hi""'), isFalse);
780+
expect(queryString.contains(r'C:\path'), isFalse);
781+
expect(queryString.contains('quote"prefix'), isFalse);
782+
expect(queryString.contains(r'back\slash'), isFalse);
783+
});
760784
});
761785
}

0 commit comments

Comments
 (0)