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