File: http_cookie_indices.cc

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (125 lines) | stat: -rw-r--r-- 4,598 bytes parent folder | download | duplicates (6)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "net/http/http_cookie_indices.h"

#include <algorithm>
#include <functional>

#include "base/containers/span.h"
#include "base/pickle.h"
#include "crypto/sha2.h"
#include "net/cookies/parsed_cookie.h"
#include "net/http/http_response_headers.h"
#include "net/http/structured_headers.h"

namespace net {

namespace {
constexpr std::string_view kCookieIndicesHeader = "Cookie-Indices";
}  // namespace

std::optional<std::vector<std::string>> ParseCookieIndices(
    const HttpResponseHeaders& headers) {
  std::optional<std::string> normalized_header =
      headers.GetNormalizedHeader(kCookieIndicesHeader);
  if (!normalized_header) {
    return std::nullopt;
  }

  std::optional<structured_headers::List> list =
      structured_headers::ParseList(*normalized_header);
  if (!list.has_value()) {
    return std::nullopt;
  }

  std::vector<std::string> cookie_names;
  cookie_names.reserve(list->size());
  for (const structured_headers::ParameterizedMember& member : *list) {
    if (member.member_is_inner_list) {
      // Inner list not permitted here.
      return std::nullopt;
    }

    const structured_headers::ParameterizedItem& item = member.member[0];
    if (!item.item.is_string()) {
      // Non-string items are not permitted here.
      return std::nullopt;
    }

    // There are basically three sets of requirements that are interesting here.
    //
    // 1. Cookie names Chromium considers valid, given by:
    //      cookie-name       = *cookie-name-octet
    //      cookie-name-octet = %x20-3A / %x3C / %x3E-7E / %x80-FF
    //                          ; octets excluding CTLs, ";", and "="
    //    See |ParsedCookie::IsValidCookieName|.
    //
    // 2. Cookie names RFC 6265 considers valid, given by:
    //      cookie-name = token
    //      token       = 1*<any CHAR except CTLs or separators>
    //      separators  = "(" | ")" | "<" | ">" | "@"
    //                  | "," | ";" | ":" | "\" | <">
    //                  | "/" | "[" | "]" | "?" | "="
    //                  | "{" | "}" | SP | HT
    //      CHAR        = <any US-ASCII character (octets 0 - 127)>
    //      CTL         = <any US-ASCII control character
    //                    (octets 0 - 31) and DEL (127)>
    //
    // 3. Valid RFC 8941 structured field strings, whose values are given by:
    //      string-value   = *( %x20-7E )
    //
    // While all RFC 6265 valid cookie names are valid structured field strings,
    // Chromium accepts cookies whose names can nonetheless not be spelled here.
    // For example, cookie names outside 7-bit ASCII cannot be specified.
    //
    // Nor is every structured field string a valid cookie name, since it may
    // contain a ";" or "=" character (or several other characters excluded by
    // RFC 6265 in addition to Chromium). In the interest of interoperability,
    // those are expressly rejected.
    const std::string& name = item.item.GetString();
    if (name.find_first_of("()<>@,;:\\\"/[]?={} \t") != std::string::npos) {
      // This is one of those structured field strings that is not a valid
      // cookie name according to RFC 6265.
      // TODO(crbug.com/328628231): Watch mnot/I-D#346 to see if a different
      // behavior is agreed on.
      continue;
    }
    CHECK(ParsedCookie::IsValidCookieName(name))
        << "invalid cookie name \"" << name << "\"";
    cookie_names.push_back(name);
  }
  return cookie_names;
}

CookieIndicesHash HashCookieIndices(
    base::span<const std::string> cookie_indices,
    base::span<const std::pair<std::string, std::string>> cookies) {
  CHECK(std::ranges::adjacent_find(cookie_indices, std::greater_equal<>()) ==
        cookie_indices.end())
      << "cookie indices must be sorted and unique";

  std::vector<std::pair<std::string_view, std::string_view>> cookies_sorted(
      cookies.begin(), cookies.end());
  std::ranges::sort(cookies_sorted);

  base::Pickle pickle;
  auto cookies_it = cookies_sorted.begin();
  for (const std::string& cookie_name : cookie_indices) {
    while (cookies_it != cookies_sorted.end() &&
           cookies_it->first < cookie_name) {
      ++cookies_it;
    }
    while (cookies_it != cookies_sorted.end() &&
           cookies_it->first == cookie_name) {
      pickle.WriteBool(true);
      pickle.WriteString(cookies_it->second);
      ++cookies_it;
    }
    pickle.WriteBool(false);
  }
  return crypto::SHA256Hash(pickle.payload_bytes());
}

}  // namespace net