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

@ -10,7 +10,7 @@ use std::fs::File;
use std::io::prelude::*;
use std::io::{self, BufReader};
use std::path::{Path, PathBuf};
use std::sync::{Arc, Mutex, RwLock};
use std::sync::{Arc, Mutex, RwLock, Weak};
use std::thread;
use std::time::Duration;
@ -24,7 +24,7 @@ use log::{debug, warn};
use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
use net_traits::blob_url_store::parse_blob_url;
use net_traits::filemanager_thread::FileTokenCheck;
use net_traits::request::{Destination, RequestBuilder};
use net_traits::request::{Destination, RequestBuilder, RequestId};
use net_traits::response::{Response, ResponseInit};
use net_traits::storage_thread::StorageThreadMsg;
use net_traits::{
@ -142,6 +142,7 @@ pub fn new_core_resource_thread(
config_dir,
ca_certificates,
ignore_certificate_errors,
cancellation_listeners: Default::default(),
};
mem_profiler_chan.run_with_memory_reporting(
@ -168,6 +169,7 @@ struct ResourceChannelManager {
config_dir: Option<PathBuf>,
ca_certificates: CACertificates,
ignore_certificate_errors: bool,
cancellation_listeners: HashMap<RequestId, Weak<CancellationListener>>,
}
fn create_http_states(
@ -300,6 +302,30 @@ impl ResourceChannelManager {
msg.send(vec![public_report, private_report]);
}
fn cancellation_listener(&self, request_id: RequestId) -> Option<Arc<CancellationListener>> {
self.cancellation_listeners
.get(&request_id)
.and_then(Weak::upgrade)
}
fn get_or_create_cancellation_listener(
&mut self,
request_id: RequestId,
) -> Arc<CancellationListener> {
if let Some(listener) = self.cancellation_listener(request_id) {
return listener;
}
// Clear away any cancellation listeners that are no longer valid.
self.cancellation_listeners
.retain(|_, listener| listener.strong_count() > 0);
let cancellation_listener = Arc::new(Default::default());
self.cancellation_listeners
.insert(request_id, Arc::downgrade(&cancellation_listener));
cancellation_listener
}
/// Returns false if the thread should exit.
fn process_msg(
&mut self,
@ -308,33 +334,45 @@ impl ResourceChannelManager {
protocols: Arc<ProtocolRegistry>,
) -> bool {
match msg {
CoreResourceMsg::Fetch(req_init, channels) => match channels {
FetchChannels::ResponseMsg(sender, cancel_chan) => self.resource_manager.fetch(
req_init,
None,
sender,
http_state,
cancel_chan,
protocols,
),
CoreResourceMsg::Fetch(request_builder, channels) => match channels {
FetchChannels::ResponseMsg(sender) => {
let cancellation_listener =
self.get_or_create_cancellation_listener(request_builder.id);
self.resource_manager.fetch(
request_builder,
None,
sender,
http_state,
cancellation_listener,
protocols,
);
},
FetchChannels::WebSocket {
event_sender,
action_receiver,
} => self.resource_manager.websocket_connect(
req_init,
request_builder,
event_sender,
action_receiver,
http_state,
),
FetchChannels::Prefetch => self.resource_manager.fetch(
req_init,
request_builder,
None,
DiscardFetch,
http_state,
None,
Arc::new(Default::default()),
protocols,
),
},
CoreResourceMsg::Cancel(request_ids) => {
for cancellation_listener in request_ids
.into_iter()
.filter_map(|request_id| self.cancellation_listener(request_id))
{
cancellation_listener.cancel();
}
},
CoreResourceMsg::DeleteCookies(request) => {
http_state
.cookie_jar
@ -343,13 +381,15 @@ impl ResourceChannelManager {
.clear_storage(&request);
return true;
},
CoreResourceMsg::FetchRedirect(req_init, res_init, sender, cancel_chan) => {
CoreResourceMsg::FetchRedirect(request_builder, res_init, sender) => {
let cancellation_listener =
self.get_or_create_cancellation_listener(request_builder.id);
self.resource_manager.fetch(
req_init,
request_builder,
Some(res_init),
sender,
http_state,
cancel_chan,
cancellation_listener,
protocols,
)
},
@ -698,7 +738,7 @@ impl CoreResourceManager {
res_init_: Option<ResponseInit>,
mut sender: Target,
http_state: &Arc<HttpState>,
cancel_chan: Option<IpcReceiver<()>>,
cancellation_listener: Arc<CancellationListener>,
protocols: Arc<ProtocolRegistry>,
) {
let http_state = http_state.clone();
@ -746,7 +786,7 @@ impl CoreResourceManager {
devtools_chan: dc.map(|dc| Arc::new(Mutex::new(dc))),
filemanager: Arc::new(Mutex::new(filemanager)),
file_token,
cancellation_listener: Arc::new(Mutex::new(CancellationListener::new(cancel_chan))),
cancellation_listener,
timing: ServoArc::new(Mutex::new(ResourceFetchTiming::new(request.timing_type()))),
protocols,
};