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