1use std::borrow::ToOwned;
8use std::collections::HashMap;
9use std::fs::File;
10use std::io::{self, BufReader};
11use std::path::{Path, PathBuf};
12use std::sync::{Arc, Weak};
13use std::thread;
14
15use base::generic_channel::{self, GenericReceiver, GenericReceiverSet, GenericSelectionResult};
16use base::id::CookieStoreId;
17use cookie::Cookie;
18use crossbeam_channel::Sender;
19use devtools_traits::DevtoolsControlMsg;
20use embedder_traits::GenericEmbedderProxy;
21use hyper_serde::Serde;
22use ipc_channel::ipc::{IpcReceiver, IpcSender};
23use log::{debug, trace, warn};
24use net_traits::blob_url_store::parse_blob_url;
25use net_traits::filemanager_thread::FileTokenCheck;
26use net_traits::pub_domains::public_suffix_list_size_of;
27use net_traits::request::{Destination, PreloadEntry, PreloadId, RequestBuilder, RequestId};
28use net_traits::response::{Response, ResponseInit};
29use net_traits::{
30 AsyncRuntime, CookieAsyncResponse, CookieData, CookieSource, CoreResourceMsg,
31 CoreResourceThread, CustomResponseMediator, DiscardFetch, FetchChannels, FetchTaskTarget,
32 ResourceFetchTiming, ResourceThreads, ResourceTimingType, WebSocketDomAction,
33 WebSocketNetworkEvent,
34};
35use parking_lot::{Mutex, RwLock};
36use profile_traits::mem::{
37 ProcessReports, ProfilerChan as MemProfilerChan, Report, ReportKind, ReportsChan,
38 perform_memory_report,
39};
40use profile_traits::path;
41use profile_traits::time::ProfilerChan;
42use rustc_hash::FxHashMap;
43use rustls_pki_types::CertificateDer;
44use rustls_pki_types::pem::PemObject;
45use serde::{Deserialize, Serialize};
46use servo_arc::Arc as ServoArc;
47use servo_url::{ImmutableOrigin, ServoUrl};
48use tokio::sync::Mutex as TokioMutex;
49
50use crate::async_runtime::{init_async_runtime, spawn_task};
51use crate::connector::{
52 CACertificates, CertificateErrorOverrideManager, create_http_client, create_tls_config,
53};
54use crate::cookie::ServoCookie;
55use crate::cookie_storage::CookieStorage;
56use crate::embedder::NetToEmbedderMsg;
57use crate::fetch::cors_cache::CorsCache;
58use crate::fetch::fetch_params::{FetchParams, SharedPreloadedResources};
59use crate::fetch::methods::{
60 CancellationListener, FetchContext, SharedInflightKeepAliveRecords, WebSocketChannel, fetch,
61};
62use crate::filemanager_thread::FileManager;
63use crate::hsts::{self, HstsList};
64use crate::http_cache::HttpCache;
65use crate::http_loader::{HttpState, http_redirect_fetch};
66use crate::protocols::ProtocolRegistry;
67use crate::request_interceptor::RequestInterceptor;
68use crate::websocket_loader::create_handshake_request;
69
70fn load_root_cert_store_from_file(file_path: String) -> io::Result<Vec<CertificateDer<'static>>> {
72 let mut pem = BufReader::new(File::open(file_path)?);
73
74 let certs = CertificateDer::pem_reader_iter(&mut pem)
75 .filter_map(|cert| {
76 cert.inspect_err(|e| log::error!("Could not load certificate ({e}). Ignoring it."))
77 .ok()
78 })
79 .collect();
80 Ok(certs)
81}
82
83#[expect(clippy::too_many_arguments)]
85pub fn new_resource_threads(
86 devtools_sender: Option<Sender<DevtoolsControlMsg>>,
87 time_profiler_chan: ProfilerChan,
88 mem_profiler_chan: MemProfilerChan,
89 embedder_proxy: GenericEmbedderProxy<NetToEmbedderMsg>,
90 config_dir: Option<PathBuf>,
91 certificate_path: Option<String>,
92 ignore_certificate_errors: bool,
93 protocols: Arc<ProtocolRegistry>,
94) -> (ResourceThreads, ResourceThreads, Box<dyn AsyncRuntime>) {
95 let async_runtime = init_async_runtime();
97
98 let ca_certificates = certificate_path
99 .and_then(|path| {
100 Some(CACertificates::Override(
101 load_root_cert_store_from_file(path).ok()?,
102 ))
103 })
104 .unwrap_or_default();
105
106 let (public_core, private_core) = new_core_resource_thread(
107 devtools_sender,
108 time_profiler_chan,
109 mem_profiler_chan.clone(),
110 embedder_proxy,
111 config_dir.clone(),
112 ca_certificates,
113 ignore_certificate_errors,
114 protocols,
115 );
116 (
117 ResourceThreads::new(public_core),
118 ResourceThreads::new(private_core),
119 async_runtime,
120 )
121}
122
123#[expect(clippy::too_many_arguments)]
125pub fn new_core_resource_thread(
126 devtools_sender: Option<Sender<DevtoolsControlMsg>>,
127 time_profiler_chan: ProfilerChan,
128 mem_profiler_chan: MemProfilerChan,
129 embedder_proxy: GenericEmbedderProxy<NetToEmbedderMsg>,
130 config_dir: Option<PathBuf>,
131 ca_certificates: CACertificates<'static>,
132 ignore_certificate_errors: bool,
133 protocols: Arc<ProtocolRegistry>,
134) -> (CoreResourceThread, CoreResourceThread) {
135 let (public_setup_chan, public_setup_port) = generic_channel::channel().unwrap();
136 let (private_setup_chan, private_setup_port) = generic_channel::channel().unwrap();
137 let (report_chan, report_port) = generic_channel::channel().unwrap();
138
139 thread::Builder::new()
140 .name("ResourceManager".to_owned())
141 .spawn(move || {
142 let resource_manager = CoreResourceManager::new(
143 devtools_sender,
144 time_profiler_chan,
145 embedder_proxy.clone(),
146 ca_certificates.clone(),
147 ignore_certificate_errors,
148 );
149
150 let mut channel_manager = ResourceChannelManager {
151 resource_manager,
152 config_dir,
153 ca_certificates,
154 ignore_certificate_errors,
155 cancellation_listeners: Default::default(),
156 cookie_listeners: Default::default(),
157 };
158
159 mem_profiler_chan.run_with_memory_reporting(
160 || {
161 channel_manager.start(
162 public_setup_port,
163 private_setup_port,
164 report_port,
165 protocols,
166 embedder_proxy,
167 )
168 },
169 String::from("network-cache-reporter"),
170 report_chan,
171 CoreResourceMsg::CollectMemoryReport,
172 );
173 })
174 .expect("Thread spawning failed");
175 (public_setup_chan, private_setup_chan)
176}
177
178struct ResourceChannelManager {
179 resource_manager: CoreResourceManager,
180 config_dir: Option<PathBuf>,
181 ca_certificates: CACertificates<'static>,
182 ignore_certificate_errors: bool,
183 cancellation_listeners: FxHashMap<RequestId, Weak<CancellationListener>>,
184 cookie_listeners: FxHashMap<CookieStoreId, IpcSender<CookieAsyncResponse>>,
185}
186
187fn create_http_states(
189 config_dir: Option<&Path>,
190 ca_certificates: CACertificates<'static>,
191 ignore_certificate_errors: bool,
192 embedder_proxy: GenericEmbedderProxy<NetToEmbedderMsg>,
193) -> (Arc<HttpState>, Arc<HttpState>) {
194 let mut hsts_list = HstsList::default();
195 let mut auth_cache = AuthCache::default();
196 let mut cookie_jar = CookieStorage::new(150);
197 if let Some(config_dir) = config_dir {
198 base::read_json_from_file(&mut auth_cache, config_dir, "auth_cache.json");
199 base::read_json_from_file(&mut hsts_list, config_dir, "hsts_list.json");
200 base::read_json_from_file(&mut cookie_jar, config_dir, "cookie_jar.json");
201 }
202
203 let override_manager = CertificateErrorOverrideManager::new();
204 let http_state = HttpState {
205 hsts_list: RwLock::new(hsts_list),
206 cookie_jar: RwLock::new(cookie_jar),
207 auth_cache: RwLock::new(auth_cache),
208 history_states: RwLock::new(FxHashMap::default()),
209 http_cache: HttpCache::default(),
210 client: create_http_client(create_tls_config(
211 ca_certificates.clone(),
212 ignore_certificate_errors,
213 override_manager.clone(),
214 )),
215 override_manager,
216 embedder_proxy: embedder_proxy.clone(),
217 };
218
219 let override_manager = CertificateErrorOverrideManager::new();
220 let private_http_state = HttpState {
221 hsts_list: RwLock::new(HstsList::default()),
222 cookie_jar: RwLock::new(CookieStorage::new(150)),
223 auth_cache: RwLock::new(AuthCache::default()),
224 history_states: RwLock::new(FxHashMap::default()),
225 http_cache: HttpCache::default(),
226 client: create_http_client(create_tls_config(
227 ca_certificates,
228 ignore_certificate_errors,
229 override_manager.clone(),
230 )),
231 override_manager,
232 embedder_proxy,
233 };
234
235 (Arc::new(http_state), Arc::new(private_http_state))
236}
237
238impl ResourceChannelManager {
239 fn start(
240 &mut self,
241 public_receiver: GenericReceiver<CoreResourceMsg>,
242 private_receiver: GenericReceiver<CoreResourceMsg>,
243 memory_reporter: GenericReceiver<CoreResourceMsg>,
244 protocols: Arc<ProtocolRegistry>,
245 embedder_proxy: GenericEmbedderProxy<NetToEmbedderMsg>,
246 ) {
247 let (public_http_state, private_http_state) = create_http_states(
248 self.config_dir.as_deref(),
249 self.ca_certificates.clone(),
250 self.ignore_certificate_errors,
251 embedder_proxy,
252 );
253
254 let mut rx_set = GenericReceiverSet::new();
255 let private_id = rx_set.add(private_receiver);
256 let public_id = rx_set.add(public_receiver);
257 let reporter_id = rx_set.add(memory_reporter);
258
259 loop {
260 for received in rx_set.select().into_iter() {
261 match received {
263 GenericSelectionResult::ChannelClosed(_) => continue,
264 GenericSelectionResult::Error(error) => {
265 log::error!("Found selection error: {error}")
266 },
267 GenericSelectionResult::MessageReceived(id, msg) => {
268 if id == reporter_id {
269 if let CoreResourceMsg::CollectMemoryReport(report_chan) = msg {
270 self.process_report(
271 report_chan,
272 &public_http_state,
273 &private_http_state,
274 );
275 continue;
276 } else {
277 log::error!("memory reporter should only send CollectMemoryReport");
278 }
279 } else {
280 let group = if id == private_id {
281 &private_http_state
282 } else {
283 assert_eq!(id, public_id);
284 &public_http_state
285 };
286 if !self.process_msg(msg, group, Arc::clone(&protocols)) {
287 return;
288 }
289 }
290 },
291 }
292 }
293 }
294 }
295
296 fn process_report(
297 &mut self,
298 msg: ReportsChan,
299 public_http_state: &Arc<HttpState>,
300 private_http_state: &Arc<HttpState>,
301 ) {
302 perform_memory_report(|ops| {
303 let mut reports = public_http_state.memory_reports("public", ops);
304 reports.extend(private_http_state.memory_reports("private", ops));
305 reports.extend(vec![
306 Report {
307 path: path!["hsts-preload-list"],
308 kind: ReportKind::ExplicitJemallocHeapSize,
309 size: hsts::hsts_preload_size_of(ops),
310 },
311 Report {
312 path: path!["public-suffix-list"],
313 kind: ReportKind::ExplicitJemallocHeapSize,
314 size: public_suffix_list_size_of(ops),
315 },
316 ]);
317 msg.send(ProcessReports::new(reports));
318 })
319 }
320
321 fn cancellation_listener(&self, request_id: RequestId) -> Option<Arc<CancellationListener>> {
322 self.cancellation_listeners
323 .get(&request_id)
324 .and_then(Weak::upgrade)
325 }
326
327 fn get_or_create_cancellation_listener(
328 &mut self,
329 request_id: RequestId,
330 ) -> Arc<CancellationListener> {
331 if let Some(listener) = self.cancellation_listener(request_id) {
332 return listener;
333 }
334
335 self.cancellation_listeners
337 .retain(|_, listener| listener.strong_count() > 0);
338
339 let cancellation_listener = Arc::new(Default::default());
340 self.cancellation_listeners
341 .insert(request_id, Arc::downgrade(&cancellation_listener));
342 cancellation_listener
343 }
344
345 fn send_cookie_response(&self, store_id: CookieStoreId, data: CookieData) {
346 let Some(sender) = self.cookie_listeners.get(&store_id) else {
347 warn!(
348 "Async cookie request made for store id that is non-existent {:?}",
349 store_id
350 );
351 return;
352 };
353 let res = sender.send(CookieAsyncResponse { data });
354 if res.is_err() {
355 warn!("Unable to send cookie response to script thread");
356 }
357 }
358
359 fn process_msg(
361 &mut self,
362 msg: CoreResourceMsg,
363 http_state: &Arc<HttpState>,
364 protocols: Arc<ProtocolRegistry>,
365 ) -> bool {
366 match msg {
367 CoreResourceMsg::Fetch(request_builder, channels) => match channels {
368 FetchChannels::ResponseMsg(sender) => {
369 let cancellation_listener =
370 self.get_or_create_cancellation_listener(request_builder.id);
371 self.resource_manager.fetch(
372 request_builder,
373 None,
374 sender,
375 http_state,
376 cancellation_listener,
377 protocols,
378 );
379 },
380 FetchChannels::WebSocket {
381 event_sender,
382 action_receiver,
383 } => {
384 let cancellation_listener =
385 self.get_or_create_cancellation_listener(request_builder.id);
386
387 self.resource_manager.websocket_connect(
388 request_builder,
389 event_sender,
390 action_receiver,
391 http_state,
392 cancellation_listener,
393 protocols,
394 )
395 },
396 FetchChannels::Prefetch => self.resource_manager.fetch(
397 request_builder,
398 None,
399 DiscardFetch,
400 http_state,
401 Arc::new(Default::default()),
402 protocols,
403 ),
404 },
405 CoreResourceMsg::Cancel(request_ids) => {
406 for cancellation_listener in request_ids
407 .into_iter()
408 .filter_map(|request_id| self.cancellation_listener(request_id))
409 {
410 cancellation_listener.cancel();
411 }
412 },
413 CoreResourceMsg::DeleteCookiesForSites(sites, sender) => {
414 http_state
415 .cookie_jar
416 .write()
417 .delete_cookies_for_sites(&sites);
418 let _ = sender.send(());
419 },
420 CoreResourceMsg::DeleteCookies(request, sender) => {
421 http_state
422 .cookie_jar
423 .write()
424 .clear_storage(request.as_ref());
425 if let Some(sender) = sender {
426 let _ = sender.send(());
427 }
428 return true;
429 },
430 CoreResourceMsg::DeleteCookie(request, name) => {
431 http_state
432 .cookie_jar
433 .write()
434 .delete_cookie_with_name(&request, name);
435 return true;
436 },
437 CoreResourceMsg::DeleteCookieAsync(cookie_store_id, url, name) => {
438 http_state
439 .cookie_jar
440 .write()
441 .delete_cookie_with_name(&url, name);
442 self.send_cookie_response(cookie_store_id, CookieData::Delete(Ok(())));
443 },
444 CoreResourceMsg::FetchRedirect(request_builder, res_init, sender) => {
445 let cancellation_listener =
446 self.get_or_create_cancellation_listener(request_builder.id);
447 self.resource_manager.fetch(
448 request_builder,
449 Some(res_init),
450 sender,
451 http_state,
452 cancellation_listener,
453 protocols,
454 )
455 },
456 CoreResourceMsg::SetCookieForUrl(request, cookie, source) => self
457 .resource_manager
458 .set_cookie_for_url(&request, cookie.into_inner().to_owned(), source, http_state),
459 CoreResourceMsg::SetCookiesForUrl(request, cookies, source) => {
460 for cookie in cookies {
461 self.resource_manager.set_cookie_for_url(
462 &request,
463 cookie.into_inner(),
464 source,
465 http_state,
466 );
467 }
468 },
469 CoreResourceMsg::SetCookieForUrlAsync(cookie_store_id, url, cookie, source) => {
470 self.resource_manager.set_cookie_for_url(
471 &url,
472 cookie.into_inner().to_owned(),
473 source,
474 http_state,
475 );
476 self.send_cookie_response(cookie_store_id, CookieData::Set(Ok(())));
477 },
478 CoreResourceMsg::GetCookiesForUrl(url, consumer, source) => {
479 let mut cookie_jar = http_state.cookie_jar.write();
480 cookie_jar.remove_expired_cookies_for_url(&url);
481 consumer
482 .send(cookie_jar.cookies_for_url(&url, source))
483 .unwrap();
484 },
485 CoreResourceMsg::GetCookieDataForUrlAsync(cookie_store_id, url, name) => {
486 let mut cookie_jar = http_state.cookie_jar.write();
487 cookie_jar.remove_expired_cookies_for_url(&url);
488 let cookie = cookie_jar
489 .query_cookies(&url, name)
490 .into_iter()
491 .map(Serde)
492 .next();
493 self.send_cookie_response(cookie_store_id, CookieData::Get(cookie));
494 },
495 CoreResourceMsg::GetAllCookieDataForUrlAsync(cookie_store_id, url, name) => {
496 let mut cookie_jar = http_state.cookie_jar.write();
497 cookie_jar.remove_expired_cookies_for_url(&url);
498 let cookies = cookie_jar
499 .query_cookies(&url, name)
500 .into_iter()
501 .map(Serde)
502 .collect();
503 self.send_cookie_response(cookie_store_id, CookieData::GetAll(cookies));
504 },
505 CoreResourceMsg::NewCookieListener(cookie_store_id, sender, _url) => {
506 self.cookie_listeners.insert(cookie_store_id, sender);
508 },
509 CoreResourceMsg::RemoveCookieListener(cookie_store_id) => {
510 self.cookie_listeners.remove(&cookie_store_id);
511 },
512 CoreResourceMsg::NetworkMediator(mediator_chan, origin) => {
513 self.resource_manager
514 .sw_managers
515 .insert(origin, mediator_chan);
516 },
517 CoreResourceMsg::GetCookiesDataForUrl(url, consumer, source) => {
518 let mut cookie_jar = http_state.cookie_jar.write();
519 cookie_jar.remove_expired_cookies_for_url(&url);
520 let cookies = cookie_jar
521 .cookies_data_for_url(&url, source)
522 .map(Serde)
523 .collect();
524 consumer.send(cookies).unwrap();
525 },
526 CoreResourceMsg::ListCookies(sender) => {
527 let mut cookie_jar = http_state.cookie_jar.write();
528 cookie_jar.remove_all_expired_cookies();
529 let _ = sender.send(cookie_jar.cookie_site_descriptors());
530 },
531 CoreResourceMsg::GetHistoryState(history_state_id, consumer) => {
532 let history_states = http_state.history_states.read();
533 consumer
534 .send(history_states.get(&history_state_id).cloned())
535 .unwrap();
536 },
537 CoreResourceMsg::SetHistoryState(history_state_id, structured_data) => {
538 let mut history_states = http_state.history_states.write();
539 history_states.insert(history_state_id, structured_data);
540 },
541 CoreResourceMsg::RemoveHistoryStates(states_to_remove) => {
542 let mut history_states = http_state.history_states.write();
543 for history_state in states_to_remove {
544 history_states.remove(&history_state);
545 }
546 },
547 CoreResourceMsg::GetCacheEntries(sender) => {
548 let _ = sender.send(http_state.http_cache.cache_entry_descriptors());
549 },
550 CoreResourceMsg::ClearCache(sender) => {
551 http_state.http_cache.clear();
552 if let Some(sender) = sender {
553 let _ = sender.send(());
554 }
555 },
556 CoreResourceMsg::ToFileManager(msg) => self.resource_manager.filemanager.handle(msg),
557 CoreResourceMsg::StorePreloadedResponse(preload_id, response) => self
558 .resource_manager
559 .handle_preloaded_response(preload_id, response),
560 CoreResourceMsg::TotalSizeOfInFlightKeepAliveRecords(pipeline_id, sender) => {
561 let total = self
562 .resource_manager
563 .in_flight_keep_alive_records
564 .lock()
565 .get(&pipeline_id)
566 .map(|records| {
567 records
568 .iter()
569 .map(|record| record.keep_alive_body_length)
570 .sum()
571 })
572 .unwrap_or_default();
573 let _ = sender.send(total);
574 },
575 CoreResourceMsg::Exit(sender) => {
576 if let Some(ref config_dir) = self.config_dir {
577 let auth_cache = http_state.auth_cache.read();
578 base::write_json_to_file(&*auth_cache, config_dir, "auth_cache.json");
579 let jar = http_state.cookie_jar.read();
580 base::write_json_to_file(&*jar, config_dir, "cookie_jar.json");
581 let hsts = http_state.hsts_list.read();
582 base::write_json_to_file(&*hsts, config_dir, "hsts_list.json");
583 }
584 self.resource_manager.exit();
585 let _ = sender.send(());
586 return false;
587 },
588 CoreResourceMsg::CollectMemoryReport(_) => {},
590 }
591 true
592 }
593}
594
595#[derive(Clone, Debug, Deserialize, Serialize)]
596pub struct AuthCacheEntry {
597 pub user_name: String,
598 pub password: String,
599}
600
601impl Default for AuthCache {
602 fn default() -> Self {
603 Self {
604 version: 1,
605 entries: HashMap::new(),
606 }
607 }
608}
609
610#[derive(Clone, Debug, Deserialize, Serialize)]
611pub struct AuthCache {
612 pub version: u32,
613 pub entries: HashMap<String, AuthCacheEntry>,
614}
615
616pub struct CoreResourceManager {
617 devtools_sender: Option<Sender<DevtoolsControlMsg>>,
618 sw_managers: HashMap<ImmutableOrigin, IpcSender<CustomResponseMediator>>,
619 filemanager: FileManager,
620 request_interceptor: RequestInterceptor,
621 ca_certificates: CACertificates<'static>,
622 ignore_certificate_errors: bool,
623 preloaded_resources: SharedPreloadedResources,
624 in_flight_keep_alive_records: SharedInflightKeepAliveRecords,
626}
627
628impl CoreResourceManager {
629 pub fn new(
630 devtools_sender: Option<Sender<DevtoolsControlMsg>>,
631 _profiler_chan: ProfilerChan,
632 embedder_proxy: GenericEmbedderProxy<NetToEmbedderMsg>,
633 ca_certificates: CACertificates<'static>,
634 ignore_certificate_errors: bool,
635 ) -> CoreResourceManager {
636 CoreResourceManager {
637 devtools_sender,
638 sw_managers: Default::default(),
639 filemanager: FileManager::new(embedder_proxy.clone()),
640 request_interceptor: RequestInterceptor::new(embedder_proxy),
641 ca_certificates,
642 ignore_certificate_errors,
643 preloaded_resources: Default::default(),
644 in_flight_keep_alive_records: Default::default(),
645 }
646 }
647
648 fn handle_preloaded_response(&self, preload_id: PreloadId, response: Response) {
649 let mut preloaded_resources = self.preloaded_resources.lock().unwrap();
650 if let Some(entry) = preloaded_resources.get_mut(&preload_id) {
651 entry.with_response(response);
652 }
653 }
654
655 pub fn exit(&mut self) {
657 debug!("Exited CoreResourceManager");
658 }
659
660 fn set_cookie_for_url(
661 &mut self,
662 request: &ServoUrl,
663 cookie: Cookie<'static>,
664 source: CookieSource,
665 http_state: &Arc<HttpState>,
666 ) {
667 if let Some(cookie) = ServoCookie::new_wrapped(cookie, request, source) {
668 let mut cookie_jar = http_state.cookie_jar.write();
669 cookie_jar.push(cookie, request, source)
670 }
671 }
672
673 fn fetch<Target: 'static + FetchTaskTarget + Send>(
674 &self,
675 request_builder: RequestBuilder,
676 res_init_: Option<ResponseInit>,
677 mut sender: Target,
678 http_state: &Arc<HttpState>,
679 cancellation_listener: Arc<CancellationListener>,
680 protocols: Arc<ProtocolRegistry>,
681 ) {
682 let http_state = http_state.clone();
683 let devtools_chan = self.devtools_sender.clone();
684 let filemanager = self.filemanager.clone();
685 let request_interceptor = self.request_interceptor.clone();
686
687 let timing_type = match request_builder.destination {
688 Destination::Document => ResourceTimingType::Navigation,
689 _ => ResourceTimingType::Resource,
690 };
691
692 let request = request_builder.build();
693 let url = request.current_url();
694
695 let (file_token, blob_url_file_id) = match url.scheme() {
706 "blob" => {
707 if let Ok((id, _)) = parse_blob_url(&url) {
708 (self.filemanager.get_token_for_file(&id), Some(id))
709 } else {
710 (FileTokenCheck::ShouldFail, None)
711 }
712 },
713 _ => (FileTokenCheck::NotRequired, None),
714 };
715
716 let ca_certificates = self.ca_certificates.clone();
717 let ignore_certificate_errors = self.ignore_certificate_errors;
718 let in_flight_keep_alive_records = self.in_flight_keep_alive_records.clone();
719 let preloaded_resources = self.preloaded_resources.clone();
720 if let Some(ref preload_id) = request.preload_id {
721 let mut preloaded_resources = self.preloaded_resources.lock().unwrap();
722 let entry = PreloadEntry::new(request.integrity_metadata.clone());
723 preloaded_resources.insert(preload_id.clone(), entry);
724 }
725
726 spawn_task(async move {
727 let context = FetchContext {
732 state: http_state,
733 user_agent: servo_config::pref!(user_agent),
734 devtools_chan,
735 filemanager,
736 file_token,
737 request_interceptor: Arc::new(TokioMutex::new(request_interceptor)),
738 cancellation_listener,
739 timing: ServoArc::new(Mutex::new(ResourceFetchTiming::new(request.timing_type()))),
740 protocols,
741 websocket_chan: None,
742 ca_certificates,
743 ignore_certificate_errors,
744 preloaded_resources,
745 in_flight_keep_alive_records,
746 };
747
748 match res_init_ {
749 Some(res_init) => {
750 let response = Response::from_init(res_init, timing_type);
751
752 let mut fetch_params = FetchParams::new(request);
753 http_redirect_fetch(
754 &mut fetch_params,
755 &mut CorsCache::default(),
756 response,
757 true,
758 &mut sender,
759 &mut None,
760 &context,
761 )
762 .await;
763 },
764 None => {
765 fetch(request, &mut sender, &context).await;
766 },
767 };
768
769 if let Some(id) = blob_url_file_id.as_ref() {
771 context
772 .filemanager
773 .invalidate_token(&context.file_token, id);
774 }
775 });
776 }
777
778 fn websocket_connect(
780 &self,
781 mut request: RequestBuilder,
782 event_sender: IpcSender<WebSocketNetworkEvent>,
783 action_receiver: IpcReceiver<WebSocketDomAction>,
784 http_state: &Arc<HttpState>,
785 cancellation_listener: Arc<CancellationListener>,
786 protocols: Arc<ProtocolRegistry>,
787 ) {
788 let http_state = http_state.clone();
789 let devtools_chan = self.devtools_sender.clone();
790 let filemanager = self.filemanager.clone();
791 let request_interceptor = self.request_interceptor.clone();
792
793 let ca_certificates = self.ca_certificates.clone();
794 let ignore_certificate_errors = self.ignore_certificate_errors;
795 let in_flight_keep_alive_records = self.in_flight_keep_alive_records.clone();
796 let preloaded_resources = self.preloaded_resources.clone();
797
798 spawn_task(async move {
799 let mut event_sender = event_sender;
800
801 let scheme = match request.url.scheme() {
804 "ws" => "http",
805 _ => "https",
806 };
807 request
808 .url
809 .as_mut_url()
810 .set_scheme(scheme)
811 .unwrap_or_else(|_| panic!("Can't set scheme to {scheme}"));
812
813 match create_handshake_request(request, http_state.clone()) {
814 Ok(request) => {
815 let context = FetchContext {
816 state: http_state,
817 user_agent: servo_config::pref!(user_agent),
818 devtools_chan,
819 filemanager,
820 file_token: FileTokenCheck::NotRequired,
821 request_interceptor: Arc::new(TokioMutex::new(request_interceptor)),
822 cancellation_listener,
823 timing: ServoArc::new(Mutex::new(ResourceFetchTiming::new(
824 request.timing_type(),
825 ))),
826 protocols: protocols.clone(),
827 websocket_chan: Some(Arc::new(Mutex::new(WebSocketChannel::new(
828 event_sender.clone(),
829 Some(action_receiver),
830 )))),
831 ca_certificates,
832 ignore_certificate_errors,
833 preloaded_resources,
834 in_flight_keep_alive_records,
835 };
836 fetch(request, &mut event_sender, &context).await;
837 },
838 Err(e) => {
839 trace!("unable to create websocket handshake request {:?}", e);
840 let _ = event_sender.send(WebSocketNetworkEvent::Fail);
841 },
842 }
843 });
844 }
845}