Bug 1708193 - Remove mozapps/extensions/internal/Content.js r=rpl
[gecko.git] / dom / performance / PerformanceTiming.cpp
blobf62003b2ef5c7fa3ce4a9ef36b6e829e9d95e91c
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/dom/PerformanceTimingBinding.h"
10 #include "mozilla/StaticPrefs_dom.h"
11 #include "mozilla/Telemetry.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 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(PerformanceTiming, AddRef)
24 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(PerformanceTiming, Release)
26 /* static */
27 PerformanceTimingData* PerformanceTimingData::Create(
28 nsITimedChannel* aTimedChannel, nsIHttpChannel* aChannel,
29 DOMHighResTimeStamp aZeroTime, nsAString& aInitiatorType,
30 nsAString& aEntryName) {
31 MOZ_ASSERT(NS_IsMainThread());
33 // Check if resource timing is prefed off.
34 if (!StaticPrefs::dom_enable_resource_timing()) {
35 return nullptr;
38 if (!aChannel || !aTimedChannel) {
39 return nullptr;
42 bool reportTiming = true;
43 aTimedChannel->GetReportResourceTiming(&reportTiming);
45 if (!reportTiming) {
46 return nullptr;
49 aTimedChannel->GetInitiatorType(aInitiatorType);
51 // If the initiator type had no valid value, then set it to the default
52 // ("other") value.
53 if (aInitiatorType.IsEmpty()) {
54 aInitiatorType = u"other"_ns;
57 // According to the spec, "The name attribute must return the resolved URL
58 // of the requested resource. This attribute must not change even if the
59 // fetch redirected to a different URL."
60 nsCOMPtr<nsIURI> originalURI;
61 aChannel->GetOriginalURI(getter_AddRefs(originalURI));
63 nsAutoCString name;
64 originalURI->GetSpec(name);
65 CopyUTF8toUTF16(name, aEntryName);
67 // The nsITimedChannel argument will be used to gather all the timings.
68 // The nsIHttpChannel argument will be used to check if any cross-origin
69 // redirects occurred.
70 // The last argument is the "zero time" (offset). Since we don't want
71 // any offset for the resource timing, this will be set to "0" - the
72 // resource timing returns a relative timing (no offset).
73 return new PerformanceTimingData(aTimedChannel, aChannel, 0);
76 PerformanceTiming::PerformanceTiming(Performance* aPerformance,
77 nsITimedChannel* aChannel,
78 nsIHttpChannel* aHttpChannel,
79 DOMHighResTimeStamp aZeroTime)
80 : mPerformance(aPerformance) {
81 MOZ_ASSERT(aPerformance, "Parent performance object should be provided");
83 mTimingData.reset(new PerformanceTimingData(
84 aChannel, aHttpChannel,
85 nsRFPService::ReduceTimePrecisionAsMSecs(
86 aZeroTime, aPerformance->GetRandomTimelineSeed(),
87 aPerformance->IsSystemPrincipal(),
88 aPerformance->CrossOriginIsolated())));
90 // Non-null aHttpChannel implies that this PerformanceTiming object is being
91 // used for subresources, which is irrelevant to this probe.
92 if (!aHttpChannel && StaticPrefs::dom_enable_performance() &&
93 IsTopLevelContentDocument()) {
94 Telemetry::Accumulate(Telemetry::TIME_TO_RESPONSE_START_MS,
95 mTimingData->ResponseStartHighRes(aPerformance) -
96 mTimingData->ZeroTime());
100 // Copy the timing info from the channel so we don't need to keep the channel
101 // alive just to get the timestamps.
102 PerformanceTimingData::PerformanceTimingData(nsITimedChannel* aChannel,
103 nsIHttpChannel* aHttpChannel,
104 DOMHighResTimeStamp aZeroTime)
105 : mZeroTime(0.0),
106 mFetchStart(0.0),
107 mEncodedBodySize(0),
108 mTransferSize(0),
109 mDecodedBodySize(0),
110 mRedirectCount(0),
111 mAllRedirectsSameOrigin(true),
112 mAllRedirectsPassTAO(true),
113 mSecureConnection(false),
114 mTimingAllowed(true),
115 mInitialized(false) {
116 mInitialized = !!aChannel;
117 mZeroTime = aZeroTime;
119 if (!StaticPrefs::dom_enable_performance() ||
120 nsContentUtils::ShouldResistFingerprinting()) {
121 mZeroTime = 0;
124 nsCOMPtr<nsIURI> uri;
125 if (aHttpChannel) {
126 aHttpChannel->GetURI(getter_AddRefs(uri));
127 } else {
128 nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel);
129 if (httpChannel) {
130 httpChannel->GetURI(getter_AddRefs(uri));
134 if (uri) {
135 mSecureConnection = uri->SchemeIs("https");
138 if (aChannel) {
139 aChannel->GetAsyncOpen(&mAsyncOpen);
140 aChannel->GetAllRedirectsSameOrigin(&mAllRedirectsSameOrigin);
141 aChannel->GetRedirectCount(&mRedirectCount);
142 aChannel->GetRedirectStart(&mRedirectStart);
143 aChannel->GetRedirectEnd(&mRedirectEnd);
144 aChannel->GetDomainLookupStart(&mDomainLookupStart);
145 aChannel->GetDomainLookupEnd(&mDomainLookupEnd);
146 aChannel->GetConnectStart(&mConnectStart);
147 aChannel->GetSecureConnectionStart(&mSecureConnectionStart);
148 aChannel->GetConnectEnd(&mConnectEnd);
149 aChannel->GetRequestStart(&mRequestStart);
150 aChannel->GetResponseStart(&mResponseStart);
151 aChannel->GetCacheReadStart(&mCacheReadStart);
152 aChannel->GetResponseEnd(&mResponseEnd);
153 aChannel->GetCacheReadEnd(&mCacheReadEnd);
155 aChannel->GetDispatchFetchEventStart(&mWorkerStart);
156 aChannel->GetHandleFetchEventStart(&mWorkerRequestStart);
157 // TODO: Track when FetchEvent.respondWith() promise resolves as
158 // ServiceWorker interception responseStart?
159 aChannel->GetHandleFetchEventEnd(&mWorkerResponseEnd);
161 // The performance timing api essentially requires that the event timestamps
162 // have a strict relation with each other. The truth, however, is the
163 // browser engages in a number of speculative activities that sometimes mean
164 // connections and lookups begin at different times. Workaround that here by
165 // clamping these values to what we expect FetchStart to be. This means the
166 // later of AsyncOpen or WorkerStart times.
167 if (!mAsyncOpen.IsNull()) {
168 // We want to clamp to the expected FetchStart value. This is later of
169 // the AsyncOpen and WorkerStart values.
170 const TimeStamp* clampTime = &mAsyncOpen;
171 if (!mWorkerStart.IsNull() && mWorkerStart > mAsyncOpen) {
172 clampTime = &mWorkerStart;
175 if (!mDomainLookupStart.IsNull() && mDomainLookupStart < *clampTime) {
176 mDomainLookupStart = *clampTime;
179 if (!mDomainLookupEnd.IsNull() && mDomainLookupEnd < *clampTime) {
180 mDomainLookupEnd = *clampTime;
183 if (!mConnectStart.IsNull() && mConnectStart < *clampTime) {
184 mConnectStart = *clampTime;
187 if (mSecureConnection && !mSecureConnectionStart.IsNull() &&
188 mSecureConnectionStart < *clampTime) {
189 mSecureConnectionStart = *clampTime;
192 if (!mConnectEnd.IsNull() && mConnectEnd < *clampTime) {
193 mConnectEnd = *clampTime;
198 // The aHttpChannel argument is null if this PerformanceTiming object is
199 // being used for navigation timing (which is only relevant for documents).
200 // It has a non-null value if this PerformanceTiming object is being used
201 // for resource timing, which can include document loads, both toplevel and
202 // in subframes, and resources linked from a document.
203 if (aHttpChannel) {
204 SetPropertiesFromHttpChannel(aHttpChannel, aChannel);
208 void PerformanceTimingData::SetPropertiesFromHttpChannel(
209 nsIHttpChannel* aHttpChannel, nsITimedChannel* aChannel) {
210 MOZ_ASSERT(aHttpChannel);
212 nsAutoCString protocol;
213 Unused << aHttpChannel->GetProtocolVersion(protocol);
214 CopyUTF8toUTF16(protocol, mNextHopProtocol);
216 Unused << aHttpChannel->GetEncodedBodySize(&mEncodedBodySize);
217 Unused << aHttpChannel->GetTransferSize(&mTransferSize);
218 Unused << aHttpChannel->GetDecodedBodySize(&mDecodedBodySize);
219 if (mDecodedBodySize == 0) {
220 mDecodedBodySize = mEncodedBodySize;
223 mTimingAllowed = CheckAllowedOrigin(aHttpChannel, aChannel);
224 aChannel->GetAllRedirectsPassTimingAllowCheck(&mAllRedirectsPassTAO);
226 aChannel->GetNativeServerTiming(mServerTiming);
229 PerformanceTiming::~PerformanceTiming() = default;
231 DOMHighResTimeStamp PerformanceTimingData::FetchStartHighRes(
232 Performance* aPerformance) {
233 MOZ_ASSERT(aPerformance);
235 if (!mFetchStart) {
236 if (!StaticPrefs::dom_enable_performance() || !IsInitialized()) {
237 return mZeroTime;
239 MOZ_ASSERT(!mAsyncOpen.IsNull(),
240 "The fetch start time stamp should always be "
241 "valid if the performance timing is enabled");
242 if (!mAsyncOpen.IsNull()) {
243 if (!mWorkerRequestStart.IsNull() && mWorkerRequestStart > mAsyncOpen) {
244 mFetchStart = TimeStampToDOMHighRes(aPerformance, mWorkerRequestStart);
245 } else {
246 mFetchStart = TimeStampToDOMHighRes(aPerformance, mAsyncOpen);
250 return nsRFPService::ReduceTimePrecisionAsMSecs(
251 mFetchStart, aPerformance->GetRandomTimelineSeed(),
252 aPerformance->IsSystemPrincipal(), aPerformance->CrossOriginIsolated());
255 DOMTimeMilliSec PerformanceTiming::FetchStart() {
256 return static_cast<int64_t>(mTimingData->FetchStartHighRes(mPerformance));
259 bool PerformanceTimingData::CheckAllowedOrigin(nsIHttpChannel* aResourceChannel,
260 nsITimedChannel* aChannel) {
261 if (!IsInitialized()) {
262 return false;
265 // Check that the current document passes the ckeck.
266 nsCOMPtr<nsILoadInfo> loadInfo = aResourceChannel->LoadInfo();
268 // TYPE_DOCUMENT loads have no loadingPrincipal.
269 if (loadInfo->GetExternalContentPolicyType() ==
270 ExtContentPolicy::TYPE_DOCUMENT) {
271 return true;
274 nsCOMPtr<nsIPrincipal> principal = loadInfo->GetLoadingPrincipal();
276 // Check if the resource is either same origin as the page that started
277 // the load, or if the response contains the proper Timing-Allow-Origin
278 // header with the domain of the page that started the load.
279 return aChannel->TimingAllowCheck(principal);
282 uint8_t PerformanceTimingData::GetRedirectCount() const {
283 if (!StaticPrefs::dom_enable_performance() || !IsInitialized() ||
284 nsContentUtils::ShouldResistFingerprinting()) {
285 return 0;
287 if (!mAllRedirectsSameOrigin) {
288 return 0;
290 return mRedirectCount;
293 bool PerformanceTimingData::ShouldReportCrossOriginRedirect(
294 bool aEnsureSameOriginAndIgnoreTAO) const {
295 if (!StaticPrefs::dom_enable_performance() || !IsInitialized() ||
296 nsContentUtils::ShouldResistFingerprinting()) {
297 return false;
300 if (!mTimingAllowed || mRedirectCount == 0) {
301 return false;
304 // If the redirect count is 0, or if one of the cross-origin
305 // redirects doesn't have the proper Timing-Allow-Origin header,
306 // then RedirectStart and RedirectEnd will be set to zero
307 return aEnsureSameOriginAndIgnoreTAO ? mAllRedirectsSameOrigin
308 : mAllRedirectsPassTAO;
311 DOMHighResTimeStamp PerformanceTimingData::AsyncOpenHighRes(
312 Performance* aPerformance) {
313 MOZ_ASSERT(aPerformance);
315 if (!StaticPrefs::dom_enable_performance() || !IsInitialized() ||
316 mAsyncOpen.IsNull()) {
317 return mZeroTime;
319 DOMHighResTimeStamp rawValue =
320 TimeStampToDOMHighRes(aPerformance, mAsyncOpen);
321 return nsRFPService::ReduceTimePrecisionAsMSecs(
322 rawValue, aPerformance->GetRandomTimelineSeed(),
323 aPerformance->IsSystemPrincipal(), aPerformance->CrossOriginIsolated());
326 DOMHighResTimeStamp PerformanceTimingData::WorkerStartHighRes(
327 Performance* aPerformance) {
328 MOZ_ASSERT(aPerformance);
330 if (!StaticPrefs::dom_enable_performance() || !IsInitialized() ||
331 mWorkerStart.IsNull()) {
332 return mZeroTime;
334 DOMHighResTimeStamp rawValue =
335 TimeStampToDOMHighRes(aPerformance, mWorkerStart);
336 return nsRFPService::ReduceTimePrecisionAsMSecs(
337 rawValue, aPerformance->GetRandomTimelineSeed(),
338 aPerformance->IsSystemPrincipal(), aPerformance->CrossOriginIsolated());
342 * RedirectStartHighRes() is used by both the navigation timing and the
343 * resource timing. Since, navigation timing and resource timing check and
344 * interpret cross-domain redirects in a different manner,
345 * RedirectStartHighRes() will make no checks for cross-domain redirect.
346 * It's up to the consumers of this method (PerformanceTiming::RedirectStart()
347 * and PerformanceResourceTiming::RedirectStart() to make such verifications.
349 * @return a valid timing if the Performance Timing is enabled
351 DOMHighResTimeStamp PerformanceTimingData::RedirectStartHighRes(
352 Performance* aPerformance) {
353 MOZ_ASSERT(aPerformance);
355 if (!StaticPrefs::dom_enable_performance() || !IsInitialized()) {
356 return mZeroTime;
358 return TimeStampToReducedDOMHighResOrFetchStart(aPerformance, mRedirectStart);
361 DOMTimeMilliSec PerformanceTiming::RedirectStart() {
362 if (!mTimingData->IsInitialized()) {
363 return 0;
365 // We have to check if all the redirect URIs had the same origin (since there
366 // is no check in RedirectStartHighRes())
367 if (mTimingData->AllRedirectsSameOrigin() &&
368 mTimingData->RedirectCountReal()) {
369 return static_cast<int64_t>(
370 mTimingData->RedirectStartHighRes(mPerformance));
372 return 0;
376 * RedirectEndHighRes() is used by both the navigation timing and the resource
377 * timing. Since, navigation timing and resource timing check and interpret
378 * cross-domain redirects in a different manner, RedirectEndHighRes() will make
379 * no checks for cross-domain redirect. It's up to the consumers of this method
380 * (PerformanceTiming::RedirectEnd() and
381 * PerformanceResourceTiming::RedirectEnd() to make such verifications.
383 * @return a valid timing if the Performance Timing is enabled
385 DOMHighResTimeStamp PerformanceTimingData::RedirectEndHighRes(
386 Performance* aPerformance) {
387 MOZ_ASSERT(aPerformance);
389 if (!StaticPrefs::dom_enable_performance() || !IsInitialized()) {
390 return mZeroTime;
392 return TimeStampToReducedDOMHighResOrFetchStart(aPerformance, mRedirectEnd);
395 DOMTimeMilliSec PerformanceTiming::RedirectEnd() {
396 if (!mTimingData->IsInitialized()) {
397 return 0;
399 // We have to check if all the redirect URIs had the same origin (since there
400 // is no check in RedirectEndHighRes())
401 if (mTimingData->AllRedirectsSameOrigin() &&
402 mTimingData->RedirectCountReal()) {
403 return static_cast<int64_t>(mTimingData->RedirectEndHighRes(mPerformance));
405 return 0;
408 DOMHighResTimeStamp PerformanceTimingData::DomainLookupStartHighRes(
409 Performance* aPerformance) {
410 MOZ_ASSERT(aPerformance);
412 if (!StaticPrefs::dom_enable_performance() || !IsInitialized()) {
413 return mZeroTime;
415 // Bug 1637985 - DomainLookup information may be useful for fingerprinting.
416 if (nsContentUtils::ShouldResistFingerprinting()) {
417 return FetchStartHighRes(aPerformance);
419 return TimeStampToReducedDOMHighResOrFetchStart(aPerformance,
420 mDomainLookupStart);
423 DOMTimeMilliSec PerformanceTiming::DomainLookupStart() {
424 return static_cast<int64_t>(
425 mTimingData->DomainLookupStartHighRes(mPerformance));
428 DOMHighResTimeStamp PerformanceTimingData::DomainLookupEndHighRes(
429 Performance* aPerformance) {
430 MOZ_ASSERT(aPerformance);
432 if (!StaticPrefs::dom_enable_performance() || !IsInitialized()) {
433 return mZeroTime;
435 // Bug 1637985 - DomainLookup information may be useful for fingerprinting.
436 if (nsContentUtils::ShouldResistFingerprinting()) {
437 return FetchStartHighRes(aPerformance);
439 // Bug 1155008 - nsHttpTransaction is racy. Return DomainLookupStart when null
440 if (mDomainLookupEnd.IsNull()) {
441 return DomainLookupStartHighRes(aPerformance);
443 DOMHighResTimeStamp rawValue =
444 TimeStampToDOMHighRes(aPerformance, mDomainLookupEnd);
445 return nsRFPService::ReduceTimePrecisionAsMSecs(
446 rawValue, aPerformance->GetRandomTimelineSeed(),
447 aPerformance->IsSystemPrincipal(), aPerformance->CrossOriginIsolated());
450 DOMTimeMilliSec PerformanceTiming::DomainLookupEnd() {
451 return static_cast<int64_t>(
452 mTimingData->DomainLookupEndHighRes(mPerformance));
455 DOMHighResTimeStamp PerformanceTimingData::ConnectStartHighRes(
456 Performance* aPerformance) {
457 MOZ_ASSERT(aPerformance);
459 if (!StaticPrefs::dom_enable_performance() || !IsInitialized()) {
460 return mZeroTime;
462 if (mConnectStart.IsNull()) {
463 return DomainLookupEndHighRes(aPerformance);
465 DOMHighResTimeStamp rawValue =
466 TimeStampToDOMHighRes(aPerformance, mConnectStart);
467 return nsRFPService::ReduceTimePrecisionAsMSecs(
468 rawValue, aPerformance->GetRandomTimelineSeed(),
469 aPerformance->IsSystemPrincipal(), aPerformance->CrossOriginIsolated());
472 DOMTimeMilliSec PerformanceTiming::ConnectStart() {
473 return static_cast<int64_t>(mTimingData->ConnectStartHighRes(mPerformance));
476 DOMHighResTimeStamp PerformanceTimingData::SecureConnectionStartHighRes(
477 Performance* aPerformance) {
478 MOZ_ASSERT(aPerformance);
480 if (!StaticPrefs::dom_enable_performance() || !IsInitialized()) {
481 return mZeroTime;
483 if (!mSecureConnection) {
484 return 0; // We use 0 here, because mZeroTime is sometimes set to the
485 // navigation start time.
487 if (mSecureConnectionStart.IsNull()) {
488 return ConnectStartHighRes(aPerformance);
490 DOMHighResTimeStamp rawValue =
491 TimeStampToDOMHighRes(aPerformance, mSecureConnectionStart);
492 return nsRFPService::ReduceTimePrecisionAsMSecs(
493 rawValue, aPerformance->GetRandomTimelineSeed(),
494 aPerformance->IsSystemPrincipal(), aPerformance->CrossOriginIsolated());
497 DOMTimeMilliSec PerformanceTiming::SecureConnectionStart() {
498 return static_cast<int64_t>(
499 mTimingData->SecureConnectionStartHighRes(mPerformance));
502 DOMHighResTimeStamp PerformanceTimingData::ConnectEndHighRes(
503 Performance* aPerformance) {
504 MOZ_ASSERT(aPerformance);
506 if (!StaticPrefs::dom_enable_performance() || !IsInitialized()) {
507 return mZeroTime;
509 // Bug 1155008 - nsHttpTransaction is racy. Return ConnectStart when null
510 if (mConnectEnd.IsNull()) {
511 return ConnectStartHighRes(aPerformance);
513 DOMHighResTimeStamp rawValue =
514 TimeStampToDOMHighRes(aPerformance, mConnectEnd);
515 return nsRFPService::ReduceTimePrecisionAsMSecs(
516 rawValue, aPerformance->GetRandomTimelineSeed(),
517 aPerformance->IsSystemPrincipal(), aPerformance->CrossOriginIsolated());
520 DOMTimeMilliSec PerformanceTiming::ConnectEnd() {
521 return static_cast<int64_t>(mTimingData->ConnectEndHighRes(mPerformance));
524 DOMHighResTimeStamp PerformanceTimingData::RequestStartHighRes(
525 Performance* aPerformance) {
526 MOZ_ASSERT(aPerformance);
528 if (!StaticPrefs::dom_enable_performance() || !IsInitialized()) {
529 return mZeroTime;
532 if (mRequestStart.IsNull()) {
533 mRequestStart = mWorkerRequestStart;
536 return TimeStampToReducedDOMHighResOrFetchStart(aPerformance, mRequestStart);
539 DOMTimeMilliSec PerformanceTiming::RequestStart() {
540 return static_cast<int64_t>(mTimingData->RequestStartHighRes(mPerformance));
543 DOMHighResTimeStamp PerformanceTimingData::ResponseStartHighRes(
544 Performance* aPerformance) {
545 MOZ_ASSERT(aPerformance);
547 if (!StaticPrefs::dom_enable_performance() || !IsInitialized()) {
548 return mZeroTime;
550 if (mResponseStart.IsNull() ||
551 (!mCacheReadStart.IsNull() && mCacheReadStart < mResponseStart)) {
552 mResponseStart = mCacheReadStart;
555 if (mResponseStart.IsNull() ||
556 (!mRequestStart.IsNull() && mResponseStart < mRequestStart)) {
557 mResponseStart = mRequestStart;
559 return TimeStampToReducedDOMHighResOrFetchStart(aPerformance, mResponseStart);
562 DOMTimeMilliSec PerformanceTiming::ResponseStart() {
563 return static_cast<int64_t>(mTimingData->ResponseStartHighRes(mPerformance));
566 DOMHighResTimeStamp PerformanceTimingData::ResponseEndHighRes(
567 Performance* aPerformance) {
568 MOZ_ASSERT(aPerformance);
570 if (!StaticPrefs::dom_enable_performance() || !IsInitialized()) {
571 return mZeroTime;
573 if (mResponseEnd.IsNull() ||
574 (!mCacheReadEnd.IsNull() && mCacheReadEnd < mResponseEnd)) {
575 mResponseEnd = mCacheReadEnd;
577 if (mResponseEnd.IsNull()) {
578 mResponseEnd = mWorkerResponseEnd;
580 // Bug 1155008 - nsHttpTransaction is racy. Return ResponseStart when null
581 if (mResponseEnd.IsNull()) {
582 return ResponseStartHighRes(aPerformance);
584 DOMHighResTimeStamp rawValue =
585 TimeStampToDOMHighRes(aPerformance, mResponseEnd);
586 return nsRFPService::ReduceTimePrecisionAsMSecs(
587 rawValue, aPerformance->GetRandomTimelineSeed(),
588 aPerformance->IsSystemPrincipal(), aPerformance->CrossOriginIsolated());
591 DOMTimeMilliSec PerformanceTiming::ResponseEnd() {
592 return static_cast<int64_t>(mTimingData->ResponseEndHighRes(mPerformance));
595 JSObject* PerformanceTiming::WrapObject(JSContext* cx,
596 JS::Handle<JSObject*> aGivenProto) {
597 return PerformanceTiming_Binding::Wrap(cx, this, aGivenProto);
600 bool PerformanceTiming::IsTopLevelContentDocument() const {
601 nsCOMPtr<Document> document = mPerformance->GetDocumentIfCurrent();
602 if (!document) {
603 return false;
606 if (BrowsingContext* bc = document->GetBrowsingContext()) {
607 return bc->IsTopContent();
609 return false;
612 nsTArray<nsCOMPtr<nsIServerTiming>> PerformanceTimingData::GetServerTiming() {
613 if (!StaticPrefs::dom_enable_performance() || !IsInitialized() ||
614 !TimingAllowed()) {
615 return nsTArray<nsCOMPtr<nsIServerTiming>>();
618 return mServerTiming.Clone();
621 } // namespace mozilla::dom