Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 : /* This Source Code Form is subject to the terms of the Mozilla Public
4 : * License, v. 2.0. If a copy of the MPL was not distributed with this
5 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : #ifndef mozilla_dom_PerformanceTiming_h
8 : #define mozilla_dom_PerformanceTiming_h
9 :
10 : #include "mozilla/Attributes.h"
11 : #include "nsContentUtils.h"
12 : #include "nsDOMNavigationTiming.h"
13 : #include "nsWrapperCache.h"
14 : #include "Performance.h"
15 :
16 : class nsIHttpChannel;
17 : class nsITimedChannel;
18 :
19 : namespace mozilla {
20 : namespace dom {
21 :
22 : // Script "performance.timing" object
23 : class PerformanceTiming final : public nsWrapperCache
24 : {
25 : public:
26 : /**
27 : * @param aPerformance
28 : * The performance object (the JS parent).
29 : * This will allow access to "window.performance.timing" attribute for
30 : * the navigation timing (can't be null).
31 : * @param aChannel
32 : * An nsITimedChannel used to gather all the networking timings by both
33 : * the navigation timing and the resource timing (can't be null).
34 : * @param aHttpChannel
35 : * An nsIHttpChannel (the resource's http channel).
36 : * This will be used by the resource timing cross-domain check
37 : * algorithm.
38 : * Argument is null for the navigation timing (navigation timing uses
39 : * another algorithm for the cross-domain redirects).
40 : * @param aZeroTime
41 : * The offset that will be added to the timestamp of each event. This
42 : * argument should be equal to performance.navigationStart for
43 : * navigation timing and "0" for the resource timing.
44 : */
45 : PerformanceTiming(Performance* aPerformance,
46 : nsITimedChannel* aChannel,
47 : nsIHttpChannel* aHttpChannel,
48 : DOMHighResTimeStamp aZeroTime);
49 6 : NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(PerformanceTiming)
50 13 : NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(PerformanceTiming)
51 :
52 2 : nsDOMNavigationTiming* GetDOMTiming() const
53 : {
54 2 : return mPerformance->GetDOMTiming();
55 : }
56 :
57 0 : Performance* GetParentObject() const
58 : {
59 0 : return mPerformance;
60 : }
61 :
62 : /**
63 : * @param aStamp
64 : * The TimeStamp recorded for a specific event. This TimeStamp can
65 : * be null.
66 : * @return the duration of an event with a given TimeStamp, relative to the
67 : * navigationStart TimeStamp (the moment the user landed on the
68 : * page), if the given TimeStamp is valid. Otherwise, it will return
69 : * the FetchStart timing value.
70 : */
71 2 : inline DOMHighResTimeStamp TimeStampToDOMHighResOrFetchStart(TimeStamp aStamp)
72 : {
73 2 : return (!aStamp.IsNull())
74 2 : ? TimeStampToDOMHighRes(aStamp)
75 2 : : FetchStartHighRes();
76 : }
77 :
78 : /**
79 : * The nsITimedChannel records an absolute timestamp for each event.
80 : * The nsDOMNavigationTiming will record the moment when the user landed on
81 : * the page. This is a window.performance unique timestamp, so it can be used
82 : * for all the events (navigation timing and resource timing events).
83 : *
84 : * The algorithm operates in 2 steps:
85 : * 1. The first step is to subtract the two timestamps: the argument (the
86 : * envet's timesramp) and the navigation start timestamp. This will result in
87 : * a relative timestamp of the event (relative to the navigation start -
88 : * window.performance.timing.navigationStart).
89 : * 2. The second step is to add any required offset (the mZeroTime). For now,
90 : * this offset value is either 0 (for the resource timing), or equal to
91 : * "performance.navigationStart" (for navigation timing).
92 : * For the resource timing, mZeroTime is set to 0, causing the result to be a
93 : * relative time.
94 : * For the navigation timing, mZeroTime is set to "performance.navigationStart"
95 : * causing the result be an absolute time.
96 : *
97 : * @param aStamp
98 : * The TimeStamp recorded for a specific event. This TimeStamp can't
99 : * be null.
100 : * @return number of milliseconds value as one of:
101 : * - relative to the navigation start time, time the user has landed on the
102 : * page
103 : * - an absolute wall clock time since the unix epoch
104 : */
105 2 : inline DOMHighResTimeStamp TimeStampToDOMHighRes(TimeStamp aStamp) const
106 : {
107 2 : MOZ_ASSERT(!aStamp.IsNull());
108 : TimeDuration duration =
109 2 : aStamp - GetDOMTiming()->GetNavigationStartTimeStamp();
110 2 : return duration.ToMilliseconds() + mZeroTime;
111 : }
112 :
113 : virtual JSObject* WrapObject(JSContext *cx,
114 : JS::Handle<JSObject*> aGivenProto) override;
115 :
116 : // PerformanceNavigation WebIDL methods
117 0 : DOMTimeMilliSec NavigationStart() const
118 : {
119 0 : if (!nsContentUtils::IsPerformanceTimingEnabled() ||
120 0 : nsContentUtils::ShouldResistFingerprinting()) {
121 0 : return 0;
122 : }
123 0 : return GetDOMTiming()->GetNavigationStart();
124 : }
125 :
126 0 : DOMTimeMilliSec UnloadEventStart()
127 : {
128 0 : if (!nsContentUtils::IsPerformanceTimingEnabled() ||
129 0 : nsContentUtils::ShouldResistFingerprinting()) {
130 0 : return 0;
131 : }
132 0 : return GetDOMTiming()->GetUnloadEventStart();
133 : }
134 :
135 0 : DOMTimeMilliSec UnloadEventEnd()
136 : {
137 0 : if (!nsContentUtils::IsPerformanceTimingEnabled() ||
138 0 : nsContentUtils::ShouldResistFingerprinting()) {
139 0 : return 0;
140 : }
141 0 : return GetDOMTiming()->GetUnloadEventEnd();
142 : }
143 :
144 : uint16_t GetRedirectCount() const;
145 :
146 : // Checks if the resource is either same origin as the page that started
147 : // the load, or if the response contains the Timing-Allow-Origin header
148 : // with a value of * or matching the domain of the loading Principal
149 : bool CheckAllowedOrigin(nsIHttpChannel* aResourceChannel, nsITimedChannel* aChannel);
150 :
151 : // Cached result of CheckAllowedOrigin. If false, security sensitive
152 : // attributes of the resourceTiming object will be set to 0
153 : bool TimingAllowed() const;
154 :
155 : // If this is false the values of redirectStart/End will be 0
156 : // This is false if no redirects occured, or if any of the responses failed
157 : // the timing-allow-origin check in HttpBaseChannel::TimingAllowCheck
158 : bool ShouldReportCrossOriginRedirect() const;
159 :
160 : // High resolution (used by resource timing)
161 : DOMHighResTimeStamp FetchStartHighRes();
162 : DOMHighResTimeStamp RedirectStartHighRes();
163 : DOMHighResTimeStamp RedirectEndHighRes();
164 : DOMHighResTimeStamp DomainLookupStartHighRes();
165 : DOMHighResTimeStamp DomainLookupEndHighRes();
166 : DOMHighResTimeStamp ConnectStartHighRes();
167 : DOMHighResTimeStamp ConnectEndHighRes();
168 : DOMHighResTimeStamp RequestStartHighRes();
169 : DOMHighResTimeStamp ResponseStartHighRes();
170 : DOMHighResTimeStamp ResponseEndHighRes();
171 :
172 : // Low resolution (used by navigation timing)
173 : DOMTimeMilliSec FetchStart();
174 : DOMTimeMilliSec RedirectStart();
175 : DOMTimeMilliSec RedirectEnd();
176 : DOMTimeMilliSec DomainLookupStart();
177 : DOMTimeMilliSec DomainLookupEnd();
178 : DOMTimeMilliSec ConnectStart();
179 : DOMTimeMilliSec ConnectEnd();
180 : DOMTimeMilliSec RequestStart();
181 : DOMTimeMilliSec ResponseStart();
182 : DOMTimeMilliSec ResponseEnd();
183 :
184 0 : DOMTimeMilliSec DomLoading()
185 : {
186 0 : if (!nsContentUtils::IsPerformanceTimingEnabled() ||
187 0 : nsContentUtils::ShouldResistFingerprinting()) {
188 0 : return 0;
189 : }
190 0 : return GetDOMTiming()->GetDomLoading();
191 : }
192 :
193 0 : DOMTimeMilliSec DomInteractive() const
194 : {
195 0 : if (!nsContentUtils::IsPerformanceTimingEnabled() ||
196 0 : nsContentUtils::ShouldResistFingerprinting()) {
197 0 : return 0;
198 : }
199 0 : return GetDOMTiming()->GetDomInteractive();
200 : }
201 :
202 0 : DOMTimeMilliSec DomContentLoadedEventStart() const
203 : {
204 0 : if (!nsContentUtils::IsPerformanceTimingEnabled() ||
205 0 : nsContentUtils::ShouldResistFingerprinting()) {
206 0 : return 0;
207 : }
208 0 : return GetDOMTiming()->GetDomContentLoadedEventStart();
209 : }
210 :
211 0 : DOMTimeMilliSec DomContentLoadedEventEnd() const
212 : {
213 0 : if (!nsContentUtils::IsPerformanceTimingEnabled() ||
214 0 : nsContentUtils::ShouldResistFingerprinting()) {
215 0 : return 0;
216 : }
217 0 : return GetDOMTiming()->GetDomContentLoadedEventEnd();
218 : }
219 :
220 0 : DOMTimeMilliSec DomComplete() const
221 : {
222 0 : if (!nsContentUtils::IsPerformanceTimingEnabled() ||
223 0 : nsContentUtils::ShouldResistFingerprinting()) {
224 0 : return 0;
225 : }
226 0 : return GetDOMTiming()->GetDomComplete();
227 : }
228 :
229 0 : DOMTimeMilliSec LoadEventStart() const
230 : {
231 0 : if (!nsContentUtils::IsPerformanceTimingEnabled() ||
232 0 : nsContentUtils::ShouldResistFingerprinting()) {
233 0 : return 0;
234 : }
235 0 : return GetDOMTiming()->GetLoadEventStart();
236 : }
237 :
238 0 : DOMTimeMilliSec LoadEventEnd() const
239 : {
240 0 : if (!nsContentUtils::IsPerformanceTimingEnabled() ||
241 0 : nsContentUtils::ShouldResistFingerprinting()) {
242 0 : return 0;
243 : }
244 0 : return GetDOMTiming()->GetLoadEventEnd();
245 : }
246 :
247 0 : DOMTimeMilliSec TimeToNonBlankPaint() const
248 : {
249 0 : if (!nsContentUtils::IsPerformanceTimingEnabled() ||
250 0 : nsContentUtils::ShouldResistFingerprinting()) {
251 0 : return 0;
252 : }
253 0 : return GetDOMTiming()->GetTimeToNonBlankPaint();
254 : }
255 :
256 : private:
257 : ~PerformanceTiming();
258 :
259 : bool IsInitialized() const;
260 : void InitializeTimingInfo(nsITimedChannel* aChannel);
261 :
262 : bool IsTopLevelContentDocument() const;
263 :
264 : RefPtr<Performance> mPerformance;
265 : DOMHighResTimeStamp mFetchStart;
266 :
267 : // This is an offset that will be added to each timing ([ms] resolution).
268 : // There are only 2 possible values: (1) logicaly equal to navigationStart
269 : // TimeStamp (results are absolute timstamps - wallclock); (2) "0" (results
270 : // are relative to the navigation start).
271 : DOMHighResTimeStamp mZeroTime;
272 :
273 : TimeStamp mAsyncOpen;
274 : TimeStamp mRedirectStart;
275 : TimeStamp mRedirectEnd;
276 : TimeStamp mDomainLookupStart;
277 : TimeStamp mDomainLookupEnd;
278 : TimeStamp mConnectStart;
279 : TimeStamp mConnectEnd;
280 : TimeStamp mRequestStart;
281 : TimeStamp mResponseStart;
282 : TimeStamp mCacheReadStart;
283 : TimeStamp mResponseEnd;
284 : TimeStamp mCacheReadEnd;
285 : uint16_t mRedirectCount;
286 : bool mTimingAllowed;
287 : bool mAllRedirectsSameOrigin;
288 : bool mInitialized;
289 :
290 : // If the resourceTiming object should have non-zero redirectStart and
291 : // redirectEnd attributes. It is false if there were no redirects, or if
292 : // any of the responses didn't pass the timing-allow-check
293 : bool mReportCrossOriginRedirect;
294 : };
295 :
296 : } // namespace dom
297 : } // namespace mozilla
298 :
299 : #endif // mozilla_dom_PerformanceTiming_h
|