1use base::cross_process_instant::CrossProcessInstant;
6use dom_struct::dom_struct;
7use net_traits::ResourceFetchTiming;
8use servo_url::ServoUrl;
9use time::Duration;
10
11use super::performanceentry::{EntryType, PerformanceEntry};
12use crate::dom::bindings::codegen::Bindings::PerformanceBinding::DOMHighResTimeStamp;
13use crate::dom::bindings::codegen::Bindings::PerformanceResourceTimingBinding::PerformanceResourceTimingMethods;
14use crate::dom::bindings::reflector::{DomGlobal, reflect_dom_object};
15use crate::dom::bindings::root::DomRoot;
16use crate::dom::bindings::str::DOMString;
17use crate::dom::globalscope::GlobalScope;
18use crate::script_runtime::CanGc;
19#[derive(Debug, JSTraceable, MallocSizeOf, PartialEq)]
28pub(crate) enum InitiatorType {
29 Beacon,
30 Css,
31 LocalName(String),
32 Navigation,
33 XMLHttpRequest,
34 Fetch,
35 Other,
36}
37
38#[dom_struct]
39pub(crate) struct PerformanceResourceTiming {
40 entry: PerformanceEntry,
41 initiator_type: InitiatorType,
42 next_hop: Option<DOMString>,
43 #[no_trace]
44 worker_start: Option<CrossProcessInstant>,
45 #[no_trace]
46 redirect_start: Option<CrossProcessInstant>,
47 #[no_trace]
48 redirect_end: Option<CrossProcessInstant>,
49 #[no_trace]
50 fetch_start: Option<CrossProcessInstant>,
51 #[no_trace]
52 domain_lookup_start: Option<CrossProcessInstant>,
53 #[no_trace]
54 domain_lookup_end: Option<CrossProcessInstant>,
55 #[no_trace]
56 connect_start: Option<CrossProcessInstant>,
57 #[no_trace]
58 connect_end: Option<CrossProcessInstant>,
59 #[no_trace]
60 secure_connection_start: Option<CrossProcessInstant>,
61 #[no_trace]
62 request_start: Option<CrossProcessInstant>,
63 #[no_trace]
64 response_start: Option<CrossProcessInstant>,
65 #[no_trace]
66 response_end: Option<CrossProcessInstant>,
67 transfer_size: u64, encoded_body_size: u64, decoded_body_size: u64, }
71
72impl PerformanceResourceTiming {
80 pub(crate) fn new_inherited(
81 url: ServoUrl,
82 initiator_type: InitiatorType,
83 next_hop: Option<DOMString>,
84 fetch_start: Option<CrossProcessInstant>,
85 ) -> PerformanceResourceTiming {
86 let entry_type = if initiator_type == InitiatorType::Navigation {
87 EntryType::Navigation
88 } else {
89 EntryType::Resource
90 };
91 PerformanceResourceTiming {
92 entry: PerformanceEntry::new_inherited(
93 DOMString::from(url.into_string()),
94 entry_type,
95 None,
96 Duration::ZERO,
97 ),
98 initiator_type,
99 next_hop,
100 worker_start: None,
101 redirect_start: None,
102 redirect_end: None,
103 fetch_start,
104 domain_lookup_end: None,
105 domain_lookup_start: None,
106 connect_start: None,
107 connect_end: None,
108 secure_connection_start: None,
109 request_start: None,
110 response_start: None,
111 response_end: None,
112 transfer_size: 0,
113 encoded_body_size: 0,
114 decoded_body_size: 0,
115 }
116 }
117
118 #[cfg_attr(crown, expect(crown::unrooted_must_root))]
120 fn from_resource_timing(
121 url: ServoUrl,
122 initiator_type: InitiatorType,
123 next_hop: Option<DOMString>,
124 resource_timing: &ResourceFetchTiming,
125 ) -> PerformanceResourceTiming {
126 let duration = match (resource_timing.start_time, resource_timing.response_end) {
127 (Some(start_time), Some(end_time)) => end_time - start_time,
128 _ => Duration::ZERO,
129 };
130 PerformanceResourceTiming {
131 entry: PerformanceEntry::new_inherited(
132 DOMString::from(url.into_string()),
133 EntryType::Resource,
134 resource_timing.start_time,
135 duration,
136 ),
137 initiator_type,
138 next_hop,
139 worker_start: None,
140 redirect_start: resource_timing.redirect_start,
141 redirect_end: resource_timing.redirect_end,
142 fetch_start: resource_timing.fetch_start,
143 domain_lookup_start: resource_timing.domain_lookup_start,
144 domain_lookup_end: None,
146 connect_start: resource_timing.connect_start,
147 connect_end: resource_timing.connect_end,
148 secure_connection_start: resource_timing.secure_connection_start,
149 request_start: resource_timing.request_start,
150 response_start: resource_timing.response_start,
151 response_end: resource_timing.response_end,
152 transfer_size: 0,
153 encoded_body_size: 0,
154 decoded_body_size: 0,
155 }
156 }
157
158 pub(crate) fn new(
159 global: &GlobalScope,
160 url: ServoUrl,
161 initiator_type: InitiatorType,
162 next_hop: Option<DOMString>,
163 resource_timing: &ResourceFetchTiming,
164 can_gc: CanGc,
165 ) -> DomRoot<PerformanceResourceTiming> {
166 reflect_dom_object(
167 Box::new(PerformanceResourceTiming::from_resource_timing(
168 url,
169 initiator_type,
170 next_hop,
171 resource_timing,
172 )),
173 global,
174 can_gc,
175 )
176 }
177
178 pub(crate) fn to_dom_high_res_time_stamp(
182 &self,
183 instant: Option<CrossProcessInstant>,
184 ) -> DOMHighResTimeStamp {
185 self.global()
186 .performance()
187 .maybe_to_dom_high_res_time_stamp(instant)
188 }
189}
190
191impl PerformanceResourceTimingMethods<crate::DomTypeHolder> for PerformanceResourceTiming {
193 fn InitiatorType(&self) -> DOMString {
195 match self.initiator_type {
196 InitiatorType::Beacon => DOMString::from("beacon"),
197 InitiatorType::Css => DOMString::from("css"),
198 InitiatorType::LocalName(ref n) => DOMString::from(n.clone()),
199 InitiatorType::Navigation => DOMString::from("navigation"),
200 InitiatorType::XMLHttpRequest => DOMString::from("xmlhttprequest"),
201 InitiatorType::Fetch => DOMString::from("fetch"),
202 InitiatorType::Other => DOMString::from("other"),
203 }
204 }
205
206 fn NextHopProtocol(&self) -> DOMString {
210 match self.next_hop {
211 Some(ref protocol) => protocol.clone(),
212 None => DOMString::from(""),
213 }
214 }
215
216 fn DomainLookupStart(&self) -> DOMHighResTimeStamp {
218 self.to_dom_high_res_time_stamp(self.domain_lookup_start)
219 }
220
221 fn DomainLookupEnd(&self) -> DOMHighResTimeStamp {
223 self.to_dom_high_res_time_stamp(self.domain_lookup_end)
224 }
225
226 fn SecureConnectionStart(&self) -> DOMHighResTimeStamp {
228 self.to_dom_high_res_time_stamp(self.secure_connection_start)
229 }
230
231 fn TransferSize(&self) -> u64 {
233 self.transfer_size
234 }
235
236 fn EncodedBodySize(&self) -> u64 {
238 self.encoded_body_size
239 }
240
241 fn DecodedBodySize(&self) -> u64 {
243 self.decoded_body_size
244 }
245
246 fn RequestStart(&self) -> DOMHighResTimeStamp {
248 self.to_dom_high_res_time_stamp(self.request_start)
249 }
250
251 fn RedirectStart(&self) -> DOMHighResTimeStamp {
253 self.to_dom_high_res_time_stamp(self.redirect_start)
254 }
255
256 fn RedirectEnd(&self) -> DOMHighResTimeStamp {
258 self.to_dom_high_res_time_stamp(self.redirect_end)
259 }
260
261 fn ResponseStart(&self) -> DOMHighResTimeStamp {
263 self.to_dom_high_res_time_stamp(self.response_start)
264 }
265
266 fn FetchStart(&self) -> DOMHighResTimeStamp {
268 self.to_dom_high_res_time_stamp(self.fetch_start)
269 }
270
271 fn ConnectStart(&self) -> DOMHighResTimeStamp {
273 self.to_dom_high_res_time_stamp(self.connect_start)
274 }
275
276 fn ConnectEnd(&self) -> DOMHighResTimeStamp {
278 self.to_dom_high_res_time_stamp(self.connect_end)
279 }
280
281 fn ResponseEnd(&self) -> DOMHighResTimeStamp {
283 self.to_dom_high_res_time_stamp(self.response_end)
284 }
285}