net: Use RequestId to cancel fetches instead of creating an IPC channel (#34883)

Instead of creating an IPC channel for every fetch, allow cancelling
fetches based on the `RequestId` of the original request. This requires
that `RequestId`s be UUIDs so that they are unique between processes
that might communicating with the resource process.

In addition, the resource process loop now keeps a `HashMap` or `Weak`
handles to cancellers and cleans them up.

This allows for creating mutiple `FetchCanceller`s in `script` for a
single fetch request, allowing integration of the media and video
elements to integrate with the `Document` canceller list -- meaning
these fetches also get cancelled when the `Document` unloads.

Signed-off-by: Martin Robinson <mrobinson@igalia.com>
This commit is contained in:
Martin Robinson 2025-01-11 12:49:22 +01:00 committed by GitHub
parent e2be55b873
commit 748954d610
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
23 changed files with 179 additions and 226 deletions

View file

@ -464,10 +464,7 @@ pub enum WebSocketNetworkEvent {
#[derive(Debug, Deserialize, Serialize)]
/// IPC channels to communicate with the script thread about network or DOM events.
pub enum FetchChannels {
ResponseMsg(
IpcSender<FetchResponseMsg>,
/* cancel_chan */ Option<IpcReceiver<()>>,
),
ResponseMsg(IpcSender<FetchResponseMsg>),
WebSocket {
event_sender: IpcSender<WebSocketNetworkEvent>,
action_receiver: IpcReceiver<WebSocketDomAction>,
@ -480,13 +477,9 @@ pub enum FetchChannels {
#[derive(Debug, Deserialize, Serialize)]
pub enum CoreResourceMsg {
Fetch(RequestBuilder, FetchChannels),
Cancel(Vec<RequestId>),
/// Initiate a fetch in response to processing a redirection
FetchRedirect(
RequestBuilder,
ResponseInit,
IpcSender<FetchResponseMsg>,
/* cancel_chan */ Option<IpcReceiver<()>>,
),
FetchRedirect(RequestBuilder, ResponseInit, IpcSender<FetchResponseMsg>),
/// Store a cookie for a given originating URL
SetCookieForUrl(ServoUrl, Serde<Cookie<'static>>, CookieSource),
/// Store a set of cookies for a given originating URL
@ -522,10 +515,10 @@ pub enum CoreResourceMsg {
// FIXME: https://github.com/servo/servo/issues/34591
#[expect(clippy::large_enum_variant)]
enum ToFetchThreadMessage {
Cancel(Vec<RequestId>),
StartFetch(
/* request_builder */ RequestBuilder,
/* response_init */ Option<ResponseInit>,
/* cancel_chan */ Option<IpcReceiver<()>>,
/* callback */ BoxedFetchCallback,
),
FetchResponse(FetchResponseMsg),
@ -584,12 +577,7 @@ impl FetchThread {
fn run(&mut self) {
loop {
match self.receiver.recv().unwrap() {
ToFetchThreadMessage::StartFetch(
request_builder,
response_init,
canceller,
callback,
) => {
ToFetchThreadMessage::StartFetch(request_builder, response_init, callback) => {
self.active_fetches.insert(request_builder.id, callback);
// Only redirects have a `response_init` field.
@ -598,11 +586,10 @@ impl FetchThread {
request_builder,
response_init,
self.to_fetch_sender.clone(),
canceller,
),
None => CoreResourceMsg::Fetch(
request_builder,
FetchChannels::ResponseMsg(self.to_fetch_sender.clone(), canceller),
FetchChannels::ResponseMsg(self.to_fetch_sender.clone()),
),
};
@ -623,6 +610,14 @@ impl FetchThread {
self.active_fetches.remove(&request_id);
}
},
ToFetchThreadMessage::Cancel(request_ids) => {
// Errors are ignored here, because Servo sends many cancellation requests when shutting down.
// At this point the networking task might be shut down completely, so just ignore errors
// during this time.
let _ = self
.core_resource_thread
.send(CoreResourceMsg::Cancel(request_ids));
},
}
}
}
@ -635,7 +630,6 @@ pub fn fetch_async(
core_resource_thread: &CoreResourceThread,
request: RequestBuilder,
response_init: Option<ResponseInit>,
canceller: Option<IpcReceiver<()>>,
callback: BoxedFetchCallback,
) {
let _ = FETCH_THREAD
@ -643,11 +637,19 @@ pub fn fetch_async(
.send(ToFetchThreadMessage::StartFetch(
request,
response_init,
canceller,
callback,
));
}
/// Instruct the resource thread to cancel an existing request. Does nothing if the
/// request has already completed or has not been fetched yet.
pub fn cancel_async_fetch(request_ids: Vec<RequestId>) {
let _ = FETCH_THREAD
.get()
.expect("Tried to cancel request in process that hasn't started one.")
.send(ToFetchThreadMessage::Cancel(request_ids));
}
#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
pub struct ResourceCorsData {
/// CORS Preflight flag