Skip to content

Commit c6e6405

Browse files
lrhnCommit Queue
authored andcommitted
Fix bug in HTTP header parameter value parsing.
The `preserveBackslash` flag should preserve backslashes before any non-`"` character, not before any non-`\` character. Change-Id: I3270f3b1b6c678e712e27a1cf4557558c883610b Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/452781 Reviewed-by: Nate Bosch <nbosch@google.com> Commit-Queue: Ivan Inozemtsev <iinozemtsev@google.com> Reviewed-by: Ivan Inozemtsev <iinozemtsev@google.com>
1 parent d4036a7 commit c6e6405

File tree

2 files changed

+61
-2
lines changed

2 files changed

+61
-2
lines changed

sdk/lib/_http/http_headers.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -851,7 +851,7 @@ class _HeaderValue implements HeaderValue {
851851
if (index < source.length) {
852852
char = source.codeUnitAt(index);
853853
index++;
854-
if (preserveBackslash && char != _CharCode.BACKSLASH) {
854+
if (preserveBackslash && char != _CharCode.QUOTE) {
855855
sb.writeCharCode(_CharCode.BACKSLASH);
856856
}
857857
sb.writeCharCode(char);

tests/standalone/io/http_headers_test.dart

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -820,7 +820,65 @@ void testForEach() {
820820
Expect.equals(4, totalValues);
821821
}
822822

823-
main() {
823+
void testPreserveBackslash() {
824+
// The `preserveBackslash` parameter of `HttpValue.parse` makes `\`s in
825+
// property values be retained, except if before a `"`.
826+
// (Is only allowed inside a `"..."`-quoted value.?)
827+
final _backslashRE = RegExp(r'\\.');
828+
829+
// Preserves every `\` escaping a non-`"` character.
830+
String preserve(Match m) {
831+
// Preserve entire `\.` match unless `.` is `"`.
832+
if (!m.input.startsWith('"', m.start + 1)) return m[0]!;
833+
return '"';
834+
}
835+
836+
// Preserves no escaping `\`.
837+
String remove(Match m) => m.input[m.start + 1];
838+
839+
for (var preserveBackslash in [false, true]) {
840+
void testInput(String input) {
841+
var headerValue = HeaderValue.parse(
842+
'value; name="$input"',
843+
preserveBackslash: preserveBackslash,
844+
);
845+
Expect.stringEquals(
846+
input.replaceAllMapped(
847+
_backslashRE,
848+
preserveBackslash ? preserve : remove,
849+
),
850+
headerValue.parameters['name']!,
851+
"$input (${preserveBackslash ? "preserved" : "removed"})",
852+
);
853+
}
854+
855+
testInput(r'\\');
856+
testInput(r'\"');
857+
testInput(r'\ ');
858+
testInput(r'text\ \a\"text');
859+
testInput(r'text\"\\\"');
860+
testInput(r'\"; abc=\\\"');
861+
862+
// An escaping `\` cannot be last character of an input.
863+
Expect.throws(
864+
() => HeaderValue.parse(r'value; name="abc\"'),
865+
null,
866+
"Trailing backslash (${preserveBackslash ? "preserved" : "removed"})",
867+
);
868+
869+
// Unquoted values do not treat backslash as escape,
870+
// and ignore `preserveBackslash`. Backslash is just a another valid
871+
// character and can occur anywhere until a terminator character.
872+
var input = r'abc\"\de\';
873+
Expect.stringEquals(
874+
input,
875+
HeaderValue.parse('value; name=$input').parameters['name']!,
876+
"Escaping in unquoted value (${preserveBackslash ? "preserved" : "removed"})",
877+
);
878+
}
879+
}
880+
881+
void main() {
824882
testMultiValue();
825883
testDate();
826884
testExpires();
@@ -843,4 +901,5 @@ main() {
843901
testLowercaseAdd();
844902
testLowercaseSet();
845903
testForEach();
904+
testPreserveBackslash();
846905
}

0 commit comments

Comments
 (0)