| // 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; |
| } |