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

@ -661,7 +661,6 @@ impl RemoteWebFontDownloader {
&core_resource_thread_clone, &core_resource_thread_clone,
request, request,
None, None,
None,
Box::new(move |response_message| { Box::new(move |response_message| {
match downloader.handle_web_font_fetch_message(response_message) { match downloader.handle_web_font_fetch_message(response_message) {
DownloaderResponseResult::InProcess => {}, DownloaderResponseResult::InProcess => {},

View file

@ -3,7 +3,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use std::borrow::Cow; use std::borrow::Cow;
use std::sync::atomic::Ordering; use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use std::{io, mem, str}; use std::{io, mem, str};
@ -15,7 +15,7 @@ use devtools_traits::DevtoolsControlMsg;
use headers::{AccessControlExposeHeaders, ContentType, HeaderMapExt}; use headers::{AccessControlExposeHeaders, ContentType, HeaderMapExt};
use http::header::{self, HeaderMap, HeaderName}; use http::header::{self, HeaderMap, HeaderName};
use http::{Method, StatusCode}; use http::{Method, StatusCode};
use ipc_channel::ipc::{self, IpcReceiver}; use ipc_channel::ipc;
use log::warn; use log::warn;
use mime::{self, Mime}; use mime::{self, Mime};
use net_traits::filemanager_thread::{FileTokenCheck, RelativePos}; use net_traits::filemanager_thread::{FileTokenCheck, RelativePos};
@ -59,37 +59,23 @@ pub struct FetchContext {
pub devtools_chan: Option<Arc<Mutex<Sender<DevtoolsControlMsg>>>>, pub devtools_chan: Option<Arc<Mutex<Sender<DevtoolsControlMsg>>>>,
pub filemanager: Arc<Mutex<FileManager>>, pub filemanager: Arc<Mutex<FileManager>>,
pub file_token: FileTokenCheck, pub file_token: FileTokenCheck,
pub cancellation_listener: Arc<Mutex<CancellationListener>>, pub cancellation_listener: Arc<CancellationListener>,
pub timing: ServoArc<Mutex<ResourceFetchTiming>>, pub timing: ServoArc<Mutex<ResourceFetchTiming>>,
pub protocols: Arc<ProtocolRegistry>, pub protocols: Arc<ProtocolRegistry>,
} }
#[derive(Default)]
pub struct CancellationListener { pub struct CancellationListener {
cancel_chan: Option<IpcReceiver<()>>, cancelled: AtomicBool,
cancelled: bool,
} }
impl CancellationListener { impl CancellationListener {
pub fn new(cancel_chan: Option<IpcReceiver<()>>) -> Self { pub(crate) fn cancelled(&self) -> bool {
Self { self.cancelled.load(Ordering::Relaxed)
cancel_chan,
cancelled: false,
}
} }
pub fn cancelled(&mut self) -> bool { pub(crate) fn cancel(&self) {
if let Some(ref cancel_chan) = self.cancel_chan { self.cancelled.store(true, Ordering::Relaxed)
if self.cancelled {
true
} else if cancel_chan.try_recv().is_ok() {
self.cancelled = true;
true
} else {
false
}
} else {
false
}
} }
} }
pub type DoneChannel = Option<(TokioSender<Data>, TokioReceiver<Data>)>; pub type DoneChannel = Option<(TokioSender<Data>, TokioReceiver<Data>)>;

View file

@ -128,7 +128,7 @@ impl FileManager {
pub fn fetch_file( pub fn fetch_file(
&self, &self,
done_sender: &mut TokioSender<Data>, done_sender: &mut TokioSender<Data>,
cancellation_listener: Arc<Mutex<CancellationListener>>, cancellation_listener: Arc<CancellationListener>,
id: Uuid, id: Uuid,
file_token: &FileTokenCheck, file_token: &FileTokenCheck,
origin: FileOrigin, origin: FileOrigin,
@ -211,7 +211,7 @@ impl FileManager {
done_sender: &mut TokioSender<Data>, done_sender: &mut TokioSender<Data>,
mut reader: BufReader<File>, mut reader: BufReader<File>,
res_body: ServoArc<Mutex<ResponseBody>>, res_body: ServoArc<Mutex<ResponseBody>>,
cancellation_listener: Arc<Mutex<CancellationListener>>, cancellation_listener: Arc<CancellationListener>,
range: RelativePos, range: RelativePos,
) { ) {
let done_sender = done_sender.clone(); let done_sender = done_sender.clone();
@ -220,7 +220,7 @@ impl FileManager {
.map(|pool| { .map(|pool| {
pool.spawn(move || { pool.spawn(move || {
loop { loop {
if cancellation_listener.lock().unwrap().cancelled() { if cancellation_listener.cancelled() {
*res_body.lock().unwrap() = ResponseBody::Done(vec![]); *res_body.lock().unwrap() = ResponseBody::Done(vec![]);
let _ = done_sender.send(Data::Cancelled); let _ = done_sender.send(Data::Cancelled);
return; return;
@ -282,7 +282,7 @@ impl FileManager {
fn fetch_blob_buf( fn fetch_blob_buf(
&self, &self,
done_sender: &mut TokioSender<Data>, done_sender: &mut TokioSender<Data>,
cancellation_listener: Arc<Mutex<CancellationListener>>, cancellation_listener: Arc<CancellationListener>,
id: &Uuid, id: &Uuid,
file_token: &FileTokenCheck, file_token: &FileTokenCheck,
origin_in: &FileOrigin, origin_in: &FileOrigin,

View file

@ -1944,7 +1944,7 @@ async fn http_network_fetch(
let meta_status = meta.status; let meta_status = meta.status;
let meta_headers = meta.headers; let meta_headers = meta.headers;
let cancellation_listener = context.cancellation_listener.clone(); let cancellation_listener = context.cancellation_listener.clone();
if cancellation_listener.lock().unwrap().cancelled() { if cancellation_listener.cancelled() {
return Response::network_error(NetworkError::Internal("Fetch aborted".into())); return Response::network_error(NetworkError::Internal("Fetch aborted".into()));
} }
@ -1983,7 +1983,7 @@ async fn http_network_fetch(
warn!("Error streaming response body: {:?}", e); warn!("Error streaming response body: {:?}", e);
}) })
.try_fold(res_body, move |res_body, chunk| { .try_fold(res_body, move |res_body, chunk| {
if cancellation_listener.lock().unwrap().cancelled() { if cancellation_listener.cancelled() {
*res_body.lock().unwrap() = ResponseBody::Done(vec![]); *res_body.lock().unwrap() = ResponseBody::Done(vec![]);
let _ = done_sender.send(Data::Cancelled); let _ = done_sender.send(Data::Cancelled);
return future::ready(Err(())); return future::ready(Err(()));

View file

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

View file

@ -26,7 +26,7 @@ use hyper::body::{Bytes, Incoming};
use hyper::{Request as HyperRequest, Response as HyperResponse}; use hyper::{Request as HyperRequest, Response as HyperResponse};
use mime::{self, Mime}; use mime::{self, Mime};
use net::fetch::cors_cache::CorsCache; use net::fetch::cors_cache::CorsCache;
use net::fetch::methods::{self, CancellationListener, FetchContext}; use net::fetch::methods::{self, FetchContext};
use net::filemanager_thread::FileManager; use net::filemanager_thread::FileManager;
use net::hsts::HstsEntry; use net::hsts::HstsEntry;
use net::protocols::ProtocolRegistry; use net::protocols::ProtocolRegistry;
@ -702,7 +702,7 @@ fn test_fetch_with_hsts() {
Weak::new(), Weak::new(),
))), ))),
file_token: FileTokenCheck::NotRequired, file_token: FileTokenCheck::NotRequired,
cancellation_listener: Arc::new(Mutex::new(CancellationListener::new(None))), cancellation_listener: Arc::new(Default::default()),
timing: ServoArc::new(Mutex::new(ResourceFetchTiming::new( timing: ServoArc::new(Mutex::new(ResourceFetchTiming::new(
ResourceTimingType::Navigation, ResourceTimingType::Navigation,
))), ))),
@ -759,7 +759,7 @@ fn test_load_adds_host_to_hsts_list_when_url_is_https() {
Weak::new(), Weak::new(),
))), ))),
file_token: FileTokenCheck::NotRequired, file_token: FileTokenCheck::NotRequired,
cancellation_listener: Arc::new(Mutex::new(CancellationListener::new(None))), cancellation_listener: Arc::new(Default::default()),
timing: ServoArc::new(Mutex::new(ResourceFetchTiming::new( timing: ServoArc::new(Mutex::new(ResourceFetchTiming::new(
ResourceTimingType::Navigation, ResourceTimingType::Navigation,
))), ))),
@ -818,7 +818,7 @@ fn test_fetch_self_signed() {
Weak::new(), Weak::new(),
))), ))),
file_token: FileTokenCheck::NotRequired, file_token: FileTokenCheck::NotRequired,
cancellation_listener: Arc::new(Mutex::new(CancellationListener::new(None))), cancellation_listener: Arc::new(Default::default()),
timing: ServoArc::new(Mutex::new(ResourceFetchTiming::new( timing: ServoArc::new(Mutex::new(ResourceFetchTiming::new(
ResourceTimingType::Navigation, ResourceTimingType::Navigation,
))), ))),

View file

@ -39,7 +39,7 @@ use hyper::{Request as HyperRequest, Response as HyperResponse};
use hyper_util::rt::tokio::TokioIo; use hyper_util::rt::tokio::TokioIo;
use net::connector::{create_http_client, create_tls_config}; use net::connector::{create_http_client, create_tls_config};
use net::fetch::cors_cache::CorsCache; use net::fetch::cors_cache::CorsCache;
use net::fetch::methods::{self, CancellationListener, FetchContext}; use net::fetch::methods::{self, FetchContext};
use net::filemanager_thread::FileManager; use net::filemanager_thread::FileManager;
use net::protocols::ProtocolRegistry; use net::protocols::ProtocolRegistry;
use net::resource_thread::CoreResourceThreadPool; use net::resource_thread::CoreResourceThreadPool;
@ -183,7 +183,7 @@ fn new_fetch_context(
pool_handle.unwrap_or_else(|| Weak::new()), pool_handle.unwrap_or_else(|| Weak::new()),
))), ))),
file_token: FileTokenCheck::NotRequired, file_token: FileTokenCheck::NotRequired,
cancellation_listener: Arc::new(Mutex::new(CancellationListener::new(None))), cancellation_listener: Arc::new(Default::default()),
timing: ServoArc::new(Mutex::new(ResourceFetchTiming::new( timing: ServoArc::new(Mutex::new(ResourceFetchTiming::new(
ResourceTimingType::Navigation, ResourceTimingType::Navigation,
))), ))),

View file

@ -6,7 +6,6 @@
//! //!
//! <https://html.spec.whatwg.org/multipage/#the-end> //! <https://html.spec.whatwg.org/multipage/#the-end>
use ipc_channel::ipc;
use net_traits::request::RequestBuilder; use net_traits::request::RequestBuilder;
use net_traits::{fetch_async, BoxedFetchCallback, ResourceThreads}; use net_traits::{fetch_async, BoxedFetchCallback, ResourceThreads};
use servo_url::ServoUrl; use servo_url::ServoUrl;
@ -121,7 +120,7 @@ impl DocumentLoader {
callback: BoxedFetchCallback, callback: BoxedFetchCallback,
) { ) {
self.add_blocking_load(load); self.add_blocking_load(load);
self.fetch_async_background(request, callback, None); self.fetch_async_background(request, callback);
} }
/// Initiate a new fetch that does not block the document load event. /// Initiate a new fetch that does not block the document load event.
@ -129,22 +128,9 @@ impl DocumentLoader {
&mut self, &mut self,
request: RequestBuilder, request: RequestBuilder,
callback: BoxedFetchCallback, callback: BoxedFetchCallback,
cancel_override: Option<ipc::IpcReceiver<()>>,
) { ) {
let canceller = cancel_override.unwrap_or_else(|| { self.cancellers.push(FetchCanceller::new(request.id));
let mut canceller = FetchCanceller::new(); fetch_async(&self.resource_threads.core_thread, request, None, callback);
let cancel_receiver = canceller.initialize();
self.cancellers.push(canceller);
cancel_receiver
});
fetch_async(
&self.resource_threads.core_thread,
request,
None, /* response_init */
Some(canceller),
callback,
);
} }
/// Mark an in-progress network request complete. /// Mark an in-progress network request complete.

View file

@ -2150,7 +2150,6 @@ impl Document {
&self, &self,
request: RequestBuilder, request: RequestBuilder,
listener: Listener, listener: Listener,
cancel_override: Option<ipc::IpcReceiver<()>>,
) { ) {
let callback = NetworkListener { let callback = NetworkListener {
context: std::sync::Arc::new(Mutex::new(listener)), context: std::sync::Arc::new(Mutex::new(listener)),
@ -2161,8 +2160,7 @@ impl Document {
.into(), .into(),
} }
.into_callback(); .into_callback();
self.loader_mut() self.loader_mut().fetch_async_background(request, callback);
.fetch_async_background(request, callback, cancel_override);
} }
// https://html.spec.whatwg.org/multipage/#the-end // https://html.spec.whatwg.org/multipage/#the-end

View file

@ -602,12 +602,12 @@ impl EventSourceMethods<crate::DomTypeHolder> for EventSource {
listener.notify_fetch(message.unwrap()); listener.notify_fetch(message.unwrap());
}), }),
); );
let cancel_receiver = ev.canceller.borrow_mut().initialize(); *ev.canceller.borrow_mut() = FetchCanceller::new(request.id);
global global
.core_resource_thread() .core_resource_thread()
.send(CoreResourceMsg::Fetch( .send(CoreResourceMsg::Fetch(
request, request,
FetchChannels::ResponseMsg(action_sender, Some(cancel_receiver)), FetchChannels::ResponseMsg(action_sender),
)) ))
.unwrap(); .unwrap();
// Step 13 // Step 13
@ -681,7 +681,7 @@ impl EventSourceTimeoutCallback {
.core_resource_thread() .core_resource_thread()
.send(CoreResourceMsg::Fetch( .send(CoreResourceMsg::Fetch(
request, request,
FetchChannels::ResponseMsg(self.action_sender, None), FetchChannels::ResponseMsg(self.action_sender),
)) ))
.unwrap(); .unwrap();
} }

View file

@ -3242,13 +3242,12 @@ impl GlobalScope {
request_builder: RequestBuilder, request_builder: RequestBuilder,
context: Arc<Mutex<Listener>>, context: Arc<Mutex<Listener>>,
task_source: SendableTaskSource, task_source: SendableTaskSource,
cancellation_sender: Option<ipc::IpcReceiver<()>>,
) { ) {
let network_listener = NetworkListener { let network_listener = NetworkListener {
context, context,
task_source, task_source,
}; };
self.fetch_with_network_listener(request_builder, network_listener, cancellation_sender); self.fetch_with_network_listener(request_builder, network_listener);
} }
pub(crate) fn fetch_with_network_listener< pub(crate) fn fetch_with_network_listener<
@ -3257,13 +3256,11 @@ impl GlobalScope {
&self, &self,
request_builder: RequestBuilder, request_builder: RequestBuilder,
network_listener: NetworkListener<Listener>, network_listener: NetworkListener<Listener>,
cancellation_receiver: Option<ipc::IpcReceiver<()>>,
) { ) {
fetch_async( fetch_async(
&self.core_resource_thread(), &self.core_resource_thread(),
request_builder, request_builder,
None, None,
cancellation_receiver,
network_listener.into_callback(), network_listener.into_callback(),
); );
} }

