Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit df95340

Browse files
sortiecommit-bot@chromium.org
authored andcommitted
[dart:_http] Fix parsing of empty cookies and double quotes.
Commit a9ad427 introduced a bug that assumed the cookie value was at least one character, but the cookie value can also be empty. RFC 6265 5.2 does not specify any special behavior for double quotes and as such they should be considered part of the value. This change stops stripping those double quotes and instead preserves them. The io/http_cookie_test test was skipped because it was considered flaky. This change dusts it off and tests the new behavior. This change adds the exact offsets and source to the FormatExceptions to help the caller understand why a malformed cookie was rejected. Fixes dart-lang/sdk#33327 Fixes dart-lang/sdk#35804 Change-Id: I3479ba48be5763c485bd3ca5b5d2d86d283df971 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/91221 Commit-Queue: Jonas Termansen <[email protected]> Reviewed-by: Zach Anderson <[email protected]> Reviewed-by: William Hesse <[email protected]>
1 parent b316210 commit df95340

File tree

4 files changed

+49
-13
lines changed

4 files changed

+49
-13
lines changed

CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,15 @@
66

77
### Core library
88

9+
#### `dart:io`
10+
11+
* Fixed `Cookie` class interoperability with certain websites by allowing the
12+
cookie values to be the empty string (Issue [35804][]) and not stripping
13+
double quotes from the value (Issue [33327][]) in accordance with RFC 6265.
14+
15+
[33327]: https://github.com/dart-lang/sdk/issues/33327
16+
[35804]: https://github.com/dart-lang/sdk/issues/35804
17+
918
### Dart VM
1019

1120
### Tools

sdk/lib/_http/http_headers.dart

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -982,22 +982,34 @@ class _Cookie implements Cookie {
982982
codeUnit >= 127 ||
983983
separators.indexOf(name[i]) >= 0) {
984984
throw new FormatException(
985-
"Invalid character in cookie name, code unit: '$codeUnit'");
985+
"Invalid character in cookie name, code unit: '$codeUnit'",
986+
name,
987+
i);
986988
}
987989
}
988990

989-
if (value[0] == '"' && value[value.length - 1] == '"') {
990-
value = value.substring(1, value.length - 1);
991+
// Per RFC 6265, consider surrounding "" as part of the value, but otherwise
992+
// double quotes are not allowed.
993+
int start = 0;
994+
int end = value.length;
995+
if (2 <= value.length &&
996+
value.codeUnits[start] == 0x22 &&
997+
value.codeUnits[end - 1] == 0x22) {
998+
start++;
999+
end--;
9911000
}
992-
for (int i = 0; i < value.length; i++) {
1001+
1002+
for (int i = start; i < end; i++) {
9931003
int codeUnit = value.codeUnits[i];
9941004
if (!(codeUnit == 0x21 ||
9951005
(codeUnit >= 0x23 && codeUnit <= 0x2B) ||
9961006
(codeUnit >= 0x2D && codeUnit <= 0x3A) ||
9971007
(codeUnit >= 0x3C && codeUnit <= 0x5B) ||
9981008
(codeUnit >= 0x5D && codeUnit <= 0x7E))) {
9991009
throw new FormatException(
1000-
"Invalid character in cookie value, code unit: '$codeUnit'");
1010+
"Invalid character in cookie value, code unit: '$codeUnit'",
1011+
value,
1012+
i);
10011013
}
10021014
}
10031015
}

tests/standalone_2/io/http_cookie_test.dart

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
// for details. All rights reserved. Use of this source code is governed by a
33
// BSD-style license that can be found in the LICENSE file.
44

5-
import "dart:async";
65
import "dart:io";
6+
77
import "package:expect/expect.dart";
88

99
void testCookies() {
@@ -59,12 +59,28 @@ void testCookies() {
5959
}
6060

6161
void testValidateCookieWithDoubleQuotes() {
62-
try {
63-
Cookie cookie = Cookie('key', '"double-quoted-value"');
64-
} catch (e) {
65-
Expect.fail("Unexpected error $e.\n"
66-
"Unable to parse cookie with value in double-quote characters.");
67-
}
62+
Expect.equals(Cookie('key', 'value').toString(), 'key=value; HttpOnly');
63+
Expect.equals(Cookie('key', '').toString(), 'key=; HttpOnly');
64+
Expect.equals(Cookie('key', '""').toString(), 'key=""; HttpOnly');
65+
Expect.equals(Cookie('key', '"value"').toString(), 'key="value"; HttpOnly');
66+
Expect.equals(Cookie.fromSetCookieValue('key=value; HttpOnly').toString(),
67+
'key=value; HttpOnly');
68+
Expect.equals(
69+
Cookie.fromSetCookieValue('key=; HttpOnly').toString(), 'key=; HttpOnly');
70+
Expect.equals(Cookie.fromSetCookieValue('key=""; HttpOnly').toString(),
71+
'key=""; HttpOnly');
72+
Expect.equals(Cookie.fromSetCookieValue('key="value"; HttpOnly').toString(),
73+
'key="value"; HttpOnly');
74+
Expect.throwsFormatException(() => Cookie('key', '"'));
75+
Expect.throwsFormatException(() => Cookie('key', '"""'));
76+
Expect.throwsFormatException(() => Cookie('key', '"x""'));
77+
Expect.throwsFormatException(() => Cookie('key', '"x"y"'));
78+
Expect.throwsFormatException(
79+
() => Cookie.fromSetCookieValue('key="; HttpOnly'));
80+
Expect.throwsFormatException(
81+
() => Cookie.fromSetCookieValue('key="""; HttpOnly'));
82+
Expect.throwsFormatException(
83+
() => Cookie.fromSetCookieValue('key="x""; HttpOnly'));
6884
}
6985

7086
void main() {

tests/standalone_2/standalone_2_kernel.status

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,6 @@ io/file_fuzz_test: RuntimeError, Pass
106106
io/http_client_connect_test: Skip # Flaky.
107107
io/http_close_test: Crash
108108
io/http_content_length_test: Skip # Flaky.
109-
io/http_cookie_test: Skip # Flaky
110109
io/http_proxy_advanced_test: Skip # Flaky
111110
io/http_proxy_test: Skip # Flaky.
112111
io/http_response_deadline_test: Skip # Flaky.

0 commit comments

Comments
 (0)