1 // Copyright 2024 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "net/http/http_cookie_indices.h"
6
7 #include "net/cookies/parsed_cookie.h"
8 #include "net/http/http_response_headers.h"
9 #include "net/http/structured_headers.h"
10
11 namespace net {
12
13 namespace {
14 constexpr std::string_view kCookieIndicesHeader = "Cookie-Indices";
15 } // namespace
16
ParseCookieIndices(const HttpResponseHeaders & headers)17 std::optional<std::vector<std::string>> ParseCookieIndices(
18 const HttpResponseHeaders& headers) {
19 std::string normalized_header;
20 if (!headers.GetNormalizedHeader(kCookieIndicesHeader, &normalized_header)) {
21 return std::nullopt;
22 }
23
24 std::optional<net::structured_headers::List> list =
25 structured_headers::ParseList(normalized_header);
26 if (!list.has_value()) {
27 return std::nullopt;
28 }
29
30 std::vector<std::string> cookie_names;
31 cookie_names.reserve(list->size());
32 for (const structured_headers::ParameterizedMember& member : *list) {
33 if (member.member_is_inner_list) {
34 // Inner list not permitted here.
35 return std::nullopt;
36 }
37
38 const structured_headers::ParameterizedItem& item = member.member[0];
39 if (!item.item.is_string()) {
40 // Non-string items are not permitted here.
41 return std::nullopt;
42 }
43
44 // There are basically three sets of requirements that are interesting here.
45 //
46 // 1. Cookie names Chromium considers valid, given by:
47 // cookie-name = *cookie-name-octet
48 // cookie-name-octet = %x20-3A / %x3C / %x3E-7E / %x80-FF
49 // ; octets excluding CTLs, ";", and "="
50 // See |net::ParsedCookie::IsValidCookieName|.
51 //
52 // 2. Cookie names RFC 6265 considers valid, given by:
53 // cookie-name = token
54 // token = 1*<any CHAR except CTLs or separators>
55 // separators = "(" | ")" | "<" | ">" | "@"
56 // | "," | ";" | ":" | "\" | <">
57 // | "/" | "[" | "]" | "?" | "="
58 // | "{" | "}" | SP | HT
59 // CHAR = <any US-ASCII character (octets 0 - 127)>
60 // CTL = <any US-ASCII control character
61 // (octets 0 - 31) and DEL (127)>
62 //
63 // 3. Valid RFC 8941 structured field strings, whose values are given by:
64 // string-value = *( %x20-7E )
65 //
66 // While all RFC 6265 valid cookie names are valid structured field strings,
67 // Chromium accepts cookies whose names can nonetheless not be spelled here.
68 // For example, cookie names outside 7-bit ASCII cannot be specified.
69 //
70 // Nor is every structured field string a valid cookie name, since it may
71 // contain a ";" or "=" character (or several other characters excluded by
72 // RFC 6265 in addition to Chromium). In the interest of interoperability,
73 // those are expressly rejected.
74 const std::string& name = item.item.GetString();
75 if (name.find_first_of("()<>@,;:\\\"/[]?={} \t") != std::string::npos) {
76 // This is one of those structured field strings that is not a valid
77 // cookie name according to RFC 6265.
78 // TODO(crbug.com/328628231): Watch mnot/I-D#346 to see if a different
79 // behavior is agreed on.
80 continue;
81 }
82 CHECK(ParsedCookie::IsValidCookieName(name))
83 << "invalid cookie name \"" << name << "\"";
84 cookie_names.push_back(name);
85 }
86 return cookie_names;
87 }
88
89 } // namespace net
90