View file

@ -419,7 +419,7 @@ impl HTMLImageElement {
// This is a background load because the load blocker already fulfills the // This is a background load because the load blocker already fulfills the
// purpose of delaying the document's load event. // purpose of delaying the document's load event.
document.fetch_background(request, context, None); document.fetch_background(request, context);
} }
// Steps common to when an image has been loaded. // Steps common to when an image has been loaded.

View file

@ -384,7 +384,7 @@ impl HTMLLinkElement {
resource_timing: ResourceFetchTiming::new(ResourceTimingType::Resource), resource_timing: ResourceFetchTiming::new(ResourceTimingType::Resource),
}; };
document.fetch_background(request, fetch_context, None); document.fetch_background(request, fetch_context);
} }
/// <https://html.spec.whatwg.org/multipage/#concept-link-obtain> /// <https://html.spec.whatwg.org/multipage/#concept-link-obtain>

View file

@ -898,15 +898,12 @@ impl HTMLMediaElement {
if let Some(ref mut current_fetch_context) = *current_fetch_context { if let Some(ref mut current_fetch_context) = *current_fetch_context {
current_fetch_context.cancel(CancelReason::Overridden); current_fetch_context.cancel(CancelReason::Overridden);
} }
let (fetch_context, cancel_receiver) = HTMLMediaElementFetchContext::new();
*current_fetch_context = Some(fetch_context); *current_fetch_context = Some(HTMLMediaElementFetchContext::new(request.id));
let listener = let listener =
HTMLMediaElementFetchListener::new(self, url.clone(), offset.unwrap_or(0), seek_lock); HTMLMediaElementFetchListener::new(self, url.clone(), offset.unwrap_or(0), seek_lock);
// TODO: If this is supposed to to be a "fetch" as defined in the specification self.owner_document().fetch_background(request, listener);
// this should probably be integrated into the Document's list of cancellable fetches.
self.owner_document()
.fetch_background(request, listener, Some(cancel_receiver));
} }
// https://html.spec.whatwg.org/multipage/#concept-media-load-resource // https://html.spec.whatwg.org/multipage/#concept-media-load-resource
@ -2598,17 +2595,12 @@ pub(crate) struct HTMLMediaElementFetchContext {
} }
impl HTMLMediaElementFetchContext { impl HTMLMediaElementFetchContext {
fn new() -> (HTMLMediaElementFetchContext, ipc::IpcReceiver<()>) { fn new(request_id: RequestId) -> HTMLMediaElementFetchContext {
let mut fetch_canceller = FetchCanceller::new(); HTMLMediaElementFetchContext {
let cancel_receiver = fetch_canceller.initialize(); cancel_reason: None,
( is_seekable: false,
HTMLMediaElementFetchContext { fetch_canceller: FetchCanceller::new(request_id),
cancel_reason: None, }
is_seekable: false,
fetch_canceller,
},
cancel_receiver,
)
} }
fn is_seekable(&self) -> bool { fn is_seekable(&self) -> bool {

View file

@ -54,8 +54,6 @@ pub(crate) struct HTMLVideoElement {
video_height: Cell<Option<u32>>, video_height: Cell<Option<u32>>,
/// Incremented whenever tasks associated with this element are cancelled. /// Incremented whenever tasks associated with this element are cancelled.
generation_id: Cell<u32>, generation_id: Cell<u32>,
/// Poster frame fetch request canceller.
poster_frame_canceller: DomRefCell<FetchCanceller>,
/// Load event blocker. Will block the load event while the poster frame /// Load event blocker. Will block the load event while the poster frame
/// is being fetched. /// is being fetched.
load_blocker: DomRefCell<Option<LoadBlocker>>, load_blocker: DomRefCell<Option<LoadBlocker>>,
@ -78,7 +76,6 @@ impl HTMLVideoElement {
video_width: Cell::new(None), video_width: Cell::new(None),
video_height: Cell::new(None), video_height: Cell::new(None),
generation_id: Cell::new(0), generation_id: Cell::new(0),
poster_frame_canceller: DomRefCell::new(Default::default()),
load_blocker: Default::default(), load_blocker: Default::default(),
last_frame: Default::default(), last_frame: Default::default(),
sent_resize: Cell::new(None), sent_resize: Cell::new(None),
@ -162,7 +159,6 @@ impl HTMLVideoElement {
/// <https://html.spec.whatwg.org/multipage/#poster-frame> /// <https://html.spec.whatwg.org/multipage/#poster-frame>
fn fetch_poster_frame(&self, poster_url: &str, can_gc: CanGc) { fn fetch_poster_frame(&self, poster_url: &str, can_gc: CanGc) {
// Step 1. // Step 1.
let cancel_receiver = self.poster_frame_canceller.borrow_mut().initialize();
self.generation_id.set(self.generation_id.get() + 1); self.generation_id.set(self.generation_id.get() + 1);
// Step 2. // Step 2.
@ -199,20 +195,14 @@ impl HTMLVideoElement {
self.process_image_response(ImageResponse::Loaded(image, url), can_gc); self.process_image_response(ImageResponse::Loaded(image, url), can_gc);
}, },
ImageCacheResult::ReadyForRequest(id) => { ImageCacheResult::ReadyForRequest(id) => {
self.do_fetch_poster_frame(poster_url, id, cancel_receiver, can_gc) self.do_fetch_poster_frame(poster_url, id, can_gc);
}, },
_ => (), _ => (),
} }
} }
/// <https://html.spec.whatwg.org/multipage/#poster-frame> /// <https://html.spec.whatwg.org/multipage/#poster-frame>
fn do_fetch_poster_frame( fn do_fetch_poster_frame(&self, poster_url: ServoUrl, id: PendingImageId, can_gc: CanGc) {
&self,
poster_url: ServoUrl,
id: PendingImageId,
cancel_receiver: ipc::IpcReceiver<()>,
can_gc: CanGc,
) {
// Continuation of step 4. // Continuation of step 4.
let document = self.owner_document(); let document = self.owner_document();
let request = RequestBuilder::new(poster_url.clone(), document.global().get_referrer()) let request = RequestBuilder::new(poster_url.clone(), document.global().get_referrer())
@ -235,12 +225,8 @@ impl HTMLVideoElement {
LoadType::Image(poster_url.clone()), LoadType::Image(poster_url.clone()),
)); ));
let context = PosterFrameFetchContext::new(self, poster_url, id); let context = PosterFrameFetchContext::new(self, poster_url, id, request.id);
self.owner_document().fetch_background(request, context);
// TODO: If this is supposed to to be a "fetch" as defined in the specification
// this should probably be integrated into the Document's list of cancellable fetches.
self.owner_document()
.fetch_background(request, context, Some(cancel_receiver));
} }
} }
@ -338,11 +324,16 @@ struct PosterFrameFetchContext {
resource_timing: ResourceFetchTiming, resource_timing: ResourceFetchTiming,
/// Url for the resource /// Url for the resource
url: ServoUrl, url: ServoUrl,
/// A [`FetchCanceller`] for this request.
fetch_canceller: FetchCanceller,
} }
impl FetchResponseListener for PosterFrameFetchContext { impl FetchResponseListener for PosterFrameFetchContext {
fn process_request_body(&mut self, _: RequestId) {} fn process_request_body(&mut self, _: RequestId) {}
fn process_request_eof(&mut self, _: RequestId) {}
fn process_request_eof(&mut self, _: RequestId) {
self.fetch_canceller.ignore()
}
fn process_response( fn process_response(
&mut self, &mut self,
@ -365,11 +356,7 @@ impl FetchResponseListener for PosterFrameFetchContext {
if !status_is_ok { if !status_is_ok {
self.cancelled = true; self.cancelled = true;
self.elem self.fetch_canceller.cancel();
.root()
.poster_frame_canceller
.borrow_mut()
.cancel();
} }
} }
@ -433,7 +420,12 @@ impl PreInvoke for PosterFrameFetchContext {
} }
impl PosterFrameFetchContext { impl PosterFrameFetchContext {
fn new(elem: &HTMLVideoElement, url: ServoUrl, id: PendingImageId) -> PosterFrameFetchContext { fn new(
elem: &HTMLVideoElement,
url: ServoUrl,
id: PendingImageId,
request_id: RequestId,
) -> PosterFrameFetchContext {
let window = elem.owner_window(); let window = elem.owner_window();
PosterFrameFetchContext { PosterFrameFetchContext {
image_cache: window.image_cache(), image_cache: window.image_cache(),
@ -442,6 +434,7 @@ impl PosterFrameFetchContext {
cancelled: false, cancelled: false,
resource_timing: ResourceFetchTiming::new(ResourceTimingType::Resource), resource_timing: ResourceFetchTiming::new(ResourceTimingType::Resource),
url, url,
fetch_canceller: FetchCanceller::new(request_id),
} }
} }
} }

View file

@ -18,7 +18,6 @@ use html5ever::serialize::SerializeOpts;
use http::header::{self, HeaderMap, HeaderName, HeaderValue}; use http::header::{self, HeaderMap, HeaderName, HeaderValue};
use http::Method; use http::Method;
use hyper_serde::Serde; use hyper_serde::Serde;
use ipc_channel::ipc;
use js::jsapi::{Heap, JS_ClearPendingException}; use js::jsapi::{Heap, JS_ClearPendingException};
use js::jsval::{JSVal, NullValue}; use js::jsval::{JSVal, NullValue};
use js::rust::wrappers::JS_ParseJSON; use js::rust::wrappers::JS_ParseJSON;
@ -291,16 +290,6 @@ impl XMLHttpRequest {
fn sync_in_window(&self) -> bool { fn sync_in_window(&self) -> bool {
self.sync.get() && self.global().is::<Window>() self.sync.get() && self.global().is::<Window>()
} }
fn initiate_async_xhr(
context: Arc<Mutex<XHRContext>>,
task_source: SendableTaskSource,
global: &GlobalScope,
init: RequestBuilder,
cancellation_chan: ipc::IpcReceiver<()>,
) {
global.fetch(init, context, task_source, Some(cancellation_chan));
}
} }
impl XMLHttpRequestMethods<crate::DomTypeHolder> for XMLHttpRequest { impl XMLHttpRequestMethods<crate::DomTypeHolder> for XMLHttpRequest {
@ -1548,7 +1537,7 @@ impl XMLHttpRequest {
self.response_status.set(Err(())); self.response_status.set(Err(()));
} }
fn fetch(&self, init: RequestBuilder, global: &GlobalScope) -> ErrorResult { fn fetch(&self, request_builder: RequestBuilder, global: &GlobalScope) -> ErrorResult {
let xhr = Trusted::new(self); let xhr = Trusted::new(self);
let context = Arc::new(Mutex::new(XHRContext { let context = Arc::new(Mutex::new(XHRContext {
@ -1556,7 +1545,7 @@ impl XMLHttpRequest {
gen_id: self.generation_id.get(), gen_id: self.generation_id.get(),
sync_status: DomRefCell::new(None), sync_status: DomRefCell::new(None),
resource_timing: ResourceFetchTiming::new(ResourceTimingType::Resource), resource_timing: ResourceFetchTiming::new(ResourceTimingType::Resource),
url: init.url.clone(), url: request_builder.url.clone(),
})); }));
let (task_source, script_port) = if self.sync.get() { let (task_source, script_port) = if self.sync.get() {
@ -1577,15 +1566,8 @@ impl XMLHttpRequest {
) )
}; };
let cancel_receiver = self.canceller.borrow_mut().initialize(); *self.canceller.borrow_mut() = FetchCanceller::new(request_builder.id);
global.fetch(request_builder, context.clone(), task_source);
XMLHttpRequest::initiate_async_xhr(
context.clone(),
task_source,
global,
init,
cancel_receiver,
);
if let Some(script_port) = script_port { if let Some(script_port) = script_port {
loop { loop {

View file

@ -12,9 +12,9 @@ use net_traits::request::{
RequestBuilder, RequestId, RequestMode, ServiceWorkersMode, RequestBuilder, RequestId, RequestMode, ServiceWorkersMode,
}; };
use net_traits::{ use net_traits::{
CoreResourceMsg, CoreResourceThread, FetchChannels, FetchMetadata, FetchResponseListener, cancel_async_fetch, CoreResourceMsg, CoreResourceThread, FetchChannels, FetchMetadata,
FetchResponseMsg, FilteredMetadata, Metadata, NetworkError, ResourceFetchTiming, FetchResponseListener, FetchResponseMsg, FilteredMetadata, Metadata, NetworkError,
ResourceTimingType, ResourceFetchTiming, ResourceTimingType,
}; };
use servo_url::ServoUrl; use servo_url::ServoUrl;
@ -52,44 +52,34 @@ struct FetchContext {
/// or let it cancel on Drop in that case. /// or let it cancel on Drop in that case.
#[derive(Default, JSTraceable, MallocSizeOf)] #[derive(Default, JSTraceable, MallocSizeOf)]
pub(crate) struct FetchCanceller { pub(crate) struct FetchCanceller {
#[ignore_malloc_size_of = "channels are hard"]
#[no_trace] #[no_trace]
cancel_chan: Option<ipc::IpcSender<()>>, request_id: Option<RequestId>,
} }
impl FetchCanceller { impl FetchCanceller {
/// Create an empty FetchCanceller /// Create an empty FetchCanceller
pub(crate) fn new() -> Self { pub(crate) fn new(request_id: RequestId) -> Self {
Default::default() Self {
} request_id: Some(request_id),
}
/// Obtain an IpcReceiver to send over to Fetch, and initialize
/// the internal sender
pub(crate) fn initialize(&mut self) -> ipc::IpcReceiver<()> {
// cancel previous fetch
self.cancel();
let (rx, tx) = ipc::channel().unwrap();
self.cancel_chan = Some(rx);
tx
} }
/// Cancel a fetch if it is ongoing /// Cancel a fetch if it is ongoing
pub(crate) fn cancel(&mut self) { pub(crate) fn cancel(&mut self) {
if let Some(chan) = self.cancel_chan.take() { if let Some(request_id) = self.request_id.take() {
// stop trying to make fetch happen // stop trying to make fetch happen
// it's not going to happen // it's not going to happen
// The receiver will be destroyed if the request has already completed; // No error handling here. Cancellation is a courtesy call,
// so we throw away the error. Cancellation is a courtesy call,
// we don't actually care if the other side heard. // we don't actually care if the other side heard.
let _ = chan.send(()); cancel_async_fetch(vec![request_id]);
} }
} }
/// Use this if you don't want it to send a cancellation request /// Use this if you don't want it to send a cancellation request
/// on drop (e.g. if the fetch completes) /// on drop (e.g. if the fetch completes)
pub(crate) fn ignore(&mut self) { pub(crate) fn ignore(&mut self) {
let _ = self.cancel_chan.take(); let _ = self.request_id.take();
} }
} }
@ -197,7 +187,6 @@ pub(crate) fn Fetch(
request_init, request_init,
fetch_context, fetch_context,
global.task_manager().networking_task_source().to_sendable(), global.task_manager().networking_task_source().to_sendable(),
None,
); );
// Step 13. Return p. // Step 13. Return p.
@ -344,7 +333,7 @@ pub(crate) fn load_whole_resource(
core_resource_thread core_resource_thread
.send(CoreResourceMsg::Fetch( .send(CoreResourceMsg::Fetch(
request, request,
FetchChannels::ResponseMsg(action_sender, None), FetchChannels::ResponseMsg(action_sender),
)) ))
.unwrap(); .unwrap();

View file

@ -112,5 +112,5 @@ pub(crate) fn fetch_image_for_layout(
.pipeline_id(Some(document.global().pipeline_id())); .pipeline_id(Some(document.global().pipeline_id()));
// Layout image loads do not delay the document load event. // Layout image loads do not delay the document load event.
document.fetch_background(request, context, None); document.fetch_background(request, context);
} }

View file

@ -13,7 +13,6 @@ use base::id::{BrowsingContextId, PipelineId, TopLevelBrowsingContextId};
use content_security_policy::Destination; use content_security_policy::Destination;
use crossbeam_channel::Sender; use crossbeam_channel::Sender;
use http::header; use http::header;
use ipc_channel::ipc;
use net_traits::request::{CredentialsMode, RedirectMode, RequestBuilder, RequestMode}; use net_traits::request::{CredentialsMode, RedirectMode, RequestBuilder, RequestMode};
use net_traits::response::ResponseInit; use net_traits::response::ResponseInit;
use net_traits::{ use net_traits::{
@ -55,13 +54,11 @@ impl NavigationListener {
self, self,
core_resource_thread: &CoreResourceThread, core_resource_thread: &CoreResourceThread,
response_init: Option<ResponseInit>, response_init: Option<ResponseInit>,
cancellation_receiver: Option<ipc::IpcReceiver<()>>,
) { ) {
fetch_async( fetch_async(
core_resource_thread, core_resource_thread,
self.request_builder.clone(), self.request_builder.clone(),
response_init, response_init,
cancellation_receiver,
self.into_callback(), self.into_callback(),
); );
} }

View file

@ -1780,7 +1780,7 @@ fn fetch_single_module_script(
network_listener.into_callback(), network_listener.into_callback(),
); );
}, },
None => global.fetch_with_network_listener(request, network_listener, None), None => global.fetch_with_network_listener(request, network_listener),
} }
} }

View file

@ -139,6 +139,7 @@ use crate::dom::window::Window;
use crate::dom::windowproxy::{CreatorBrowsingContextInfo, WindowProxy}; use crate::dom::windowproxy::{CreatorBrowsingContextInfo, WindowProxy};
use crate::dom::worklet::WorkletThreadPool; use crate::dom::worklet::WorkletThreadPool;
use crate::dom::workletglobalscope::WorkletGlobalScopeInit; use crate::dom::workletglobalscope::WorkletGlobalScopeInit;
use crate::fetch::FetchCanceller;
use crate::messaging::{ use crate::messaging::{
CommonScriptMsg, MainThreadScriptMsg, MixedMessage, ScriptEventLoopSender, CommonScriptMsg, MainThreadScriptMsg, MixedMessage, ScriptEventLoopSender,
ScriptThreadReceivers, ScriptThreadSenders, ScriptThreadReceivers, ScriptThreadSenders,
@ -3426,17 +3427,10 @@ impl ScriptThread {
.borrow_mut() .borrow_mut()
.push((incomplete.pipeline_id, context)); .push((incomplete.pipeline_id, context));
let cancellation_receiver = incomplete.canceller.initialize(); let request_builder = incomplete.request_builder();
NavigationListener::new( incomplete.canceller = FetchCanceller::new(request_builder.id);
incomplete.request_builder(), NavigationListener::new(request_builder, self.senders.self_sender.clone())
self.senders.self_sender.clone(), .initiate_fetch(&self.resource_threads.core_thread, None);
)
.initiate_fetch(
&self.resource_threads.core_thread,
None,
Some(cancellation_receiver),
);
self.incomplete_loads.borrow_mut().push(incomplete); self.incomplete_loads.borrow_mut().push(incomplete);
} }
@ -3557,12 +3551,9 @@ impl ScriptThread {
.unwrap_or(200), .unwrap_or(200),
}); });
let cancellation_receiver = incomplete_load.canceller.initialize(); incomplete_load.canceller = FetchCanceller::new(request_builder.id);
NavigationListener::new(request_builder, self.senders.self_sender.clone()).initiate_fetch( NavigationListener::new(request_builder, self.senders.self_sender.clone())
&self.resource_threads.core_thread, .initiate_fetch(&self.resource_threads.core_thread, response_init);
response_init,
Some(cancellation_receiver),
);
} }
/// Synchronously fetch `about:blank`. Stores the `InProgressLoad` /// Synchronously fetch `about:blank`. Stores the `InProgressLoad`
@ -3590,7 +3581,7 @@ impl ScriptThread {
self.incomplete_loads.borrow_mut().push(incomplete); self.incomplete_loads.borrow_mut().push(incomplete);
let dummy_request_id = RequestId::next(); let dummy_request_id = RequestId::default();
context.process_response(dummy_request_id, Ok(FetchMetadata::Unfiltered(meta))); context.process_response(dummy_request_id, Ok(FetchMetadata::Unfiltered(meta)));
context.process_response_chunk(dummy_request_id, chunk); context.process_response_chunk(dummy_request_id, chunk);
context.process_response_eof( context.process_response_eof(
@ -3614,7 +3605,8 @@ impl ScriptThread {
self.incomplete_loads.borrow_mut().push(incomplete); self.incomplete_loads.borrow_mut().push(incomplete);
let mut context = ParserContext::new(id, url); let mut context = ParserContext::new(id, url);
let dummy_request_id = RequestId::next(); let dummy_request_id = RequestId::default();
context.process_response(dummy_request_id, Ok(FetchMetadata::Unfiltered(meta))); context.process_response(dummy_request_id, Ok(FetchMetadata::Unfiltered(meta)));
context.process_response_chunk(dummy_request_id, chunk); context.process_response_chunk(dummy_request_id, chunk);
context.process_response_eof( context.process_response_eof(

View file

@ -464,10 +464,7 @@ pub enum WebSocketNetworkEvent {
#[derive(Debug, Deserialize, Serialize)] #[derive(Debug, Deserialize, Serialize)]
/// IPC channels to communicate with the script thread about network or DOM events. /// IPC channels to communicate with the script thread about network or DOM events.
pub enum FetchChannels { pub enum FetchChannels {
ResponseMsg( ResponseMsg(IpcSender<FetchResponseMsg>),
IpcSender<FetchResponseMsg>,
/* cancel_chan */ Option<IpcReceiver<()>>,
),
WebSocket { WebSocket {
event_sender: IpcSender<WebSocketNetworkEvent>, event_sender: IpcSender<WebSocketNetworkEvent>,
action_receiver: IpcReceiver<WebSocketDomAction>, action_receiver: IpcReceiver<WebSocketDomAction>,
@ -480,13 +477,9 @@ pub enum FetchChannels {
#[derive(Debug, Deserialize, Serialize)] #[derive(Debug, Deserialize, Serialize)]
pub enum CoreResourceMsg { pub enum CoreResourceMsg {
Fetch(RequestBuilder, FetchChannels), Fetch(RequestBuilder, FetchChannels),
Cancel(Vec<RequestId>),
/// Initiate a fetch in response to processing a redirection /// Initiate a fetch in response to processing a redirection
FetchRedirect( FetchRedirect(RequestBuilder, ResponseInit, IpcSender<FetchResponseMsg>),
RequestBuilder,
ResponseInit,
IpcSender<FetchResponseMsg>,
/* cancel_chan */ Option<IpcReceiver<()>>,
),
/// Store a cookie for a given originating URL /// Store a cookie for a given originating URL
SetCookieForUrl(ServoUrl, Serde<Cookie<'static>>, CookieSource), SetCookieForUrl(ServoUrl, Serde<Cookie<'static>>, CookieSource),
/// Store a set of cookies for a given originating URL /// 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 // FIXME: https://github.com/servo/servo/issues/34591
#[expect(clippy::large_enum_variant)] #[expect(clippy::large_enum_variant)]
enum ToFetchThreadMessage { enum ToFetchThreadMessage {
Cancel(Vec<RequestId>),
StartFetch( StartFetch(
/* request_builder */ RequestBuilder, /* request_builder */ RequestBuilder,
/* response_init */ Option<ResponseInit>, /* response_init */ Option<ResponseInit>,
/* cancel_chan */ Option<IpcReceiver<()>>,
/* callback */ BoxedFetchCallback, /* callback */ BoxedFetchCallback,
), ),
FetchResponse(FetchResponseMsg), FetchResponse(FetchResponseMsg),
@ -584,12 +577,7 @@ impl FetchThread {
fn run(&mut self) { fn run(&mut self) {
loop { loop {
match self.receiver.recv().unwrap() { match self.receiver.recv().unwrap() {
ToFetchThreadMessage::StartFetch( ToFetchThreadMessage::StartFetch(request_builder, response_init, callback) => {
request_builder,
response_init,
canceller,
callback,
) => {
self.active_fetches.insert(request_builder.id, callback); self.active_fetches.insert(request_builder.id, callback);
// Only redirects have a `response_init` field. // Only redirects have a `response_init` field.
@ -598,11 +586,10 @@ impl FetchThread {
request_builder, request_builder,
response_init, response_init,
self.to_fetch_sender.clone(), self.to_fetch_sender.clone(),
canceller,
), ),
None => CoreResourceMsg::Fetch( None => CoreResourceMsg::Fetch(
request_builder, 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); 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, core_resource_thread: &CoreResourceThread,
request: RequestBuilder, request: RequestBuilder,
response_init: Option<ResponseInit>, response_init: Option<ResponseInit>,
canceller: Option<IpcReceiver<()>>,
callback: BoxedFetchCallback, callback: BoxedFetchCallback,
) { ) {
let _ = FETCH_THREAD let _ = FETCH_THREAD
@ -643,11 +637,19 @@ pub fn fetch_async(
.send(ToFetchThreadMessage::StartFetch( .send(ToFetchThreadMessage::StartFetch(
request, request,
response_init, response_init,
canceller,
callback, 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)] #[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
pub struct ResourceCorsData { pub struct ResourceCorsData {
/// CORS Preflight flag /// CORS Preflight flag

View file

@ -2,7 +2,6 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use base::id::{PipelineId, TopLevelBrowsingContextId}; use base::id::{PipelineId, TopLevelBrowsingContextId};
@ -14,6 +13,7 @@ use malloc_size_of_derive::MallocSizeOf;
use mime::Mime; use mime::Mime;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use servo_url::{ImmutableOrigin, ServoUrl}; use servo_url::{ImmutableOrigin, ServoUrl};
use uuid::Uuid;
use crate::policy_container::{PolicyContainer, RequestPolicyContainer}; use crate::policy_container::{PolicyContainer, RequestPolicyContainer};
use crate::response::HttpsState; use crate::response::HttpsState;
@ -21,12 +21,11 @@ use crate::{ReferrerPolicy, ResourceTimingType};
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)] #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)]
/// An id to differeniate one network request from another. /// An id to differeniate one network request from another.
pub struct RequestId(usize); pub struct RequestId(Uuid);
impl RequestId { impl Default for RequestId {
pub fn next() -> Self { fn default() -> Self {
static NEXT_REQUEST_ID: AtomicUsize = AtomicUsize::new(0); Self(servo_rand::random_uuid())
Self(NEXT_REQUEST_ID.fetch_add(1, Ordering::Relaxed))
} }
} }
@ -283,7 +282,7 @@ pub struct RequestBuilder {
impl RequestBuilder { impl RequestBuilder {
pub fn new(url: ServoUrl, referrer: Referrer) -> RequestBuilder { pub fn new(url: ServoUrl, referrer: Referrer) -> RequestBuilder {
RequestBuilder { RequestBuilder {
id: RequestId::next(), id: RequestId::default(),
method: Method::GET, method: Method::GET,
url, url,
headers: HeaderMap::new(), headers: HeaderMap::new(),
@ -471,8 +470,9 @@ impl RequestBuilder {
/// the Fetch spec. /// the Fetch spec.
#[derive(Clone, MallocSizeOf)] #[derive(Clone, MallocSizeOf)]
pub struct Request { pub struct Request {
/// The id of this request so that the task that triggered it can route /// The unique id of this request so that the task that triggered it can route
/// messages to the correct listeners. /// messages to the correct listeners. This is a UUID that is generated when a request
/// is being built.
pub id: RequestId, pub id: RequestId,
/// <https://fetch.spec.whatwg.org/#concept-request-method> /// <https://fetch.spec.whatwg.org/#concept-request-method>
#[ignore_malloc_size_of = "Defined in hyper"] #[ignore_malloc_size_of = "Defined in hyper"]