8000 script: initial CookieStore implementation by sebsebmc · Pull Request #37968 · servo/servo · GitHub
[go: up one dir, main page]

Skip to content

Conversation

sebsebmc
Copy link
Contributor
@sebsebmc sebsebmc commented Jul 9, 2025

This is a first draft at implementing the required infrastructure for CookieStore, which requires setting up IPC between script and the resource thread to allow for async/"in parallel" handling of cookie changes that have a promise API.

Cookie Store also will need to receive change events when cookies for a url are changed so the architecture needs to support that.

Expect this PR to be reworked once the architecture becomes more settled, cookie change events will be implemented in follow up PRs

Testing: WPT tests exist for this API
Part of #37674

DeleteCookies(ServoUrl),
DeleteCookie(ServoUrl, String),
DeleteCookieAsync(CookieStoreId, CookieRequestId, ServoUrl, String),
NewCookieListener(CookieStoreId, IpcSender<CookieAsyncResponse>, ServoUrl),
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For lifecycle management I believe I will also need a RemoveCookieListener message for when a global navigates to a new page. The spec makes clear that CookieStore's relevant URL is the global's creation_url.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes that sounds like a good idea.

Copy link
Member
@gterzian gterzian Aug 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you currently sending that message? I think it could be done on drop of the global.

EDIT: drop of the cookiestore.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I noticed that I forgot to wire this up yesterday. I'll look at adding this to the drop

Copy link
Member
@gterzian gterzian left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great so far, thank you.

How do you want to scope this PR?

// 1. Perform the steps defined in Cookies § Retrieval Model to compute the "cookie-string from a given cookie
// store" with url as request-uri. The cookie-string itself is ignored, but the intermediate cookie-list is
// used in subsequent steps.
// For the purposes of the steps, the cookie-string is being generated for a "non-HTTP" API.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This also belongs in resource threads, and instead I would just document the method with a note on sending a message to run the "in-parallel" steps.

.or_init(|| Storage::new(self, StorageType::Local, CanGc::note()))
}

// https://wicg.github.io/cookie-store/
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The correct link is https://wicg.github.io/cookie-store/#dom-window-cookiestore(and format is wrong also).

DeleteCookies(ServoUrl),
DeleteCookie(ServoUrl, String),
DeleteCookieAsync(CookieStoreId, CookieRequestId, ServoUrl, String),
NewCookieListener(CookieStoreId, IpcSender<CookieAsyncResponse>, ServoUrl),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes that sounds like a good idea.

@sebsebmc
Copy link
Contributor Author

How do you want to scope this PR?

I think the goal for this PR is going to be setting up the infrastructure needed to be able to do the most minimal Set-Get-Delete implementation. The change event listener is definitely going to be in a follow up

@gterzian
Copy link
Member

I think the goal for this PR is

Sounds good.

@sebsebmc sebsebmc changed the title wip: cookiestore: setup basics script: initial CookieStore implementation Aug 1, 2025
@sebsebmc
Copy link
Contributor Author

@gterzian @jdm I don't want to make this PR too much larger, I think this is ready for the next round of review.

Copy link
Member
@gterzian gterzian left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some initial commend; I'll take another look later today.

}

// https://cookiestore.spec.whatwg.org/#Window
fn CookieStore(&self) -> DomRoot<CookieStore> {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here you can pass a can_gc argument using Bindings.conf.

self.store_id,
global.creation_url().clone(),
options.name.to_string(),
));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here and elsewhere you could log an error if the send fails. In theory it never should.

creation_url.clone(),
Serde(cookie.build()),
NonHTTP,
));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it fails you probably want to. remove the inflight promise as well, and reject it with an error.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, yeah probably just going to make a small helper for this then. I wish there was a nice way to make this a type/lifetime error somehow.

p.reject_error(Error::Security, can_gc);
return p;
}
// 4. Let url be settings’s creation URL.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: I always add a line between the last line of code and the next comment.

