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