Bug 1892041 - Part 1: Update test262 features. r=spidermonkey-reviewers,dminor
[gecko.git] / dom / performance / PerformanceTiming.cpp
blobd4505899ccafbc0c057f736f12f6c9b9bf224bb6
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/. */
7 #include "PerformanceTiming.h"
8 #include "mozilla/BasePrincipal.h"
9 #include "mozilla/StaticPrefs_dom.h"
10 #include "mozilla/dom/PerformanceTimingBinding.h"
11 #include "mozilla/glean/GleanMetrics.h"
12 #include "nsIDocShell.h"
13 #include "nsIDocShellTreeItem.h"
14 #include "nsIHttpChannel.h"
15 #include "mozilla/dom/BrowsingContext.h"
16 #include "mozilla/dom/Document.h"
17 #include "nsITimedChannel.h"
19 namespace mozilla::dom {
21 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(PerformanceTiming, mPerformance)
23 /* static */
24 PerformanceTimingData* PerformanceTimingData::Create(
25 nsITimedChannel* aTimedChannel, nsIHttpChannel* aChannel,
26 DOMHighResTimeStamp aZeroTime, nsAString& aInitiatorType,
27 nsAString& aEntryName) {
28 MOZ_ASSERT(NS_IsMainThread());
30 // Check if resource timing is prefed off.
31 if (!StaticPrefs::dom_enable_resource_timing()) {
32 return nullptr;
35 if (!aChannel || !aTimedChannel) {
36 return nullptr;
39 bool reportTiming = true;
40 aTimedChannel->GetReportResourceTiming(&reportTiming);
42 if (!reportTiming) {
43 return nullptr;
46 aTimedChannel->GetInitiatorType(aInitiatorType);
48 // If the initiator type had no valid value, then set it to the default
49 // ("other") value.
50 if (aInitiatorType.IsEmpty()) {
51 aInitiatorType = u"other"_ns;
54 // According to the spec, "The name attribute must return the resolved URL
55 // of the requested resource. This attribute must not change even if the
56 // fetch redirected to a different URL."
57 nsCOMPtr<nsIURI> originalURI;
58 aChannel->GetOriginalURI(getter_AddRefs(originalURI));
60 nsAutoCString name;
61 originalURI->GetSpec(name);
62 CopyUTF8toUTF16(name, aEntryName);
64 // The nsITimedChannel argument will be used to gather all the timings.
65 // The nsIHttpChannel argument will be used to check if any cross-origin
66 // redirects occurred.
67 // The last argument is the "zero time" (offset). Since we don't want
68 // any offset for the resource timing, this will be set to "0" - the
69 // resource timing returns a relative timing (no offset).
70 return new PerformanceTimingData(aTimedChannel, aChannel, 0);
73 PerformanceTiming::PerformanceTiming(Performance* aPerformance,
74 nsITimedChannel* aChannel,
75 nsIHttpChannel* aHttpChannel,
76 DOMHighResTimeStamp aZeroTime)
77 : mPerformance(aPerformance) {
78 MOZ_ASSERT(aPerformance, "Parent performance object should be provided");
80 mTimingData.reset(new PerformanceTimingData(
81 aChannel, aHttpChannel,
82 nsRFPService::ReduceTimePrecisionAsMSecs(
83 aZeroTime, aPerformance->GetRandomTimelineSeed(),
84 aPerformance->GetRTPCallerType())));
86 // Non-null aHttpChannel implies that this PerformanceTiming object is being
87 // used for subresources, which is irrelevant to this probe.
88 if (!aHttpChannel && StaticPrefs::dom_enable_performance() &&
89 IsTopLevelContentDocument()) {
90 glean::performance_time::response_start.AccumulateRawDuration(
91 TimeDuration::FromMilliseconds(
92 mTimingData->ResponseStartHighRes(aPerformance) -
93 mTimingData->ZeroTime()));
97 // Copy the timing info from the channel so we don't need to keep the channel
98 // alive just to get the timestamps.
99 PerformanceTimingData::PerformanceTimingData(nsITimedChannel* aChannel,
100 nsIHttpChannel* aHttpChannel,
101 DOMHighResTimeStamp aZeroTime)
102 : mZeroTime(0.0),
103 mFetchStart(0.0),
104 mEncodedBodySize(0),
105 mTransferSize(0),
106 mDecodedBodySize(0),
107 mRedirectCount(0),
108 mAllRedirectsSameOrigin(true),
109 mAllRedirectsPassTAO(true),
110 mSecureConnection(false),
111 mTimingAllowed(true),
112 mInitialized(false) {
113 mInitialized = !!aChannel;
114 mZeroTime = aZeroTime;
116 if (!StaticPrefs::dom_enable_performance()) {
117 mZeroTime = 0;
120 nsCOMPtr<nsIURI> uri;
121 if (aHttpChannel) {
122 aHttpChannel->GetURI(getter_AddRefs(uri));
123 } else {
124 nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel);
125 if (httpChannel) {
126 httpChannel->GetURI(getter_AddRefs(uri));
130 if (uri) {
131 mSecureConnection = uri->SchemeIs("https");
134 if (aChannel) {
135 aChannel->GetAsyncOpen(&mAsyncOpen);
136 aChannel->GetAllRedirectsSameOrigin(&mAllRedirectsSameOrigin);
137 aChannel->GetAllRedirectsPassTimingAllowCheck(&mAllRedirectsPassTAO);
138 aChannel->GetRedirectCount(&mRedirectCount);
139 aChannel->GetRedirectStart(&mRedirectStart);
140 aChannel->GetRedirectEnd(&mRedirectEnd);
141 aChannel->GetDomainLookupStart(&mDomainLookupStart);
142 aChannel->GetDomainLookupEnd(&mDomainLookupEnd);
143 aChannel->GetConnectStart(&mConnectStart);
144 aChannel->GetSecureConnectionStart(&mSecureConnectionStart);
145 aChannel->GetConnectEnd(&mConnectEnd);
146 aChannel->GetRequestStart(&mRequestStart);
147 aChannel->GetResponseStart(&mResponseStart);
148 aChannel->GetCacheReadStart(&mCacheReadStart);
149 aChannel->GetResponseEnd(&mResponseEnd);
150 aChannel->GetCacheReadEnd(&mCacheReadEnd);
152 aChannel->GetDispatchFetchEventStart(&mWorkerStart);
153 aChannel->GetHandleFetchEventStart(&mWorkerRequestStart);
154 // TODO: Track when FetchEvent.respondWith() promise resolves as
155 // ServiceWorker interception responseStart?
156 aChannel->GetHandleFetchEventEnd(&mWorkerResponseEnd);
158 // The performance timing api essentially requires that the event timestamps
159 // have a strict relation with each other. The truth, however, is the
160 // browser engages in a number of speculative activities that sometimes mean
161 // connections and lookups begin at different times. Workaround that here by
162 // clamping these values to what we expect FetchStart to be. This means the
163 // later of AsyncOpen or WorkerStart times.
164 if (!mAsyncOpen.IsNull()) {
165 // We want to clamp to the expected FetchStart value. This is later of
166 // the AsyncOpen and WorkerStart values.
167 const TimeStamp* clampTime = &mAsyncOpen;
168 if (!mWorkerStart.IsNull() && mWorkerStart > mAsyncOpen) {
169 clampTime = &mWorkerStart;
172 if (!mDomainLookupStart.IsNull() && mDomainLookupStart < *clampTime) {
173 mDomainLookupStart = *clampTime;
176 if (!mDomainLookupEnd.IsNull() && mDomainLookupEnd < *clampTime) {
177 mDomainLookupEnd = *clampTime;
180 if (!mConnectStart.IsNull() && mConnectStart < *clampTime) {
181 mConnectStart = *clampTime;
184 if (mSecureConnection && !mSecureConnectionStart.IsNull() &&
185 mSecureConnectionStart < *clampTime) {
186 mSecureConnectionStart = *clampTime;
189 if (!mConnectEnd.IsNull() && mConnectEnd < *clampTime) {
190 mConnectEnd = *clampTime;
195 // The aHttpChannel argument is null if this PerformanceTiming object is
196 // being used for navigation timing (which is only relevant for documents).
197 // It has a non-null value if this PerformanceTiming object is being used
198 // for resource timing, which can include document loads, both toplevel and
199 // in subframes, and resources linked from a document.
200 if (aHttpChannel) {
201 SetPropertiesFromHttpChannel(aHttpChannel, aChannel);
205 PerformanceTimingData::PerformanceTimingData(
206 const IPCPerformanceTimingData& aIPCData)
207 : mNextHopProtocol(aIPCData.nextHopProtocol()),
208 mAsyncOpen(aIPCData.asyncOpen()),
209 mRedirectStart(aIPCData.redirectStart()),
210 mRedirectEnd(aIPCData.redirectEnd()),
211 mDomainLookupStart(aIPCData.domainLookupStart()),
212 mDomainLookupEnd(aIPCData.domainLookupEnd()),
213 mConnectStart(aIPCData.connectStart()),
214 mSecureConnectionStart(aIPCData.secureConnectionStart()),
215 mConnectEnd(aIPCData.connectEnd()),
216 mRequestStart(aIPCData.requestStart()),
217 mResponseStart(aIPCData.responseStart()),
218 mCacheReadStart(aIPCData.cacheReadStart()),
219 mResponseEnd(aIPCData.responseEnd()),
220 mCacheReadEnd(aIPCData.cacheReadEnd()),
221 mWorkerStart(aIPCData.workerStart()),
222 mWorkerRequestStart(aIPCData.workerRequestStart()),
223 mWorkerResponseEnd(aIPCData.workerResponseEnd()),
224 mZeroTime(aIPCData.zeroTime()),
225 mFetchStart(aIPCData.fetchStart()),
226 mEncodedBodySize(aIPCData.encodedBodySize()),
227 mTransferSize(aIPCData.transferSize()),
228 mDecodedBodySize(aIPCData.decodedBodySize()),
229 mRedirectCount(aIPCData.redirectCount()),
230 mAllRedirectsSameOrigin(aIPCData.allRedirectsSameOrigin()),
231 mAllRedirectsPassTAO(aIPCData.allRedirectsPassTAO()),
232 mSecureConnection(aIPCData.secureConnection()),
233 mTimingAllowed(aIPCData.timingAllowed()),
234 mInitialized(aIPCData.initialized()) {
235 for (const auto& serverTimingData : aIPCData.serverTiming()) {
236 RefPtr<nsServerTiming> timing = new nsServerTiming();
237 timing->SetName(serverTimingData.name());
238 timing->SetDuration(serverTimingData.duration());
239 timing->SetDescription(serverTimingData.description());
240 mServerTiming.AppendElement(timing);
244 IPCPerformanceTimingData PerformanceTimingData::ToIPC() {
245 nsTArray<IPCServerTiming> ipcServerTiming;
246 for (auto& serverTimingData : mServerTiming) {
247 nsAutoCString name;
248 Unused << serverTimingData->GetName(name);
249 double duration = 0;
250 Unused << serverTimingData->GetDuration(&duration);
251 nsAutoCString description;
252 Unused << serverTimingData->GetDescription(description);
253 ipcServerTiming.AppendElement(IPCServerTiming(name, duration, description));
255 return IPCPerformanceTimingData(
256 ipcServerTiming, mNextHopProtocol, mAsyncOpen, mRedirectStart,
257 mRedirectEnd, mDomainLookupStart, mDomainLookupEnd, mConnectStart,
258 mSecureConnectionStart, mConnectEnd, mRequestStart, mResponseStart,
259 mCacheReadStart, mResponseEnd, mCacheReadEnd, mWorkerStart,
260 mWorkerRequestStart, mWorkerResponseEnd, mZeroTime, mFetchStart,
261 mEncodedBodySize, mTransferSize, mDecodedBodySize, mRedirectCount,
262 mAllRedirectsSameOrigin, mAllRedirectsPassTAO, mSecureConnection,
263 mTimingAllowed, mInitialized);
266 void PerformanceTimingData::SetPropertiesFromHttpChannel(
267 nsIHttpChannel* aHttpChannel, nsITimedChannel* aChannel) {
268 MOZ_ASSERT(aHttpChannel);
270 nsAutoCString protocol;
271 Unused << aHttpChannel->GetProtocolVersion(protocol);
272 CopyUTF8toUTF16(protocol, mNextHopProtocol);
274 Unused << aHttpChannel->GetEncodedBodySize(&mEncodedBodySize);
275 Unused << aHttpChannel->GetTransferSize(&mTransferSize);
276 Unused << aHttpChannel->GetDecodedBodySize(&mDecodedBodySize);
277 if (mDecodedBodySize == 0) {
278 mDecodedBodySize = mEncodedBodySize;
281 mTimingAllowed = CheckAllowedOrigin(aHttpChannel, aChannel);
282 aChannel->GetAllRedirectsPassTimingAllowCheck(&mAllRedirectsPassTAO);
284 aChannel->GetNativeServerTiming(mServerTiming);
287 PerformanceTiming::~PerformanceTiming() = default;
289 DOMHighResTimeStamp PerformanceTimingData::FetchStartHighRes(
290 Performance* aPerformance) {
291 MOZ_ASSERT(aPerformance);
293 if (!mFetchStart) {
294 if (!StaticPrefs::dom_enable_performance() || !IsInitialized()) {
295 return mZeroTime;
297 MOZ_ASSERT(!mAsyncOpen.IsNull(),
298 "The fetch start time stamp should always be "
299 "valid if the performance timing is enabled");
300 if (!mAsyncOpen.IsNull()) {
301 if (!mWorkerRequestStart.IsNull() && mWorkerRequestStart > mAsyncOpen) {
302 mFetchStart = TimeStampToDOMHighRes(aPerformance, mWorkerRequestStart);
303 } else {
304 mFetchStart = TimeStampToDOMHighRes(aPerformance, mAsyncOpen);
308 return nsRFPService::ReduceTimePrecisionAsMSecs(
309 mFetchStart, aPerformance->GetRandomTimelineSeed(),
310 aPerformance->GetRTPCallerType());
313 DOMTimeMilliSec PerformanceTiming::FetchStart() {
314 return static_cast<int64_t>(mTimingData->FetchStartHighRes(mPerformance));
317 bool PerformanceTimingData::CheckAllowedOrigin(nsIHttpChannel* aResourceChannel,
318 nsITimedChannel* aChannel) {
319 if (!IsInitialized()) {
320 return false;
323 // Check that the current document passes the ckeck.
324 nsCOMPtr<nsILoadInfo> loadInfo = aResourceChannel->LoadInfo();
326 // TYPE_DOCUMENT loads have no loadingPrincipal.
327 if (loadInfo->GetExternalContentPolicyType() ==
328 ExtContentPolicy::TYPE_DOCUMENT) {
329 return true;
332 nsCOMPtr<nsIPrincipal> principal = loadInfo->GetLoadingPrincipal();
334 // Check if the resource is either same origin as the page that started
335 // the load, or if the response contains the proper Timing-Allow-Origin
336 // header with the domain of the page that started the load.
337 return aChannel->TimingAllowCheck(principal);
340 uint8_t PerformanceTimingData::GetRedirectCount() const {
341 if (!StaticPrefs::dom_enable_performance() || !IsInitialized()) {
342 return 0;
344 if (!mAllRedirectsSameOrigin) {
345 return 0;
347 return mRedirectCount;
350 bool PerformanceTimingData::ShouldReportCrossOriginRedirect(
351 bool aEnsureSameOriginAndIgnoreTAO) const {
352 if (!StaticPrefs::dom_enable_performance() || !IsInitialized()) {
353 return false;
356 if (!mTimingAllowed || mRedirectCount == 0) {
357 return false;
360 // If the redirect count is 0, or if one of the cross-origin
361 // redirects doesn't have the proper Timing-Allow-Origin header,
362 // then RedirectStart and RedirectEnd will be set to zero
363 return aEnsureSameOriginAndIgnoreTAO ? mAllRedirectsSameOrigin
364 : mAllRedirectsPassTAO;
367 DOMHighResTimeStamp PerformanceTimingData::AsyncOpenHighRes(
368 Performance* aPerformance) {
369 MOZ_ASSERT(aPerformance);
371 if (!StaticPrefs::dom_enable_performance() || !IsInitialized() ||
372 mAsyncOpen.IsNull()) {
373 return mZeroTime;
375 DOMHighResTimeStamp rawValue =
376 TimeStampToDOMHighRes(aPerformance, mAsyncOpen);
377 return nsRFPService::ReduceTimePrecisionAsMSecs(
378 rawValue, aPerformance->GetRandomTimelineSeed(),
379 aPerformance->GetRTPCallerType());
382 DOMHighResTimeStamp PerformanceTimingData::WorkerStartHighRes(
383 Performance* aPerformance) {
384 MOZ_ASSERT(aPerformance);
386 if (!StaticPrefs::dom_enable_performance() || !IsInitialized() ||
387 mWorkerStart.IsNull()) {
388 return mZeroTime;
390 DOMHighResTimeStamp rawValue =
391 TimeStampToDOMHighRes(aPerformance, mWorkerStart);
392 return nsRFPService::ReduceTimePrecisionAsMSecs(
393 rawValue, aPerformance->GetRandomTimelineSeed(),
394 aPerformance->GetRTPCallerType());
398 * RedirectStartHighRes() is used by both the navigation timing and the
399 * resource timing. Since, navigation timing and resource timing check and
400 * interpret cross-domain redirects in a different manner,
401 * RedirectStartHighRes() will make no checks for cross-domain redirect.
402 * It's up to the consumers of this method (PerformanceTiming::RedirectStart()
403 * and PerformanceResourceTiming::RedirectStart() to make such verifications.
405 * @return a valid timing if the Performance Timing is enabled
407 DOMHighResTimeStamp PerformanceTimingData::RedirectStartHighRes(
408 Performance* aPerformance) {
409 MOZ_ASSERT(aPerformance);
411 if (!StaticPrefs::dom_enable_performance() || !IsInitialized()) {
412 return mZeroTime;
414 return TimeStampToReducedDOMHighResOrFetchStart(aPerformance, mRedirectStart);
417 DOMTimeMilliSec PerformanceTiming::RedirectStart() {
418 if (!mTimingData->IsInitialized()) {
419 return 0;
421 // We have to check if all the redirect URIs had the same origin (since there
422 // is no check in RedirectStartHighRes())
423 if (mTimingData->AllRedirectsSameOrigin() &&
424 mTimingData->RedirectCountReal()) {
425 return static_cast<int64_t>(
426 mTimingData->RedirectStartHighRes(mPerformance));
428 return 0;
432 * RedirectEndHighRes() is used by both the navigation timing and the resource
433 * timing. Since, navigation timing and resource timing check and interpret
434 * cross-domain redirects in a different manner, RedirectEndHighRes() will make
435 * no checks for cross-domain redirect. It's up to the consumers of this method
436 * (PerformanceTiming::RedirectEnd() and
437 * PerformanceResourceTiming::RedirectEnd() to make such verifications.
439 * @return a valid timing if the Performance Timing is enabled
441 DOMHighResTimeStamp PerformanceTimingData::RedirectEndHighRes(
442 Performance* aPerformance) {
443 MOZ_ASSERT(aPerformance);
445 if (!StaticPrefs::dom_enable_performance() || !IsInitialized()) {
446 return mZeroTime;
448 return TimeStampToReducedDOMHighResOrFetchStart(aPerformance, mRedirectEnd);
451 DOMTimeMilliSec PerformanceTiming::RedirectEnd() {
452 if (!mTimingData->IsInitialized()) {
453 return 0;
455 // We have to check if all the redirect URIs had the same origin (since there
456 // is no check in RedirectEndHighRes())
457 if (mTimingData->AllRedirectsSameOrigin() &&
458 mTimingData->RedirectCountReal()) {
459 return static_cast<int64_t>(mTimingData->RedirectEndHighRes(mPerformance));
461 return 0;
464 DOMHighResTimeStamp PerformanceTimingData::DomainLookupStartHighRes(
465 Performance* aPerformance) {
466 MOZ_ASSERT(aPerformance);
468 if (!StaticPrefs::dom_enable_performance() || !IsInitialized()) {
469 return mZeroTime;
471 // Bug 1637985 - DomainLookup information may be useful for fingerprinting.
472 if (aPerformance->ShouldResistFingerprinting()) {
473 return FetchStartHighRes(aPerformance);
475 return TimeStampToReducedDOMHighResOrFetchStart(aPerformance,
476 mDomainLookupStart);
479 DOMTimeMilliSec PerformanceTiming::DomainLookupStart() {
480 return static_cast<int64_t>(
481 mTimingData->DomainLookupStartHighRes(mPerformance));
484 DOMHighResTimeStamp PerformanceTimingData::DomainLookupEndHighRes(
485 Performance* aPerformance) {
486 MOZ_ASSERT(aPerformance);
488 if (!StaticPrefs::dom_enable_performance() || !IsInitialized()) {
489 return mZeroTime;
491 // Bug 1637985 - DomainLookup information may be useful for fingerprinting.
492 if (aPerformance->ShouldResistFingerprinting()) {
493 return FetchStartHighRes(aPerformance);
495 // Bug 1155008 - nsHttpTransaction is racy. Return DomainLookupStart when null
496 if (mDomainLookupEnd.IsNull()) {
497 return DomainLookupStartHighRes(aPerformance);
499 DOMHighResTimeStamp rawValue =
500 TimeStampToDOMHighRes(aPerformance, mDomainLookupEnd);
501 return nsRFPService::ReduceTimePrecisionAsMSecs(
502 rawValue, aPerformance->GetRandomTimelineSeed(),
503 aPerformance->GetRTPCallerType());
506 DOMTimeMilliSec PerformanceTiming::DomainLookupEnd() {
507 return static_cast<int64_t>(
508 mTimingData->DomainLookupEndHighRes(mPerformance));
511 DOMHighResTimeStamp PerformanceTimingData::ConnectStartHighRes(
512 Performance* aPerformance) {
513 MOZ_ASSERT(aPerformance);
515 if (!StaticPrefs::dom_enable_performance() || !IsInitialized()) {
516 return mZeroTime;
518 if (mConnectStart.IsNull()) {
519 return DomainLookupEndHighRes(aPerformance);
521 DOMHighResTimeStamp rawValue =
522 TimeStampToDOMHighRes(aPerformance, mConnectStart);
523 return nsRFPService::ReduceTimePrecisionAsMSecs(
524 rawValue, aPerformance->GetRandomTimelineSeed(),
525 aPerformance->GetRTPCallerType());
528 DOMTimeMilliSec PerformanceTiming::ConnectStart() {
529 return static_cast<int64_t>(mTimingData->ConnectStartHighRes(mPerformance));
532 DOMHighResTimeStamp PerformanceTimingData::SecureConnectionStartHighRes(
533 Performance* aPerformance) {
534 MOZ_ASSERT(aPerformance);
536 if (!StaticPrefs::dom_enable_performance() || !IsInitialized()) {
537 return mZeroTime;
539 if (!mSecureConnection) {
540 return 0; // We use 0 here, because mZeroTime is sometimes set to the
541 // navigation start time.
543 if (mSecureConnectionStart.IsNull()) {
544 return ConnectStartHighRes(aPerformance);
546 DOMHighResTimeStamp rawValue =
547 TimeStampToDOMHighRes(aPerformance, mSecureConnectionStart);
548 return nsRFPService::ReduceTimePrecisionAsMSecs(
549 rawValue, aPerformance->GetRandomTimelineSeed(),
550 aPerformance->GetRTPCallerType());
553 DOMTimeMilliSec PerformanceTiming::SecureConnectionStart() {
554 return static_cast<int64_t>(
555 mTimingData->SecureConnectionStartHighRes(mPerformance));
558 DOMHighResTimeStamp PerformanceTimingData::ConnectEndHighRes(
559 Performance* aPerformance) {
560 MOZ_ASSERT(aPerformance);
562 if (!StaticPrefs::dom_enable_performance() || !IsInitialized()) {
563 return mZeroTime;
565 // Bug 1155008 - nsHttpTransaction is racy. Return ConnectStart when null
566 if (mConnectEnd.IsNull()) {
567 return ConnectStartHighRes(aPerformance);
569 DOMHighResTimeStamp rawValue =
570 TimeStampToDOMHighRes(aPerformance, mConnectEnd);
571 return nsRFPService::ReduceTimePrecisionAsMSecs(
572 rawValue, aPerformance->GetRandomTimelineSeed(),
573 aPerformance->GetRTPCallerType());
576 DOMTimeMilliSec PerformanceTiming::ConnectEnd() {
577 return static_cast<int64_t>(mTimingData->ConnectEndHighRes(mPerformance));
580 DOMHighResTimeStamp PerformanceTimingData::RequestStartHighRes(
581 Performance* aPerformance) {
582 MOZ_ASSERT(aPerformance);
584 if (!StaticPrefs::dom_enable_performance() || !IsInitialized()) {
585 return mZeroTime;
588 if (mRequestStart.IsNull()) {
589 mRequestStart = mWorkerRequestStart;
592 return TimeStampToReducedDOMHighResOrFetchStart(aPerformance, mRequestStart);
595 DOMTimeMilliSec PerformanceTiming::RequestStart() {
596 return static_cast<int64_t>(mTimingData->RequestStartHighRes(mPerformance));
599 DOMHighResTimeStamp PerformanceTimingData::ResponseStartHighRes(
600 Performance* aPerformance) {
601 MOZ_ASSERT(aPerformance);
603 if (!StaticPrefs::dom_enable_performance() || !IsInitialized()) {
604 return mZeroTime;
606 if (mResponseStart.IsNull() ||
607 (!mCacheReadStart.IsNull() && mCacheReadStart < mResponseStart)) {
608 mResponseStart = mCacheReadStart;
611 if (mResponseStart.IsNull() ||
612 (!mRequestStart.IsNull() && mResponseStart < mRequestStart)) {
613 mResponseStart = mRequestStart;
615 return TimeStampToReducedDOMHighResOrFetchStart(aPerformance, mResponseStart);
618 DOMTimeMilliSec PerformanceTiming::ResponseStart() {
619 return static_cast<int64_t>(mTimingData->ResponseStartHighRes(mPerformance));
622 DOMHighResTimeStamp PerformanceTimingData::ResponseEndHighRes(
623 Performance* aPerformance) {
624 MOZ_ASSERT(aPerformance);
626 if (!StaticPrefs::dom_enable_performance() || !IsInitialized()) {
627 return mZeroTime;
629 if (mResponseEnd.IsNull() ||
630 (!mCacheReadEnd.IsNull() && mCacheReadEnd < mResponseEnd)) {
631 mResponseEnd = mCacheReadEnd;
633 if (mResponseEnd.IsNull()) {
634 mResponseEnd = mWorkerResponseEnd;
636 // Bug 1155008 - nsHttpTransaction is racy. Return ResponseStart when null
637 if (mResponseEnd.IsNull()) {
638 return ResponseStartHighRes(aPerformance);
640 DOMHighResTimeStamp rawValue =
641 TimeStampToDOMHighRes(aPerformance, mResponseEnd);
642 return nsRFPService::ReduceTimePrecisionAsMSecs(
643 rawValue, aPerformance->GetRandomTimelineSeed(),
644 aPerformance->GetRTPCallerType());
647 DOMTimeMilliSec PerformanceTiming::ResponseEnd() {
648 return static_cast<int64_t>(mTimingData->ResponseEndHighRes(mPerformance));
651 JSObject* PerformanceTiming::WrapObject(JSContext* cx,
652 JS::Handle<JSObject*> aGivenProto) {
653 return PerformanceTiming_Binding::Wrap(cx, this, aGivenProto);
656 bool PerformanceTiming::IsTopLevelContentDocument() const {
657 nsCOMPtr<Document> document = mPerformance->GetDocumentIfCurrent();
658 if (!document) {
659 return false;
662 if (BrowsingContext* bc = document->GetBrowsingContext()) {
663 return bc->IsTopContent();
665 return false;
668 nsTArray<nsCOMPtr<nsIServerTiming>> PerformanceTimingData::GetServerTiming() {
669 if (!StaticPrefs::dom_enable_performance() || !IsInitialized() ||
670 !TimingAllowed()) {
671 return nsTArray<nsCOMPtr<nsIServerTiming>>();
674 return mServerTiming.Clone();
677 } // namespace mozilla::dom