fn cookie_to_list_item(cookie: Cookie) -> CookieListItem {
CookieListItem {
// Let domain be the result of running UTF-8 decode without BOM on cookie’s domain.
domain: cookie
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should add a TODO to actually call into UTF-8 decode without BOM

);
return;
}
let _ = sender.unwrap().send(CookieAsyncResponse { data });
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's nicer to do a Let Some() = else

Copy link
Member
@gterzian gterzian left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good overall, thank you. I might spend some time looking at the spec again and into some things mentioned below, in the meantime let's address the current comments.

.collect_vec(),
CanGc::note());
},
_ => {promise.resolve_native(&(), CanGc::note());}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's better yo be explicit here.

}

struct CookieListener {
task_source: SendableTaskSource,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's document which task source this is, and add a link to the spec is such an appropriate link exists

DeleteCookies(ServoUrl),
DeleteCookie(ServoUrl, String),
DeleteCookieAsync(CookieStoreId, CookieRequestId, ServoUrl, String),
NewCookieListener(CookieStoreId, IpcSender<CookieAsyncResponse>, ServoUrl),
Copy link
Member
@gterzian gterzian Aug 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you currently sending that message? I think it could be done on drop of the global.

EDIT: drop of the cookiestore.

.send(CoreResourceMsg::GetCookieDataForUrlAsync(
self.store_id,
creation_url.clone(),
Some(name.to_string()),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: I'm not quite sure how to make this work with the decoding that happens later in parallel. Should we do the decoding before turning it into a string, which means decoding it here, or can we do it later on the string in parallel. But rust strings are already utf8 I believe. Needs some looking into. Any relevant tests failing at this point?

52F5

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe the only encoding/decoding tests that exist are checking if we strip the BOM from the name and we currently pass the test. (We don't strip it)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's some UTF8 encoding checks in the tests for the cookie change events, which we haven't implemented at all.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I guess we can then leave it as it, and revisit when the others parts are implemented.

Copy link
Member
@gterzian gterzian left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM with one nit; thank you.

Some(name.to_string()),
));
if res.is_err() {
self.in_flight.borrow_mut().pop_back();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would it's simpler to only push it back if the send is ok.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I do like that a bit more, since now the pattern is consistent about pushing back if we send a message. Now anytime we send a message we always have a pattern to check to make sure we also stored a promise.

Signed-off-by: Sebastian C <sebsebmc@gmail.com>
Signed-off-by: Sebastian C <sebsebmc@gmail.com>
Signed-off-by: Sebastian C <sebsebmc@gmail.com>
Signed-off-by: Sebastian C <sebsebmc@gmail.com>
Signed-off-by: Sebastian C <sebsebmc@gmail.com>
Signed-off-by: Sebastian C <sebsebmc@gmail.com>
Signed-off-by: Sebastian C <sebsebmc@gmail.com>
Signed-off-by: Sebastian C <sebsebmc@gmail.com>
Signed-off-by: Sebastian C <sebsebmc@gmail.com>
Signed-off-by: Sebastian C <sebsebmc@gmail.com>
Signed-off-by: Sebastian C <sebsebmc@gmail.com>
@sebsebmc sebsebmc marked this pull request as ready for review August 20, 2025 18:38
@gterzian gterzian added this pull request to the merge queue Aug 20, 2025
@github-merge-queue github-merge-queue bot removed this pull request from the merge queue due to failed status checks Aug 20, 2025
@sebsebmc
Copy link
Contributor Author

Not sure what happened there, is that just a flake on the MacOS runner?

@jdm
Copy link
Member
jdm commented Aug 21, 2025
  cargo:warning=fatal error: /Applications/Xcode_16.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ranlib: can't write to output file (Input/output error)
  cargo:warning=/Applications/Xcode_16.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ar: internal ranlib command failed

Wild. Never seen that before! Let's try again.

@jdm jdm added this pull request to the merge queue Aug 21, 2025
Merged via the queue into servo:main with commit b869b7e Aug 21, 2025
23 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants
0