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