Refactor and document cookie-list retrieval (#38070)

This refactors some of the cookie retrieval mechanism to be less
repetitive and separates the cookie-list from the cookie-string which
will also be needed for Cookie Store.

Testing: No new behavior, should be covered by existing WPT tests.

Signed-off-by: Sebastian C <sebsebmc@gmail.com>
This commit is contained in:
Sebastian C 2025-07-14 17:15:27 -05:00 committed by GitHub
parent 6ea7638c21
commit f13311a00e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 43 additions and 30 deletions

View file

@ -10,7 +10,9 @@ use std::collections::HashMap;
use std::collections::hash_map::Entry;
use std::time::SystemTime;
use log::{debug, info};
use cookie::Cookie;
use itertools::Itertools;
use log::info;
use net_traits::CookieSource;
use net_traits::pub_domains::reg_suffix;
use serde::{Deserialize, Serialize};
@ -175,41 +177,26 @@ impl CookieStorage {
// http://tools.ietf.org/html/rfc6265#section-5.4
pub fn cookies_for_url(&mut self, url: &ServoUrl, source: CookieSource) -> Option<String> {
let filterer = |c: &&mut ServoCookie| -> bool {
debug!(
" === SENT COOKIE : {} {} {:?} {:?}",
c.cookie.name(),
c.cookie.value(),
c.cookie.domain(),
c.cookie.path()
);
debug!(
" === SENT COOKIE RESULT {}",
c.appropriate_for_url(url, source)
);
// Step 1
c.appropriate_for_url(url, source)
};
// Step 2
let domain = reg_host(url.host_str().unwrap_or(""));
let cookies = self.cookies_map.entry(domain).or_default();
// Let cookie-list be the set of cookies from the cookie store
let cookie_list = self.cookies_data_for_url(url, source);
let mut url_cookies: Vec<&mut ServoCookie> = cookies.iter_mut().filter(filterer).collect();
url_cookies.sort_by(|a, b| CookieStorage::cookie_comparator(a, b));
let reducer = |acc: String, c: &mut &mut ServoCookie| -> String {
// Step 3
c.touch();
// Step 4
let reducer = |acc: String, cookie: Cookie<'static>| -> String {
// Serialize the cookie-list into a cookie-string by processing each cookie in the cookie-list in order:
// If the cookies' name is not empty, output the cookie's name followed by the %x3D ("=") character.
// If the cookies' value is not empty, output the cookie's value.
// If there is an unprocessed cookie in the cookie-list, output the characters %x3B and %x20 ("; ").
// Security: the above steps allow for "nameless" cookies which have proved to be a security footgun
// especially with the new cookie name prefix proposals
(match acc.len() {
0 => acc,
_ => acc + "; ",
}) + c.cookie.name() +
}) + cookie.name() +
"=" +
c.cookie.value()
cookie.value()
};
let result = url_cookies.iter_mut().fold("".to_owned(), reducer);
// Serialize the cookie-list into a cookie-string by processing each cookie in the cookie-list in order
let result = cookie_list.fold("".to_owned(), reducer);
info!(" === COOKIES SENT: {}", result);
match result.len() {
@ -229,7 +216,12 @@ impl CookieStorage {
cookies
.iter_mut()
.filter(move |c| c.appropriate_for_url(url, source))
.sorted_by(|a: &&mut ServoCookie, b: &&mut ServoCookie| {
// The user agent SHOULD sort the cookie-list
CookieStorage::cookie_comparator(a, b)
})
.map(|c| {
// Update the last-access-time of each cookie in the cookie-list to the current date and time
c.touch();
c.cookie.clone()
})