1use std::sync::Arc;
10
11use net_traits::image_cache::{ImageCache, PendingImageId};
12use net_traits::request::{Destination, RequestBuilder as FetchRequestInit, RequestId};
13use net_traits::{
14 FetchMetadata, FetchResponseListener, FetchResponseMsg, NetworkError, ResourceFetchTiming,
15 ResourceTimingType,
16};
17use servo_url::ServoUrl;
18
19use crate::dom::bindings::refcounted::Trusted;
20use crate::dom::bindings::reflector::DomGlobal;
21use crate::dom::bindings::root::DomRoot;
22use crate::dom::csp::{GlobalCspReporting, Violation};
23use crate::dom::document::Document;
24use crate::dom::globalscope::GlobalScope;
25use crate::dom::node::{Node, NodeTraits};
26use crate::dom::performanceresourcetiming::InitiatorType;
27use crate::network_listener::{self, PreInvoke, ResourceTimingListener};
28use crate::script_runtime::CanGc;
29
30struct LayoutImageContext {
31 id: PendingImageId,
32 cache: Arc<dyn ImageCache>,
33 resource_timing: ResourceFetchTiming,
34 doc: Trusted<Document>,
35 url: ServoUrl,
36}
37
38impl FetchResponseListener for LayoutImageContext {
39 fn process_request_body(&mut self, _: RequestId) {}
40 fn process_request_eof(&mut self, _: RequestId) {}
41 fn process_response(
42 &mut self,
43 request_id: RequestId,
44 metadata: Result<FetchMetadata, NetworkError>,
45 ) {
46 self.cache.notify_pending_response(
47 self.id,
48 FetchResponseMsg::ProcessResponse(request_id, metadata),
49 );
50 }
51
52 fn process_response_chunk(&mut self, request_id: RequestId, payload: Vec<u8>) {
53 self.cache.notify_pending_response(
54 self.id,
55 FetchResponseMsg::ProcessResponseChunk(request_id, payload),
56 );
57 }
58
59 fn process_response_eof(
60 &mut self,
61 request_id: RequestId,
62 response: Result<ResourceFetchTiming, NetworkError>,
63 ) {
64 self.cache.notify_pending_response(
65 self.id,
66 FetchResponseMsg::ProcessResponseEOF(request_id, response),
67 );
68 }
69
70 fn resource_timing_mut(&mut self) -> &mut ResourceFetchTiming {
71 &mut self.resource_timing
72 }
73
74 fn resource_timing(&self) -> &ResourceFetchTiming {
75 &self.resource_timing
76 }
77
78 fn submit_resource_timing(&mut self) {
79 network_listener::submit_timing(self, CanGc::note())
80 }
81
82 fn process_csp_violations(&mut self, _request_id: RequestId, violations: Vec<Violation>) {
83 let global = &self.resource_timing_global();
84 global.report_csp_violations(violations, None, None);
85 }
86}
87
88impl ResourceTimingListener for LayoutImageContext {
89 fn resource_timing_information(&self) -> (InitiatorType, ServoUrl) {
90 (InitiatorType::Other, self.url.clone())
91 }
92
93 fn resource_timing_global(&self) -> DomRoot<GlobalScope> {
94 self.doc.root().global()
95 }
96}
97
98impl PreInvoke for LayoutImageContext {}
99
100pub(crate) fn fetch_image_for_layout(
101 url: ServoUrl,
102 node: &Node,
103 id: PendingImageId,
104 cache: Arc<dyn ImageCache>,
105) {
106 let document = node.owner_document();
107 let context = LayoutImageContext {
108 id,
109 cache,
110 resource_timing: ResourceFetchTiming::new(ResourceTimingType::Resource),
111 doc: Trusted::new(&document),
112 url: url.clone(),
113 };
114
115 let request = FetchRequestInit::new(
116 Some(document.webview_id()),
117 url,
118 document.global().get_referrer(),
119 )
120 .origin(document.origin().immutable().clone())
121 .destination(Destination::Image)
122 .pipeline_id(Some(document.global().pipeline_id()))
123 .insecure_requests_policy(document.insecure_requests_policy())
124 .has_trustworthy_ancestor_origin(document.has_trustworthy_ancestor_origin())
125 .policy_container(document.policy_container().to_owned());
126
127 document.fetch_background(request, context);
129}