1use dom_struct::dom_struct;
6use js::context::JSContext;
7use net_traits::ResourceFetchTiming;
8use script_bindings::reflector::reflect_dom_object_with_cx;
9use servo_base::cross_process_instant::CrossProcessInstant;
10use servo_url::ServoUrl;
11use time::Duration;
12
13use super::performanceentry::{EntryType, PerformanceEntry};
14use crate::dom::bindings::codegen::Bindings::PerformanceBinding::DOMHighResTimeStamp;
15use crate::dom::bindings::codegen::Bindings::PerformanceResourceTimingBinding::PerformanceResourceTimingMethods;
16use crate::dom::bindings::reflector::DomGlobal;
17use crate::dom::bindings::root::DomRoot;
18use crate::dom::bindings::str::DOMString;
19use crate::dom::globalscope::GlobalScope;
20#[derive(Debug, JSTraceable, MallocSizeOf, PartialEq)]
29pub(crate) enum InitiatorType {
30 Beacon,
31 Css,
32 LocalName(String),
33 Navigation,
34 XMLHttpRequest,
35 Fetch,
36 Other,
37}
38
39#[dom_struct]
40pub(crate) struct PerformanceResourceTiming {
41 entry: PerformanceEntry,
42 initiator_type: InitiatorType,
43 next_hop: Option<DOMString>,
44 #[no_trace]
45 worker_start: Option<CrossProcessInstant>,
46 #[no_trace]
47 redirect_start: Option<CrossProcessInstant>,
48 #[no_trace]
49 redirect_end: Option<CrossProcessInstant>,
50 #[no_trace]
51 fetch_start: Option<CrossProcessInstant>,
52 #[no_trace]
53 domain_lookup_start: Option<CrossProcessInstant>,
54 #[no_trace]
55 domain_lookup_end: Option<CrossProcessInstant>,
56 #[no_trace]
57 connect_start: Option<CrossProcessInstant>,
58 #[no_trace]
59 connect_end: Option<CrossProcessInstant>,
60 #[no_trace]
61 secure_connection_start: Option<CrossProcessInstant>,
62 #[no_trace]
63 request_start: Option<CrossProcessInstant>,
64 #[no_trace]
65 response_start: Option<CrossProcessInstant>,
66 #[no_trace]
67 response_end: Option<CrossProcessInstant>,
68 transfer_size: u64, encoded_body_size: u64, decoded_body_size: u64, }
72
73impl PerformanceResourceTiming {
81 pub(crate) fn new_inherited(
82 url: ServoUrl,
83 initiator_type: InitiatorType,
84 next_hop: Option<DOMString>,
85 fetch_start: Option<CrossProcessInstant>,
86 ) -> PerformanceResourceTiming {
87 let entry_type = if initiator_type == InitiatorType::Navigation {
88 EntryType::Navigation
89 } else {
90 EntryType::Resource
91 };
92 PerformanceResourceTiming {
93 entry: PerformanceEntry::new_inherited(
94 DOMString::from(url.into_string()),
95 entry_type,
96 None,
97 Duration::ZERO,
98 ),
99 initiator_type,
100 next_hop,
101 worker_start: None,
102 redirect_start: None,
103 redirect_end: None,
104 fetch_start,
105 domain_lookup_end: None,
106 domain_lookup_start: None,
107 connect_start: None,
108 connect_end: None,
109 secure_connection_start: None,
110 request_start: None,
111 response_start: None,
112 response_end: None,
113 transfer_size: 0,
114 encoded_body_size: 0,
115 decoded_body_size: 0,
116 }
117 }
118
119 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 cx: &mut JSContext,
160 global: &GlobalScope,
161 url: ServoUrl,
162 initiator_type: InitiatorType,
163 next_hop: Option<DOMString>,
164 resource_timing: &ResourceFetchTiming,
165 ) -> DomRoot<PerformanceResourceTiming> {
166 reflect_dom_object_with_cx(
167 Box::new(PerformanceResourceTiming::from_resource_timing(
168 url,
169 initiator_type,
170 next_hop,
171 resource_timing,
172 )),
173 global,
174 cx,
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}