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 Track,
37 Other,
38}
39
40#[dom_struct]
41pub(crate) struct PerformanceResourceTiming {
42 entry: PerformanceEntry,
43 initiator_type: InitiatorType,
44 next_hop: Option<DOMString>,
45 #[no_trace]
46 worker_start: Option<CrossProcessInstant>,
47 #[no_trace]
48 redirect_start: Option<CrossProcessInstant>,
49 #[no_trace]
50 redirect_end: Option<CrossProcessInstant>,
51 #[no_trace]
52 fetch_start: Option<CrossProcessInstant>,
53 #[no_trace]
54 domain_lookup_start: Option<CrossProcessInstant>,
55 #[no_trace]
56 domain_lookup_end: Option<CrossProcessInstant>,
57 #[no_trace]
58 connect_start: Option<CrossProcessInstant>,
59 #[no_trace]
60 connect_end: Option<CrossProcessInstant>,
61 #[no_trace]
62 secure_connection_start: Option<CrossProcessInstant>,
63 #[no_trace]
64 request_start: Option<CrossProcessInstant>,
65 #[no_trace]
66 response_start: Option<CrossProcessInstant>,
67 #[no_trace]
68 response_end: Option<CrossProcessInstant>,
69 transfer_size: u64, encoded_body_size: u64, decoded_body_size: u64, }
73
74impl PerformanceResourceTiming {
78 pub(crate) fn new_inherited(
79 url: ServoUrl,
80 initiator_type: InitiatorType,
81 resource_timing: &ResourceFetchTiming,
82 ) -> PerformanceResourceTiming {
83 let (entry_type, start_time) = if initiator_type == InitiatorType::Navigation {
84 (EntryType::Navigation, None)
85 } else {
86 (EntryType::Resource, resource_timing.start_time)
87 };
88 let duration = match (resource_timing.start_time, resource_timing.response_end) {
89 (Some(start_time), Some(end_time)) => end_time - start_time,
90 _ => Duration::ZERO,
91 };
92 PerformanceResourceTiming {
93 entry: PerformanceEntry::new_inherited(
94 DOMString::from(url.into_string()),
95 entry_type,
96 start_time,
97 duration,
98 ),
99 initiator_type,
100 next_hop: None,
101 worker_start: None,
102 redirect_start: resource_timing.redirect_start,
103 redirect_end: resource_timing.redirect_end,
104 fetch_start: resource_timing.fetch_start,
105 domain_lookup_start: resource_timing.domain_lookup_start,
106 domain_lookup_end: None,
107 connect_start: resource_timing.connect_start,
108 connect_end: resource_timing.connect_end,
109 secure_connection_start: resource_timing.secure_connection_start,
110 request_start: resource_timing.request_start,
111 response_start: resource_timing.response_start,
112 response_end: resource_timing.response_end,
113 transfer_size: 0,
114 encoded_body_size: 0,
115 decoded_body_size: 0,
116 }
117 }
118
119 pub(crate) fn new(
120 cx: &mut JSContext,
121 global: &GlobalScope,
122 url: ServoUrl,
123 initiator_type: InitiatorType,
124 resource_timing: &ResourceFetchTiming,
125 ) -> DomRoot<PerformanceResourceTiming> {
126 reflect_dom_object_with_cx(
127 Box::new(PerformanceResourceTiming::new_inherited(
128 url,
129 initiator_type,
130 resource_timing,
131 )),
132 global,
133 cx,
134 )
135 }
136
137 pub(crate) fn to_dom_high_res_time_stamp(
141 &self,
142 cx: &mut JSContext,
143 instant: Option<CrossProcessInstant>,
144 ) -> DOMHighResTimeStamp {
145 self.global()
146 .performance(cx)
147 .maybe_to_dom_high_res_time_stamp(instant)
148 }
149}
150
151impl PerformanceResourceTimingMethods<crate::DomTypeHolder> for PerformanceResourceTiming {
153 fn InitiatorType(&self) -> DOMString {
155 match self.initiator_type {
156 InitiatorType::Beacon => DOMString::from("beacon"),
157 InitiatorType::Css => DOMString::from("css"),
158 InitiatorType::LocalName(ref n) => DOMString::from(n.clone()),
159 InitiatorType::Navigation => DOMString::from("navigation"),
160 InitiatorType::XMLHttpRequest => DOMString::from("xmlhttprequest"),
161 InitiatorType::Fetch => DOMString::from("fetch"),
162 InitiatorType::Track => DOMString::from("track"),
163 InitiatorType::Other => DOMString::from("other"),
164 }
165 }
166
167 fn NextHopProtocol(&self) -> DOMString {
171 match self.next_hop {
172 Some(ref protocol) => protocol.clone(),
173 None => DOMString::from(""),
174 }
175 }
176
177 fn DomainLookupStart(&self, cx: &mut JSContext) -> DOMHighResTimeStamp {
179 self.to_dom_high_res_time_stamp(cx, self.domain_lookup_start)
180 }
181
182 fn DomainLookupEnd(&self, cx: &mut JSContext) -> DOMHighResTimeStamp {
184 self.to_dom_high_res_time_stamp(cx, self.domain_lookup_end)
185 }
186
187 fn SecureConnectionStart(&self, cx: &mut JSContext) -> DOMHighResTimeStamp {
189 self.to_dom_high_res_time_stamp(cx, self.secure_connection_start)
190 }
191
192 fn TransferSize(&self) -> u64 {
194 self.transfer_size
195 }
196
197 fn EncodedBodySize(&self) -> u64 {
199 self.encoded_body_size
200 }
201
202 fn DecodedBodySize(&self) -> u64 {
204 self.decoded_body_size
205 }
206
207 fn RequestStart(&self, cx: &mut JSContext) -> DOMHighResTimeStamp {
209 self.to_dom_high_res_time_stamp(cx, self.request_start)
210 }
211
212 fn RedirectStart(&self, cx: &mut JSContext) -> DOMHighResTimeStamp {
214 self.to_dom_high_res_time_stamp(cx, self.redirect_start)
215 }
216
217 fn RedirectEnd(&self, cx: &mut JSContext) -> DOMHighResTimeStamp {
219 self.to_dom_high_res_time_stamp(cx, self.redirect_end)
220 }
221
222 fn ResponseStart(&self, cx: &mut JSContext) -> DOMHighResTimeStamp {
224 self.to_dom_high_res_time_stamp(cx, self.response_start)
225 }
226
227 fn FetchStart(&self, cx: &mut JSContext) -> DOMHighResTimeStamp {
229 self.to_dom_high_res_time_stamp(cx, self.fetch_start)
230 }
231
232 fn ConnectStart(&self, cx: &mut JSContext) -> DOMHighResTimeStamp {
234 self.to_dom_high_res_time_stamp(cx, self.connect_start)
235 }
236
237 fn ConnectEnd(&self, cx: &mut JSContext) -> DOMHighResTimeStamp {
239 self.to_dom_high_res_time_stamp(cx, self.connect_end)
240 }
241
242 fn ResponseEnd(&self, cx: &mut JSContext) -> DOMHighResTimeStamp {
244 self.to_dom_high_res_time_stamp(cx, self.response_end)
245 }
246}