From 4bb15d3fab53b406a22e618f6e5f0b7b357eb84b Mon Sep 17 00:00:00 2001 From: Klemen Tusar Date: Wed, 20 Aug 2025 07:04:53 +0100 Subject: [PATCH 1/3] :bug: protect encoded dots in keys during decoding when decodeDotInKeys is false --- lib/src/extensions/decode.dart | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/lib/src/extensions/decode.dart b/lib/src/extensions/decode.dart index 764686c..0d3519f 100644 --- a/lib/src/extensions/decode.dart +++ b/lib/src/extensions/decode.dart @@ -147,10 +147,26 @@ extension _$Decode on QS { dynamic val; // Bare key without '=', interpret as null vs empty-string per strictNullHandling. if (pos == -1) { - key = options.decoder(part, charset: charset); + // Protect %2E/%2e in keys so dot-splitting doesn’t see them unless decodeDotInKeys is true. + String keyInput = part; + if (options.allowDots && + !options.decodeDotInKeys && + keyInput.contains('%2')) { + keyInput = + keyInput.replaceAll('%2E', '%252E').replaceAll('%2e', '%252e'); + } + key = options.decoder(keyInput, charset: charset); val = options.strictNullHandling ? null : ''; } else { - key = options.decoder(part.slice(0, pos), charset: charset); + // Protect %2E/%2e in the key slice only; values decode normally. + String keyInput = part.slice(0, pos); + if (options.allowDots && + !options.decodeDotInKeys && + keyInput.contains('%2')) { + keyInput = + keyInput.replaceAll('%2E', '%252E').replaceAll('%2e', '%252e'); + } + key = options.decoder(keyInput, charset: charset); // Decode the substring *after* '=', applying list parsing and the configured decoder. val = Utils.apply( _parseListValue( From f674ad72be9b38e7bc3aed8a7f8c9c8986d82a61 Mon Sep 17 00:00:00 2001 From: Klemen Tusar Date: Wed, 20 Aug 2025 07:11:52 +0100 Subject: [PATCH 2/3] :bug: handle lowercase '%2e' when decoding dots in keys and adjust dot allowance logic --- lib/src/extensions/decode.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/src/extensions/decode.dart b/lib/src/extensions/decode.dart index 0d3519f..5ed8237 100644 --- a/lib/src/extensions/decode.dart +++ b/lib/src/extensions/decode.dart @@ -273,7 +273,7 @@ extension _$Decode on QS { ? root.slice(1, root.length - 1) : root; final String decodedRoot = options.decodeDotInKeys - ? cleanRoot.replaceAll('%2E', '.') + ? cleanRoot.replaceAll('%2E', '.').replaceAll('%2e', '.') : cleanRoot; final int? index = int.tryParse(decodedRoot); if (!options.parseLists && decodedRoot == '') { @@ -316,7 +316,7 @@ extension _$Decode on QS { final segments = _splitKeyIntoSegments( originalKey: givenKey, - allowDots: options.allowDots, + allowDots: options.allowDots || options.decodeDotInKeys, maxDepth: options.depth, strictDepth: options.strictDepth, ); From e2b734d261de92de12012603b5d080b648ead1e0 Mon Sep 17 00:00:00 2001 From: Klemen Tusar Date: Wed, 20 Aug 2025 07:22:46 +0100 Subject: [PATCH 3/3] :bug: always protect encoded dots in keys from dot-splitting regardless of decodeDotInKeys option --- lib/src/extensions/decode.dart | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/lib/src/extensions/decode.dart b/lib/src/extensions/decode.dart index 5ed8237..188f19c 100644 --- a/lib/src/extensions/decode.dart +++ b/lib/src/extensions/decode.dart @@ -147,11 +147,9 @@ extension _$Decode on QS { dynamic val; // Bare key without '=', interpret as null vs empty-string per strictNullHandling. if (pos == -1) { - // Protect %2E/%2e in keys so dot-splitting doesn’t see them unless decodeDotInKeys is true. + // Protect %2E/%2e in keys so dot-splitting never sees them as literal dots. String keyInput = part; - if (options.allowDots && - !options.decodeDotInKeys && - keyInput.contains('%2')) { + if (options.allowDots && keyInput.contains('%2')) { keyInput = keyInput.replaceAll('%2E', '%252E').replaceAll('%2e', '%252e'); } @@ -160,9 +158,7 @@ extension _$Decode on QS { } else { // Protect %2E/%2e in the key slice only; values decode normally. String keyInput = part.slice(0, pos); - if (options.allowDots && - !options.decodeDotInKeys && - keyInput.contains('%2')) { + if (options.allowDots && keyInput.contains('%2')) { keyInput = keyInput.replaceAll('%2E', '%252E').replaceAll('%2e', '%252e'); } @@ -316,7 +312,7 @@ extension _$Decode on QS { final segments = _splitKeyIntoSegments( originalKey: givenKey, - allowDots: options.allowDots || options.decodeDotInKeys, + allowDots: options.allowDots, maxDepth: options.depth, strictDepth: options.strictDepth, );