blob: 780bb446b811295a7e717b224fa2c66e56b6f69a [file] [log] [blame]
// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
/// "token" as defined in RFC 2616, 2.2
/// See https://datatracker.ietf.org/doc/html/rfc2616#section-2.2
const _tokenChars = r"!#$%&'*+\-.0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ^_`"
'abcdefghijklmnopqrstuvwxyz|~';
/// Splits comma-separated header values.
var _headerSplitter = RegExp(r'[ \t]*,[ \t]*');
/// Splits comma-separated "Set-Cookie" header values.
///
/// Set-Cookie strings can contain commas. In particular, the following
/// productions defined in RFC-6265, section 4.1.1:
/// - `<sane-cookie-date>` e.g. "Expires=Sun, 06 Nov 1994 08:49:37 GMT"
/// - `<path-value>` e.g. "Path=somepath,"
/// - `<extension-av>` e.g. "AnyString,Really,"
///
/// Some values are ambiguous e.g.
/// "Set-Cookie: lang=en; Path=/foo/"
/// "Set-Cookie: SID=x23"
/// and:
/// "Set-Cookie: lang=en; Path=/foo/,SID=x23"
/// would both be result in `response.headers` => "lang=en; Path=/foo/,SID=x23"
///
/// The idea behind this regex is that `,<valid token>=` is more likely to
/// start a new `<cookie-pair>` than be part of `<path-value>` or
/// `<extension-av>`.
///
/// See https://datatracker.ietf.org/doc/html/rfc6265#section-4.1.1
var _setCookieSplitter = RegExp(r'[ \t]*,[ \t]*(?=[' + _tokenChars + r']+=)');
/// Splits comma-separated header values into a [List].
///
/// Copied from `package:http`.
Map<String, List<String>> splitHeaderValues(Map<String, String> headers) {
var headersWithFieldLists = <String, List<String>>{};
headers.forEach((key, value) {
if (!value.contains(',')) {
headersWithFieldLists[key] = [value];
} else {
if (key == 'set-cookie') {
headersWithFieldLists[key] = value.split(_setCookieSplitter);
} else {
headersWithFieldLists[key] = value.split(_headerSplitter);
}
}
});
return headersWithFieldLists;
}