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