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::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
144 thread::Builder::new()
145 .name("ResourceManager".to_owned())
146 .spawn(move || {
147 let resource_manager = CoreResourceManager::new(
148 devtools_sender,
149 time_profiler_chan,
150 embedder_proxy.clone(),
151 ca_certificates.clone(),
152 ignore_certificate_errors,
153 );
154
155 let mut channel_manager = ResourceChannelManager {
156 resource_manager,
157 config_dir,
158 ca_certificates,
159 ignore_certificate_errors,
160 cancellation_listeners: Default::default(),
161 cookie_listeners: Default::default(),
162 };
163
164 mem_profiler_chan.run_with_memory_reporting(
165 || {
166 channel_manager.start(
167 public_setup_port,
168 private_setup_port,
169 report_port,
170 protocols,
171 embedder_proxy,
172 )
173 },
174 String::from("network-cache-reporter"),
175 report_chan,
176 CoreResourceMsg::CollectMemoryReport,
177 );
178 })
179 .expect("Thread spawning failed");
180 (public_setup_chan, private_setup_chan)
181}
182
183struct ResourceChannelManager {
184 resource_manager: CoreResourceManager,
185 config_dir: Option<PathBuf>,
186 ca_certificates: CACertificates<'static>,
187 ignore_certificate_errors: bool,
188 cancellation_listeners: FxHashMap<RequestId, Weak<CancellationListener>>,
189 cookie_listeners: FxHashMap<CookieStoreId, GenericCallback<CookieAsyncResponse>>,
190}
191
192fn create_http_states(
194 config_dir: Option<&Path>,
195 ca_certificates: CACertificates<'static>,
196 ignore_certificate_errors: bool,
197 embedder_proxy: GenericEmbedderProxy<NetToEmbedderMsg>,
198) -> (Arc<HttpState>, Arc<HttpState>) {
199 let mut hsts_list = HstsList::default();
200 let mut auth_cache = AuthCache::default();
201 let mut cookie_jar = CookieStorage::new(150);
202 if let Some(config_dir) = config_dir {
203 servo_base::read_json_from_file(&mut auth_cache, config_dir, "auth_cache.json");
204 servo_base::read_json_from_file(&mut hsts_list, config_dir, "hsts_list.json");
205 servo_base::read_json_from_file(&mut cookie_jar, config_dir, "cookie_jar.json");
206 }
207
208 let override_manager = CertificateErrorOverrideManager::new();
209 let http_state = HttpState {
210 hsts_list: RwLock::new(hsts_list),
211 cookie_jar: RwLock::new(cookie_jar),
212 auth_cache: RwLock::new(auth_cache),
213 history_states: RwLock::new(FxHashMap::default()),
214 http_cache: HttpCache::default(),
215 client: create_http_client(create_tls_config(
216 ca_certificates.clone(),
217 ignore_certificate_errors,
218 override_manager.clone(),
219 )),
220 override_manager,
221 embedder_proxy: embedder_proxy.clone(),
222 };
223
224 let override_manager = CertificateErrorOverrideManager::new();
225 let private_http_state = HttpState {
226 hsts_list: RwLock::new(HstsList::default()),
227 cookie_jar: RwLock::new(CookieStorage::new(150)),
228 auth_cache: RwLock::new(AuthCache::default()),
229 history_states: RwLock::new(FxHashMap::default()),
230 http_cache: HttpCache::default(),
231 client: create_http_client(create_tls_config(
232 ca_certificates,
233 ignore_certificate_errors,
234 override_manager.clone(),
235 )),
236 override_manager,
237 embedder_proxy,
238 };
239
240 (Arc::new(http_state), Arc::new(private_http_state))
241}
242
243impl ResourceChannelManager {
244 fn start(
245 &mut self,
246 public_receiver: GenericReceiver<CoreResourceMsg>,
247 private_receiver: GenericReceiver<CoreResourceMsg>,
248 memory_reporter: GenericReceiver<CoreResourceMsg>,
249 protocols: Arc<ProtocolRegistry>,
250 embedder_proxy: GenericEmbedderProxy<NetToEmbedderMsg>,
251 ) {
252 let (public_http_state, private_http_state) = create_http_states(
253 self.config_dir.as_deref(),
254 self.ca_certificates.clone(),
255 self.ignore_certificate_errors,
256 embedder_proxy,
257 );
258
259 let mut rx_set = GenericReceiverSet::new();
260 let private_id = rx_set.add(private_receiver);
261 let public_id = rx_set.add(public_receiver);
262 let reporter_id = rx_set.add(memory_reporter);
263
264 loop {
265 for received in rx_set.select().into_iter() {
266 match received {
268 GenericSelectionResult::ChannelClosed(_) => continue,
269 GenericSelectionResult::Error(error) => {
270 log::error!("Found selection error: {error}")
271 },
272 GenericSelectionResult::MessageReceived(id, msg) => {
273 if id == reporter_id {
274 if let CoreResourceMsg::CollectMemoryReport(report_chan) = msg {
275 self.process_report(
276 report_chan,
277 &public_http_state,
278 &private_http_state,
279 );
280 continue;
281 } else {
282 log::error!("memory reporter should only send CollectMemoryReport");
283 }
284 } else {
285 let group = if id == private_id {
286 &private_http_state
287 } else {
288 assert_eq!(id, public_id);
289 &public_http_state
290 };
291 if !self.process_msg(msg, group, Arc::clone(&protocols)) {
292 return;
293 }
294 }
295 },
296 }
297 }
298 }
299 }
300
301 fn process_report(
302 &mut self,
303 msg: ReportsChan,
304 public_http_state: &Arc<HttpState>,
305 private_http_state: &Arc<HttpState>,
306 ) {
307 perform_memory_report(|ops| {
308 let mut reports = public_http_state.memory_reports("public", ops);
309 reports.extend(private_http_state.memory_reports("private", ops));
310 reports.extend(vec![
311 Report {
312 path: path!["hsts-preload-list"],
313 kind: ReportKind::ExplicitJemallocHeapSize,
314 size: hsts::hsts_preload_size_of(ops),
315 },
316 Report {
317 path: path!["public-suffix-list"],
318 kind: ReportKind::ExplicitJemallocHeapSize,
319 size: public_suffix_list_size_of(ops),
320 },
321 ]);
322 msg.send(ProcessReports::new(reports));
323 })
324 }
325
326 fn cancellation_listener(&self, request_id: RequestId) -> Option<Arc<CancellationListener>> {
327 self.cancellation_listeners
328 .get(&request_id)
329 .and_then(Weak::upgrade)
330 }
331
332 fn get_or_create_cancellation_listener(
333 &mut self,
334 request_id: RequestId,
335 ) -> Arc<CancellationListener> {
336 if let Some(listener) = self.cancellation_listener(request_id) {
337 return listener;
338 }
339
340 self.cancellation_listeners
342 .retain(|_, listener| listener.strong_count() > 0);
343
344 let cancellation_listener = Arc::new(Default::default());
345 self.cancellation_listeners
346 .insert(request_id, Arc::downgrade(&cancellation_listener));
347 cancellation_listener
348 }
349
350 fn send_cookie_response(&self, store_id: CookieStoreId, data: CookieData) {
351 let Some(sender) = self.cookie_listeners.get(&store_id) else {
352 warn!(
353 "Async cookie request made for store id that is non-existent {:?}",
354 store_id
355 );
356 return;
357 };
358 let res = sender.send(CookieAsyncResponse { data });
359 if res.is_err() {
360 warn!("Unable to send cookie response to script thread");
361 }
362 }
363
364 fn process_msg(
366 &mut self,
367 msg: CoreResourceMsg,
368 http_state: &Arc<HttpState>,
369 protocols: Arc<ProtocolRegistry>,
370 ) -> bool {
371 match msg {
372 CoreResourceMsg::Fetch(request_builder, channels) => match channels {
373 FetchChannels::ResponseMsg(sender) => {
374 let cancellation_listener =
375 self.get_or_create_cancellation_listener(request_builder.id);
376 self.resource_manager.fetch(
377 request_builder,
378 None,
379 sender,
380 http_state,
381 cancellation_listener,
382 protocols,
383 );
384 },
385 FetchChannels::WebSocket {
386 event_sender,
387 action_receiver,
388 } => {
389 let cancellation_listener =
390 self.get_or_create_cancellation_listener(request_builder.id);
391
392 self.resource_manager.websocket_connect(
393 request_builder,
394 event_sender,
395 action_receiver,
396 http_state,
397 cancellation_listener,
398 protocols,
399 )
400 },
401 FetchChannels::Prefetch => self.resource_manager.fetch(
402 request_builder,
403 None,
404 DiscardFetch,
405 http_state,
406 Arc::new(Default::default()),
407 protocols,
408 ),
409 },
410 CoreResourceMsg::Cancel(request_ids) => {
411 for cancellation_listener in request_ids
412 .into_iter()
413 .filter_map(|request_id| self.cancellation_listener(request_id))
414 {
415 cancellation_listener.cancel();
416 }
417 },
418 CoreResourceMsg::DeleteCookiesForSites(sites, sender) => {
419 http_state
420 .cookie_jar
421 .write()
422 .delete_cookies_for_sites(&sites);
423 let _ = sender.send(());
424 },
425 CoreResourceMsg::DeleteCookies(request, sender) => {
426 http_state
427 .cookie_jar
428 .write()
429 .clear_storage(request.as_ref());
430 if let Some(sender) = sender {
431 let _ = sender.send(());
432 }
433 return true;
434 },
435 CoreResourceMsg::DeleteCookie(request, name) => {
436 http_state
437 .cookie_jar
438 .write()
439 .delete_cookie_with_name(&request, name);
440 return true;
441 },
442 CoreResourceMsg::DeleteCookieAsync(cookie_store_id, url, name) => {
443 http_state
444 .cookie_jar
445 .write()
446 .delete_cookie_with_name(&url, name);
447 self.send_cookie_response(cookie_store_id, CookieData::Delete(Ok(())));
448 },
449 CoreResourceMsg::FetchRedirect(request_builder, res_init, sender) => {
450 let cancellation_listener =
451 self.get_or_create_cancellation_listener(request_builder.id);
452 self.resource_manager.fetch(
453 request_builder,
454 Some(res_init),
455 sender,
456 http_state,
457 cancellation_listener,
458 protocols,
459 )
460 },
461 CoreResourceMsg::SetCookieForUrl(request, cookie, source, sender) => {
462 self.resource_manager.set_cookie_for_url(
463 &request,
464 cookie.into_inner().to_owned(),
465 source,
466 http_state,
467 );
468 if let Some(sender) = sender {
469 let _ = sender.send(());
470 }
471 },
472 CoreResourceMsg::SetCookiesForUrl(request, cookies, source) => {
473 for cookie in cookies {
474 self.resource_manager.set_cookie_for_url(
475 &request,
476 cookie.into_inner(),
477 source,
478 http_state,
479 );
480 }
481 },
482 CoreResourceMsg::SetCookieForUrlAsync(cookie_store_id, url, cookie, source) => {
483 self.resource_manager.set_cookie_for_url(
484 &url,
485 cookie.into_inner().to_owned(),
486 source,
487 http_state,
488 );
489 self.send_cookie_response(cookie_store_id, CookieData::Set(Ok(())));
490 },
491 CoreResourceMsg::GetCookieStringForUrl(url, consumer, source) => {
492 let mut cookie_jar = http_state.cookie_jar.write();
493 cookie_jar.remove_expired_cookies_for_url(&url);
494 consumer
495 .send(cookie_jar.cookies_for_url(&url, source))
496 .unwrap();
497 },
498 CoreResourceMsg::GetCookiesForUrl(url, consumer, source) => {
499 let mut cookie_jar = http_state.cookie_jar.write();
500 cookie_jar.remove_expired_cookies_for_url(&url);
501 let cookies = cookie_jar
502 .cookies_data_for_url(&url, source)
503 .map(Serde)
504 .collect();
505 consumer.send(cookies).unwrap();
506 },
507 CoreResourceMsg::GetCookieDataForUrlAsync(cookie_store_id, url, name) => {
508 let mut cookie_jar = http_state.cookie_jar.write();
509 cookie_jar.remove_expired_cookies_for_url(&url);
510 let cookie = cookie_jar
511 .query_cookies(&url, name)
512 .into_iter()
513 .map(Serde)
514 .next();
515 self.send_cookie_response(cookie_store_id, CookieData::Get(cookie));
516 },
517 CoreResourceMsg::GetAllCookieDataForUrlAsync(cookie_store_id, url, name) => {
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 .query_cookies(&url, name)
522 .into_iter()
523 .map(Serde)
524 .collect();
525 self.send_cookie_response(cookie_store_id, CookieData::GetAll(cookies));
526 },
527 CoreResourceMsg::NewCookieListener(cookie_store_id, callback, _url) => {
528 self.cookie_listeners.insert(cookie_store_id, callback);
530 },
531 CoreResourceMsg::RemoveCookieListener(cookie_store_id) => {
532 self.cookie_listeners.remove(&cookie_store_id);
533 },
534 CoreResourceMsg::NetworkMediator(mediator_chan, origin) => {
535 self.resource_manager
536 .sw_managers
537 .insert(origin, mediator_chan);
538 },
539 CoreResourceMsg::GetCookiesDataForUrl(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::ListCookies(sender) => {
549 let mut cookie_jar = http_state.cookie_jar.write();
550 cookie_jar.remove_all_expired_cookies();
551 let _ = sender.send(cookie_jar.cookie_site_descriptors());
552 },
553 CoreResourceMsg::GetHistoryState(history_state_id, consumer) => {
554 let history_states = http_state.history_states.read();
555 consumer
556 .send(history_states.get(&history_state_id).cloned())
557 .unwrap();
558 },
559 CoreResourceMsg::SetHistoryState(history_state_id, structured_data) => {
560 let mut history_states = http_state.history_states.write();
561 history_states.insert(history_state_id, structured_data);
562 },
563 CoreResourceMsg::RemoveHistoryStates(states_to_remove) => {
564 let mut history_states = http_state.history_states.write();
565 for history_state in states_to_remove {
566 history_states.remove(&history_state);
567 }
568 },
569 CoreResourceMsg::GetCacheEntries(sender) => {
570 let _ = sender.send(http_state.http_cache.cache_entry_descriptors());
571 },
572 CoreResourceMsg::ClearCache(sender) => {
573 http_state.http_cache.clear();
574 if let Some(sender) = sender {
575 let _ = sender.send(());
576 }
577 },
578 CoreResourceMsg::ToFileManager(msg) => self.resource_manager.filemanager.handle(msg),
579 CoreResourceMsg::StorePreloadedResponse(preload_id, response) => self
580 .resource_manager
581 .handle_preloaded_response(preload_id, response),
582 CoreResourceMsg::TotalSizeOfInFlightKeepAliveRecords(pipeline_id, sender) => {
583 let total = self
584 .resource_manager
585 .in_flight_keep_alive_records
586 .lock()
587 .get(&pipeline_id)
588 .map(|records| {
589 records
590 .iter()
591 .map(|record| record.keep_alive_body_length)
592 .sum()
593 })
594 .unwrap_or_default();
595 let _ = sender.send(total);
596 },
597 CoreResourceMsg::Exit(sender) => {
598 if let Some(ref config_dir) = self.config_dir {
599 let auth_cache = http_state.auth_cache.read();
600 servo_base::write_json_to_file(&*auth_cache, config_dir, "auth_cache.json");
601 let jar = http_state.cookie_jar.read();
602 servo_base::write_json_to_file(&*jar, config_dir, "cookie_jar.json");
603 let hsts = http_state.hsts_list.read();
604 servo_base::write_json_to_file(&*hsts, config_dir, "hsts_list.json");
605 }
606 self.resource_manager.exit();
607 let _ = sender.send(());
608 return false;
609 },
610 CoreResourceMsg::CollectMemoryReport(_) => {},
612 }
613 true
614 }
615}
616
617#[derive(Clone, Debug, Deserialize, Serialize)]
618pub struct AuthCacheEntry {
619 pub user_name: String,
620 pub password: String,
621}
622
623impl Default for AuthCache {
624 fn default() -> Self {
625 Self {
626 version: 1,
627 entries: HashMap::new(),
628 }
629 }
630}
631
632#[derive(Clone, Debug, Deserialize, Serialize)]
633pub struct AuthCache {
634 pub version: u32,
635 pub entries: HashMap<String, AuthCacheEntry>,
636}
637
638pub struct CoreResourceManager {
639 devtools_sender: Option<Sender<DevtoolsControlMsg>>,
640 sw_managers: HashMap<ImmutableOrigin, IpcSender<CustomResponseMediator>>,
641 filemanager: FileManager,
642 request_interceptor: RequestInterceptor,
643 ca_certificates: CACertificates<'static>,
644 ignore_certificate_errors: bool,
645 preloaded_resources: SharedPreloadedResources,
646 in_flight_keep_alive_records: SharedInflightKeepAliveRecords,
648}
649
650impl CoreResourceManager {
651 pub fn new(
652 devtools_sender: Option<Sender<DevtoolsControlMsg>>,
653 _profiler_chan: ProfilerChan,
654 embedder_proxy: GenericEmbedderProxy<NetToEmbedderMsg>,
655 ca_certificates: CACertificates<'static>,
656 ignore_certificate_errors: bool,
657 ) -> CoreResourceManager {
658 CoreResourceManager {
659 devtools_sender,
660 sw_managers: Default::default(),
661 filemanager: FileManager::new(embedder_proxy.clone()),
662 request_interceptor: RequestInterceptor::new(embedder_proxy),
663 ca_certificates,
664 ignore_certificate_errors,
665 preloaded_resources: Default::default(),
666 in_flight_keep_alive_records: Default::default(),
667 }
668 }
669
670 fn handle_preloaded_response(&self, preload_id: PreloadId, response: Response) {
671 let mut preloaded_resources = self.preloaded_resources.lock().unwrap();
672 if let Some(entry) = preloaded_resources.get_mut(&preload_id) {
673 entry.with_response(response);
674 }
675 }
676
677 pub fn exit(&mut self) {
679 debug!("Exited CoreResourceManager");
680 }
681
682 fn set_cookie_for_url(
683 &mut self,
684 request: &ServoUrl,
685 cookie: Cookie<'static>,
686 source: CookieSource,
687 http_state: &Arc<HttpState>,
688 ) {
689 if let Some(cookie) = ServoCookie::new_wrapped(cookie, request, source) {
690 let mut cookie_jar = http_state.cookie_jar.write();
691 cookie_jar.push(cookie, request, source)
692 }
693 }
694
695 fn fetch<Target: 'static + FetchTaskTarget + Send>(
696 &self,
697 request_builder: RequestBuilder,
698 res_init_: Option<ResponseInit>,
699 mut sender: Target,
700 http_state: &Arc<HttpState>,
701 cancellation_listener: Arc<CancellationListener>,
702 protocols: Arc<ProtocolRegistry>,
703 ) {
704 let http_state = http_state.clone();
705 let devtools_chan = self.devtools_sender.clone();
706 let filemanager = self.filemanager.clone();
707 let request_interceptor = self.request_interceptor.clone();
708
709 let timing_type = match request_builder.destination {
710 Destination::Document => ResourceTimingType::Navigation,
711 _ => ResourceTimingType::Resource,
712 };
713
714 let request = request_builder.build();
715 let url = request.current_url();
716
717 let (file_token, blob_url_file_id) = match url.scheme() {
728 "blob" => {
729 if let Ok((id, _)) = parse_blob_url(&url) {
730 (self.filemanager.get_token_for_file(&id), Some(id))
731 } else {
732 (FileTokenCheck::ShouldFail, None)
733 }
734 },
735 _ => (FileTokenCheck::NotRequired, None),
736 };
737
738 let ca_certificates = self.ca_certificates.clone();
739 let ignore_certificate_errors = self.ignore_certificate_errors;
740 let in_flight_keep_alive_records = self.in_flight_keep_alive_records.clone();
741 let preloaded_resources = self.preloaded_resources.clone();
742 if let Some(ref preload_id) = request.preload_id {
743 let mut preloaded_resources = self.preloaded_resources.lock().unwrap();
744 let entry = PreloadEntry::new(request.integrity_metadata.clone());
745 preloaded_resources.insert(preload_id.clone(), entry);
746 }
747
748 spawn_task(async move {
749 let context = FetchContext {
754 state: http_state,
755 user_agent: servo_config::pref!(user_agent),
756 devtools_chan,
757 filemanager,
758 file_token,
759 request_interceptor: Arc::new(TokioMutex::new(request_interceptor)),
760 cancellation_listener,
761 timing: ServoArc::new(Mutex::new(ResourceFetchTiming::new(request.timing_type()))),
762 protocols,
763 websocket_chan: None,
764 ca_certificates,
765 ignore_certificate_errors,
766 preloaded_resources,
767 in_flight_keep_alive_records,
768 };
769
770 match res_init_ {
771 Some(res_init) => {
772 let response = Response::from_init(res_init, timing_type);
773
774 let mut fetch_params = FetchParams::new(request);
775 let mut request_body_stream_closer =
776 AutoRequestBodyStreamCloser::new(fetch_params.request.body.as_ref());
777 let response = http_redirect_fetch(
778 &mut fetch_params,
779 &mut CorsCache::default(),
780 response,
781 true,
782 &mut sender,
783 &mut None,
784 &context,
785 )
786 .await;
787 if transfers_request_body_stream_to_later_manual_redirect(
788 &fetch_params.request,
789 &response,
790 ) {
791 request_body_stream_closer.disarm();
792 }
793 },
794 None => {
795 fetch(request, &mut sender, &context).await;
796 },
797 };
798
799 if let Some(id) = blob_url_file_id.as_ref() {
801 context
802 .filemanager
803 .invalidate_token(&context.file_token, id);
804 }
805 });
806 }
807
808 fn websocket_connect(
810 &self,
811 mut request: RequestBuilder,
812 event_sender: IpcSender<WebSocketNetworkEvent>,
813 action_receiver: CallbackSetter<WebSocketDomAction>,
814 http_state: &Arc<HttpState>,
815 cancellation_listener: Arc<CancellationListener>,
816 protocols: Arc<ProtocolRegistry>,
817 ) {
818 let http_state = http_state.clone();
819 let devtools_chan = self.devtools_sender.clone();
820 let filemanager = self.filemanager.clone();
821 let request_interceptor = self.request_interceptor.clone();
822
823 let ca_certificates = self.ca_certificates.clone();
824 let ignore_certificate_errors = self.ignore_certificate_errors;
825 let in_flight_keep_alive_records = self.in_flight_keep_alive_records.clone();
826 let preloaded_resources = self.preloaded_resources.clone();
827
828 spawn_task(async move {
829 let mut event_sender = event_sender;
830
831 let scheme = match request.url.scheme() {
834 "ws" => "http",
835 _ => "https",
836 };
837 request
838 .url
839 .as_mut_url()
840 .set_scheme(scheme)
841 .unwrap_or_else(|_| panic!("Can't set scheme to {scheme}"));
842
843 match create_handshake_request(request, http_state.clone()) {
844 Ok(request) => {
845 let context = FetchContext {
846 state: http_state,
847 user_agent: servo_config::pref!(user_agent),
848 devtools_chan,
849 filemanager,
850 file_token: FileTokenCheck::NotRequired,
851 request_interceptor: Arc::new(TokioMutex::new(request_interceptor)),
852 cancellation_listener,
853 timing: ServoArc::new(Mutex::new(ResourceFetchTiming::new(
854 request.timing_type(),
855 ))),
856 protocols: protocols.clone(),
857 websocket_chan: Some(Arc::new(Mutex::new(WebSocketChannel::new(
858 event_sender.clone(),
859 Some(action_receiver),
860 )))),
861 ca_certificates,
862 ignore_certificate_errors,
863 preloaded_resources,
864 in_flight_keep_alive_records,
865 };
866 fetch(request, &mut event_sender, &context).await;
867 },
868 Err(e) => {
869 trace!("unable to create websocket handshake request {:?}", e);
870 let _ = event_sender.send(WebSocketNetworkEvent::Fail);
871 },
872 }
873 });
874 }
875}