diff --git a/dom/performance/PerformanceMainThread.cpp b/dom/performance/PerformanceMainThread.cpp index bd842e918e13..bd23b09b1106 100644 --- a/dom/performance/PerformanceMainThread.cpp +++ b/dom/performance/PerformanceMainThread.cpp @@ -159,14 +159,14 @@ PerformanceMainThread::AddEntry(nsIHttpChannel* channel, // The last argument is the "zero time" (offset). Since we don't want // any offset for the resource timing, this will be set to "0" - the // resource timing returns a relative timing (no offset). - RefPtr performanceTiming = - new PerformanceTiming(this, timedChannel, channel, - 0); + UniquePtr performanceTimingData( + new PerformanceTimingData(timedChannel, channel, 0)); // The PerformanceResourceTiming object will use the PerformanceTiming // object to get all the required timings. RefPtr performanceEntry = - new PerformanceResourceTiming(performanceTiming, this, entryName, channel); + new PerformanceResourceTiming(Move(performanceTimingData), this, + entryName); // If the initiator type had no valid value, then set it to the default // ("other") value. @@ -326,10 +326,9 @@ PerformanceMainThread::EnsureDocEntry() { if (!mDocEntry && nsContentUtils::IsPerformanceNavigationTimingEnabled()) { nsCOMPtr httpChannel = do_QueryInterface(mChannel); - RefPtr timing = - new PerformanceTiming(this, mChannel, nullptr, 0); - mDocEntry = new PerformanceNavigationTiming(timing, this, - httpChannel); + UniquePtr timing( + new PerformanceTimingData(mChannel, nullptr, 0)); + mDocEntry = new PerformanceNavigationTiming(Move(timing), this); } } diff --git a/dom/performance/PerformanceNavigation.cpp b/dom/performance/PerformanceNavigation.cpp index 474e6c2618c0..6c564d7d3c4c 100644 --- a/dom/performance/PerformanceNavigation.cpp +++ b/dom/performance/PerformanceNavigation.cpp @@ -36,7 +36,7 @@ PerformanceNavigation::WrapObject(JSContext *cx, uint16_t PerformanceNavigation::RedirectCount() const { - return GetPerformanceTiming()->GetRedirectCount(); + return GetPerformanceTiming()->Data()->GetRedirectCount(); } } // dom namespace diff --git a/dom/performance/PerformanceNavigationTiming.cpp b/dom/performance/PerformanceNavigationTiming.cpp index 4e00b2bb21dc..d73eb56d0a06 100644 --- a/dom/performance/PerformanceNavigationTiming.cpp +++ b/dom/performance/PerformanceNavigationTiming.cpp @@ -24,55 +24,55 @@ PerformanceNavigationTiming::WrapObject(JSContext* aCx, JS::Handle aG DOMHighResTimeStamp PerformanceNavigationTiming::UnloadEventStart() const { - return mTiming->GetDOMTiming()->GetUnloadEventStartHighRes(); + return mPerformance->GetDOMTiming()->GetUnloadEventStartHighRes(); } DOMHighResTimeStamp PerformanceNavigationTiming::UnloadEventEnd() const { - return mTiming->GetDOMTiming()->GetUnloadEventEndHighRes(); + return mPerformance->GetDOMTiming()->GetUnloadEventEndHighRes(); } DOMHighResTimeStamp PerformanceNavigationTiming::DomInteractive() const { - return mTiming->GetDOMTiming()->GetDomInteractiveHighRes(); + return mPerformance->GetDOMTiming()->GetDomInteractiveHighRes(); } DOMHighResTimeStamp PerformanceNavigationTiming::DomContentLoadedEventStart() const { - return mTiming->GetDOMTiming()->GetDomContentLoadedEventStartHighRes(); + return mPerformance->GetDOMTiming()->GetDomContentLoadedEventStartHighRes(); } DOMHighResTimeStamp PerformanceNavigationTiming::DomContentLoadedEventEnd() const { - return mTiming->GetDOMTiming()->GetDomContentLoadedEventEndHighRes(); + return mPerformance->GetDOMTiming()->GetDomContentLoadedEventEndHighRes(); } DOMHighResTimeStamp PerformanceNavigationTiming::DomComplete() const { - return mTiming->GetDOMTiming()->GetDomCompleteHighRes(); + return mPerformance->GetDOMTiming()->GetDomCompleteHighRes(); } DOMHighResTimeStamp PerformanceNavigationTiming::LoadEventStart() const { - return mTiming->GetDOMTiming()->GetLoadEventStartHighRes(); + return mPerformance->GetDOMTiming()->GetLoadEventStartHighRes(); } DOMHighResTimeStamp PerformanceNavigationTiming::LoadEventEnd() const { - return mTiming->GetDOMTiming()->GetLoadEventEndHighRes(); + return mPerformance->GetDOMTiming()->GetLoadEventEndHighRes(); } NavigationType PerformanceNavigationTiming::Type() const { - switch(mTiming->GetDOMTiming()->GetType()) { + switch(mPerformance->GetDOMTiming()->GetType()) { case nsDOMNavigationTiming::TYPE_NAVIGATE: return NavigationType::Navigate; break; @@ -92,5 +92,5 @@ PerformanceNavigationTiming::Type() const uint16_t PerformanceNavigationTiming::RedirectCount() const { - return mTiming->GetRedirectCount(); + return mTimingData->GetRedirectCount(); } diff --git a/dom/performance/PerformanceNavigationTiming.h b/dom/performance/PerformanceNavigationTiming.h index 8d698e305b4d..afc586337b1a 100644 --- a/dom/performance/PerformanceNavigationTiming.h +++ b/dom/performance/PerformanceNavigationTiming.h @@ -29,11 +29,10 @@ public: // so that timestamps are relative to startTime, as opposed to the // performance.timing object for which timestamps are absolute and has a // zeroTime initialized to navigationStart - explicit PerformanceNavigationTiming(PerformanceTiming* aPerformanceTiming, - Performance* aPerformance, - nsIHttpChannel* aChannel) - : PerformanceResourceTiming(aPerformanceTiming, aPerformance, - NS_LITERAL_STRING("document"), aChannel) { + PerformanceNavigationTiming(UniquePtr&& aPerformanceTiming, + Performance* aPerformance) + : PerformanceResourceTiming(Move(aPerformanceTiming), aPerformance, + NS_LITERAL_STRING("document")) { SetEntryType(NS_LITERAL_STRING("navigation")); SetInitiatorType(NS_LITERAL_STRING("navigation")); } diff --git a/dom/performance/PerformanceResourceTiming.cpp b/dom/performance/PerformanceResourceTiming.cpp index f08f320ca729..31f0aa67ae0c 100644 --- a/dom/performance/PerformanceResourceTiming.cpp +++ b/dom/performance/PerformanceResourceTiming.cpp @@ -11,7 +11,7 @@ using namespace mozilla::dom; NS_IMPL_CYCLE_COLLECTION_INHERITED(PerformanceResourceTiming, PerformanceEntry, - mTiming) + mPerformance) NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(PerformanceResourceTiming, PerformanceEntry) @@ -23,45 +23,14 @@ NS_INTERFACE_MAP_END_INHERITING(PerformanceEntry) NS_IMPL_ADDREF_INHERITED(PerformanceResourceTiming, PerformanceEntry) NS_IMPL_RELEASE_INHERITED(PerformanceResourceTiming, PerformanceEntry) -PerformanceResourceTiming::PerformanceResourceTiming(PerformanceTiming* aPerformanceTiming, +PerformanceResourceTiming::PerformanceResourceTiming(UniquePtr&& aPerformanceTiming, Performance* aPerformance, - const nsAString& aName, - nsIHttpChannel* aChannel) -: PerformanceEntry(aPerformance->GetParentObject(), aName, NS_LITERAL_STRING("resource")), - mTiming(aPerformanceTiming), - mEncodedBodySize(0), - mTransferSize(0), - mDecodedBodySize(0) + const nsAString& aName) + : PerformanceEntry(aPerformance->GetParentObject(), aName, NS_LITERAL_STRING("resource")) + , mTimingData(Move(aPerformanceTiming)) + , mPerformance(aPerformance) { MOZ_ASSERT(aPerformance, "Parent performance object should be provided"); - SetPropertiesFromChannel(aChannel); -} - -void -PerformanceResourceTiming::SetPropertiesFromChannel(nsIHttpChannel* aChannel) -{ - if (!aChannel) { - return; - } - - nsAutoCString protocol; - Unused << aChannel->GetProtocolVersion(protocol); - SetNextHopProtocol(NS_ConvertUTF8toUTF16(protocol)); - - uint64_t encodedBodySize = 0; - Unused << aChannel->GetEncodedBodySize(&encodedBodySize); - SetEncodedBodySize(encodedBodySize); - - uint64_t transferSize = 0; - Unused << aChannel->GetTransferSize(&transferSize); - SetTransferSize(transferSize); - - uint64_t decodedBodySize = 0; - Unused << aChannel->GetDecodedBodySize(&decodedBodySize); - if (decodedBodySize == 0) { - decodedBodySize = encodedBodySize; - } - SetDecodedBodySize(decodedBodySize); } PerformanceResourceTiming::~PerformanceResourceTiming() @@ -78,13 +47,14 @@ PerformanceResourceTiming::StartTime() const // Ignore zero values. The RedirectStart and WorkerStart values // can come from earlier redirected channels prior to the AsyncOpen // time being recorded. - DOMHighResTimeStamp redirect = mTiming->RedirectStartHighRes(); + DOMHighResTimeStamp redirect = + mTimingData->RedirectStartHighRes(mPerformance); redirect = redirect ? redirect : DBL_MAX; - DOMHighResTimeStamp worker = mTiming->WorkerStartHighRes(); + DOMHighResTimeStamp worker = mTimingData->WorkerStartHighRes(mPerformance); worker = worker ? worker : DBL_MAX; - DOMHighResTimeStamp asyncOpen = mTiming->AsyncOpenHighRes(); + DOMHighResTimeStamp asyncOpen = mTimingData->AsyncOpenHighRes(mPerformance); return std::min(asyncOpen, std::min(redirect, worker)); } @@ -106,5 +76,7 @@ PerformanceResourceTiming::SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSize { return PerformanceEntry::SizeOfExcludingThis(aMallocSizeOf) + mInitiatorType.SizeOfExcludingThisIfUnshared(aMallocSizeOf) + - mNextHopProtocol.SizeOfExcludingThisIfUnshared(aMallocSizeOf); + (mTimingData + ? mTimingData->NextHopProtocol().SizeOfExcludingThisIfUnshared(aMallocSizeOf) + : 0); } diff --git a/dom/performance/PerformanceResourceTiming.h b/dom/performance/PerformanceResourceTiming.h index b768528ff97d..cb1f1b5c69cb 100644 --- a/dom/performance/PerformanceResourceTiming.h +++ b/dom/performance/PerformanceResourceTiming.h @@ -7,9 +7,8 @@ #ifndef mozilla_dom_PerformanceResourceTiming_h___ #define mozilla_dom_PerformanceResourceTiming_h___ +#include "mozilla/UniquePtr.h" #include "nsCOMPtr.h" -#include "nsIChannel.h" -#include "nsITimedChannel.h" #include "Performance.h" #include "PerformanceEntry.h" #include "PerformanceTiming.h" @@ -28,10 +27,9 @@ public: PerformanceResourceTiming, PerformanceEntry) - PerformanceResourceTiming(PerformanceTiming* aPerformanceTiming, + PerformanceResourceTiming(UniquePtr&& aPerformanceTimingData, Performance* aPerformance, - const nsAString& aName, - nsIHttpChannel* aChannel = nullptr); + const nsAString& aName); virtual JSObject* WrapObject(JSContext* aCx, JS::Handle aGivenProto) override; @@ -55,88 +53,85 @@ public: void GetNextHopProtocol(nsAString& aNextHopProtocol) const { - aNextHopProtocol = mNextHopProtocol; - } - - void SetNextHopProtocol(const nsAString& aNextHopProtocol) - { - mNextHopProtocol = aNextHopProtocol; + if (mTimingData) { + aNextHopProtocol = mTimingData->NextHopProtocol(); + } } DOMHighResTimeStamp WorkerStart() const { - return mTiming - ? mTiming->WorkerStartHighRes() + return mTimingData + ? mTimingData->WorkerStartHighRes(mPerformance) : 0; } DOMHighResTimeStamp FetchStart() const { - return mTiming - ? mTiming->FetchStartHighRes() + return mTimingData + ? mTimingData->FetchStartHighRes(mPerformance) : 0; } DOMHighResTimeStamp RedirectStart() const { // We have to check if all the redirect URIs had the same origin (since // there is no check in RedirectEndHighRes()) - return mTiming && mTiming->ShouldReportCrossOriginRedirect() - ? mTiming->RedirectStartHighRes() + return mTimingData && mTimingData->ShouldReportCrossOriginRedirect() + ? mTimingData->RedirectStartHighRes(mPerformance) : 0; } DOMHighResTimeStamp RedirectEnd() const { // We have to check if all the redirect URIs had the same origin (since // there is no check in RedirectEndHighRes()) - return mTiming && mTiming->ShouldReportCrossOriginRedirect() - ? mTiming->RedirectEndHighRes() + return mTimingData && mTimingData->ShouldReportCrossOriginRedirect() + ? mTimingData->RedirectEndHighRes(mPerformance) : 0; } DOMHighResTimeStamp DomainLookupStart() const { - return mTiming && mTiming->TimingAllowed() - ? mTiming->DomainLookupStartHighRes() + return mTimingData && mTimingData->TimingAllowed() + ? mTimingData->DomainLookupStartHighRes(mPerformance) : 0; } DOMHighResTimeStamp DomainLookupEnd() const { - return mTiming && mTiming->TimingAllowed() - ? mTiming->DomainLookupEndHighRes() + return mTimingData && mTimingData->TimingAllowed() + ? mTimingData->DomainLookupEndHighRes(mPerformance) : 0; } DOMHighResTimeStamp ConnectStart() const { - return mTiming && mTiming->TimingAllowed() - ? mTiming->ConnectStartHighRes() + return mTimingData && mTimingData->TimingAllowed() + ? mTimingData->ConnectStartHighRes(mPerformance) : 0; } DOMHighResTimeStamp ConnectEnd() const { - return mTiming && mTiming->TimingAllowed() - ? mTiming->ConnectEndHighRes() + return mTimingData && mTimingData->TimingAllowed() + ? mTimingData->ConnectEndHighRes(mPerformance) : 0; } DOMHighResTimeStamp RequestStart() const { - return mTiming && mTiming->TimingAllowed() - ? mTiming->RequestStartHighRes() + return mTimingData && mTimingData->TimingAllowed() + ? mTimingData->RequestStartHighRes(mPerformance) : 0; } DOMHighResTimeStamp ResponseStart() const { - return mTiming && mTiming->TimingAllowed() - ? mTiming->ResponseStartHighRes() + return mTimingData && mTimingData->TimingAllowed() + ? mTimingData->ResponseStartHighRes(mPerformance) : 0; } DOMHighResTimeStamp ResponseEnd() const { - return mTiming - ? mTiming->ResponseEndHighRes() + return mTimingData + ? mTimingData->ResponseEndHighRes(mPerformance) : 0; } DOMHighResTimeStamp SecureConnectionStart() const { - return mTiming && mTiming->TimingAllowed() - ? mTiming->SecureConnectionStartHighRes() + return mTimingData && mTimingData->TimingAllowed() + ? mTimingData->SecureConnectionStartHighRes(mPerformance) : 0; } @@ -147,32 +142,17 @@ public: uint64_t TransferSize() const { - return mTiming && mTiming->TimingAllowed() ? mTransferSize : 0; + return mTimingData ? mTimingData->TransferSize() : 0; } uint64_t EncodedBodySize() const { - return mTiming && mTiming->TimingAllowed() ? mEncodedBodySize : 0; + return mTimingData ? mTimingData->EncodedBodySize() : 0; } uint64_t DecodedBodySize() const { - return mTiming && mTiming->TimingAllowed() ? mDecodedBodySize : 0; - } - - void SetEncodedBodySize(uint64_t aEncodedBodySize) - { - mEncodedBodySize = aEncodedBodySize; - } - - void SetTransferSize(uint64_t aTransferSize) - { - mTransferSize = aTransferSize; - } - - void SetDecodedBodySize(uint64_t aDecodedBodySize) - { - mDecodedBodySize = aDecodedBodySize; + return mTimingData ? mTimingData->DecodedBodySize() : 0; } size_t @@ -180,17 +160,13 @@ public: protected: virtual ~PerformanceResourceTiming(); - void SetPropertiesFromChannel(nsIHttpChannel* aChannel); size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const override; nsString mInitiatorType; - nsString mNextHopProtocol; - RefPtr mTiming; - uint64_t mEncodedBodySize; - uint64_t mTransferSize; - uint64_t mDecodedBodySize; + UniquePtr mTimingData; + RefPtr mPerformance; }; } // namespace dom diff --git a/dom/performance/PerformanceTiming.cpp b/dom/performance/PerformanceTiming.cpp index 73da49a95c2a..8ecd54b4fa84 100644 --- a/dom/performance/PerformanceTiming.cpp +++ b/dom/performance/PerformanceTiming.cpp @@ -24,35 +24,49 @@ PerformanceTiming::PerformanceTiming(Performance* aPerformance, nsITimedChannel* aChannel, nsIHttpChannel* aHttpChannel, DOMHighResTimeStamp aZeroTime) - : mPerformance(aPerformance), - mFetchStart(0.0), - mZeroTime(nsRFPService::ReduceTimePrecisionAsMSecs(aZeroTime)), - mRedirectCount(0), - mTimingAllowed(true), - mAllRedirectsSameOrigin(true), - mInitialized(!!aChannel), - mReportCrossOriginRedirect(true) + : mPerformance(aPerformance) { MOZ_ASSERT(aPerformance, "Parent performance object should be provided"); + mTimingData.reset(new PerformanceTimingData(aChannel, aHttpChannel, + aZeroTime)); + + // Non-null aHttpChannel implies that this PerformanceTiming object is being + // used for subresources, which is irrelevant to this probe. + if (!aHttpChannel && + nsContentUtils::IsPerformanceTimingEnabled() && + IsTopLevelContentDocument()) { + Telemetry::Accumulate(Telemetry::TIME_TO_RESPONSE_START_MS, + mTimingData->ResponseStartHighRes(aPerformance) - + mTimingData->ZeroTime()); + } +} + +// Copy the timing info from the channel so we don't need to keep the channel +// alive just to get the timestamps. +PerformanceTimingData::PerformanceTimingData(nsITimedChannel* aChannel, + nsIHttpChannel* aHttpChannel, + DOMHighResTimeStamp aZeroTime) + : mZeroTime(0.0) + , mFetchStart(0.0) + , mEncodedBodySize(0) + , mTransferSize(0) + , mDecodedBodySize(0) + , mRedirectCount(0) + , mAllRedirectsSameOrigin(true) + , mReportCrossOriginRedirect(true) + , mSecureConnection(false) + , mTimingAllowed(true) + , mInitialized(false) +{ + mInitialized = !!aChannel; + + mZeroTime = nsRFPService::ReduceTimePrecisionAsMSecs(aZeroTime); if (!nsContentUtils::IsPerformanceTimingEnabled() || nsContentUtils::ShouldResistFingerprinting()) { mZeroTime = 0; } - // The aHttpChannel argument is null if this PerformanceTiming object is - // being used for navigation timing (which is only relevant for documents). - // It has a non-null value if this PerformanceTiming object is being used - // for resource timing, which can include document loads, both toplevel and - // in subframes, and resources linked from a document. - if (aHttpChannel) { - mTimingAllowed = CheckAllowedOrigin(aHttpChannel, aChannel); - bool redirectsPassCheck = false; - aChannel->GetAllRedirectsPassTimingAllowCheck(&redirectsPassCheck); - mReportCrossOriginRedirect = mTimingAllowed && redirectsPassCheck; - } - - mSecureConnection = false; nsCOMPtr uri; if (aHttpChannel) { aHttpChannel->GetURI(getter_AddRefs(uri)); @@ -69,23 +83,7 @@ PerformanceTiming::PerformanceTiming(Performance* aPerformance, mSecureConnection = false; } } - InitializeTimingInfo(aChannel); - // Non-null aHttpChannel implies that this PerformanceTiming object is being - // used for subresources, which is irrelevant to this probe. - if (!aHttpChannel && - nsContentUtils::IsPerformanceTimingEnabled() && - IsTopLevelContentDocument()) { - Telemetry::Accumulate(Telemetry::TIME_TO_RESPONSE_START_MS, - ResponseStartHighRes() - mZeroTime); - } -} - -// Copy the timing info from the channel so we don't need to keep the channel -// alive just to get the timestamps. -void -PerformanceTiming::InitializeTimingInfo(nsITimedChannel* aChannel) -{ if (aChannel) { aChannel->GetAsyncOpen(&mAsyncOpen); aChannel->GetAllRedirectsSameOrigin(&mAllRedirectsSameOrigin); @@ -110,11 +108,11 @@ PerformanceTiming::InitializeTimingInfo(nsITimedChannel* aChannel) aChannel->GetHandleFetchEventEnd(&mWorkerResponseEnd); // The performance timing api essentially requires that the event timestamps - // have a strict relation with each other. The truth, however, is the browser - // engages in a number of speculative activities that sometimes mean connections - // and lookups begin at different times. Workaround that here by clamping - // these values to what we expect FetchStart to be. This means the later of - // AsyncOpen or WorkerStart times. + // have a strict relation with each other. The truth, however, is the + // browser engages in a number of speculative activities that sometimes mean + // connections and lookups begin at different times. Workaround that here by + // clamping these values to what we expect FetchStart to be. This means the + // later of AsyncOpen or WorkerStart times. if (!mAsyncOpen.IsNull()) { // We want to clamp to the expected FetchStart value. This is later of // the AsyncOpen and WorkerStart values. @@ -145,6 +143,29 @@ PerformanceTiming::InitializeTimingInfo(nsITimedChannel* aChannel) } } } + + // The aHttpChannel argument is null if this PerformanceTiming object is + // being used for navigation timing (which is only relevant for documents). + // It has a non-null value if this PerformanceTiming object is being used + // for resource timing, which can include document loads, both toplevel and + // in subframes, and resources linked from a document. + if (aHttpChannel) { + mTimingAllowed = CheckAllowedOrigin(aHttpChannel, aChannel); + bool redirectsPassCheck = false; + aChannel->GetAllRedirectsPassTimingAllowCheck(&redirectsPassCheck); + mReportCrossOriginRedirect = mTimingAllowed && redirectsPassCheck; + + nsAutoCString protocol; + Unused << aHttpChannel->GetProtocolVersion(protocol); + mNextHopProtocol = NS_ConvertUTF8toUTF16(protocol); + + Unused << aHttpChannel->GetEncodedBodySize(&mEncodedBodySize); + Unused << aHttpChannel->GetTransferSize(&mTransferSize); + Unused << aHttpChannel->GetDecodedBodySize(&mDecodedBodySize); + if (mDecodedBodySize == 0) { + mDecodedBodySize = mEncodedBodySize; + } + } } PerformanceTiming::~PerformanceTiming() @@ -152,8 +173,10 @@ PerformanceTiming::~PerformanceTiming() } DOMHighResTimeStamp -PerformanceTiming::FetchStartHighRes() +PerformanceTimingData::FetchStartHighRes(Performance* aPerformance) { + MOZ_ASSERT(aPerformance); + if (!mFetchStart) { if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized() || nsContentUtils::ShouldResistFingerprinting()) { @@ -163,9 +186,9 @@ PerformanceTiming::FetchStartHighRes() "valid if the performance timing is enabled"); if (!mAsyncOpen.IsNull()) { if (!mWorkerRequestStart.IsNull() && mWorkerRequestStart > mAsyncOpen) { - mFetchStart = TimeStampToDOMHighRes(mWorkerRequestStart); + mFetchStart = TimeStampToDOMHighRes(aPerformance, mWorkerRequestStart); } else { - mFetchStart = TimeStampToDOMHighRes(mAsyncOpen); + mFetchStart = TimeStampToDOMHighRes(aPerformance, mAsyncOpen); } } } @@ -175,12 +198,12 @@ PerformanceTiming::FetchStartHighRes() DOMTimeMilliSec PerformanceTiming::FetchStart() { - return static_cast(FetchStartHighRes()); + return static_cast(mTimingData->FetchStartHighRes(mPerformance)); } bool -PerformanceTiming::CheckAllowedOrigin(nsIHttpChannel* aResourceChannel, - nsITimedChannel* aChannel) +PerformanceTimingData::CheckAllowedOrigin(nsIHttpChannel* aResourceChannel, + nsITimedChannel* aChannel) { if (!IsInitialized()) { return false; @@ -208,14 +231,8 @@ PerformanceTiming::CheckAllowedOrigin(nsIHttpChannel* aResourceChannel, return aChannel->TimingAllowCheck(principal); } -bool -PerformanceTiming::TimingAllowed() const -{ - return mTimingAllowed; -} - uint8_t -PerformanceTiming::GetRedirectCount() const +PerformanceTimingData::GetRedirectCount() const { if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized() || nsContentUtils::ShouldResistFingerprinting()) { @@ -228,7 +245,7 @@ PerformanceTiming::GetRedirectCount() const } bool -PerformanceTiming::ShouldReportCrossOriginRedirect() const +PerformanceTimingData::ShouldReportCrossOriginRedirect() const { if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized() || nsContentUtils::ShouldResistFingerprinting()) { @@ -242,23 +259,29 @@ PerformanceTiming::ShouldReportCrossOriginRedirect() const } DOMHighResTimeStamp -PerformanceTiming::AsyncOpenHighRes() +PerformanceTimingData::AsyncOpenHighRes(Performance* aPerformance) { + MOZ_ASSERT(aPerformance); + if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized() || nsContentUtils::ShouldResistFingerprinting() || mAsyncOpen.IsNull()) { return mZeroTime; } - return nsRFPService::ReduceTimePrecisionAsMSecs(TimeStampToDOMHighRes(mAsyncOpen)); + return nsRFPService::ReduceTimePrecisionAsMSecs( + TimeStampToDOMHighRes(aPerformance, mAsyncOpen)); } DOMHighResTimeStamp -PerformanceTiming::WorkerStartHighRes() +PerformanceTimingData::WorkerStartHighRes(Performance* aPerformance) { + MOZ_ASSERT(aPerformance); + if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized() || nsContentUtils::ShouldResistFingerprinting() || mWorkerStart.IsNull()) { return mZeroTime; } - return nsRFPService::ReduceTimePrecisionAsMSecs(TimeStampToDOMHighRes(mWorkerStart)); + return nsRFPService::ReduceTimePrecisionAsMSecs( + TimeStampToDOMHighRes(aPerformance, mWorkerStart)); } /** @@ -272,25 +295,28 @@ PerformanceTiming::WorkerStartHighRes() * @return a valid timing if the Performance Timing is enabled */ DOMHighResTimeStamp -PerformanceTiming::RedirectStartHighRes() +PerformanceTimingData::RedirectStartHighRes(Performance* aPerformance) { + MOZ_ASSERT(aPerformance); + if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized() || nsContentUtils::ShouldResistFingerprinting()) { return mZeroTime; } - return TimeStampToReducedDOMHighResOrFetchStart(mRedirectStart); + return TimeStampToReducedDOMHighResOrFetchStart(aPerformance, mRedirectStart); } DOMTimeMilliSec PerformanceTiming::RedirectStart() { - if (!IsInitialized()) { + if (!mTimingData->IsInitialized()) { return 0; } // We have to check if all the redirect URIs had the same origin (since there // is no check in RedirectStartHighRes()) - if (mAllRedirectsSameOrigin && mRedirectCount) { - return static_cast(RedirectStartHighRes()); + if (mTimingData->AllRedirectsSameOrigin() && + mTimingData->RedirectCountReal()) { + return static_cast(mTimingData->RedirectStartHighRes(mPerformance)); } return 0; } @@ -306,85 +332,99 @@ PerformanceTiming::RedirectStart() * @return a valid timing if the Performance Timing is enabled */ DOMHighResTimeStamp -PerformanceTiming::RedirectEndHighRes() +PerformanceTimingData::RedirectEndHighRes(Performance* aPerformance) { + MOZ_ASSERT(aPerformance); + if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized() || nsContentUtils::ShouldResistFingerprinting()) { return mZeroTime; } - return TimeStampToReducedDOMHighResOrFetchStart(mRedirectEnd); + return TimeStampToReducedDOMHighResOrFetchStart(aPerformance, mRedirectEnd); } DOMTimeMilliSec PerformanceTiming::RedirectEnd() { - if (!IsInitialized()) { + if (!mTimingData->IsInitialized()) { return 0; } // We have to check if all the redirect URIs had the same origin (since there // is no check in RedirectEndHighRes()) - if (mAllRedirectsSameOrigin && mRedirectCount) { - return static_cast(RedirectEndHighRes()); + if (mTimingData->AllRedirectsSameOrigin() && + mTimingData->RedirectCountReal()) { + return static_cast(mTimingData->RedirectEndHighRes(mPerformance)); } return 0; } DOMHighResTimeStamp -PerformanceTiming::DomainLookupStartHighRes() +PerformanceTimingData::DomainLookupStartHighRes(Performance* aPerformance) { + MOZ_ASSERT(aPerformance); + if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized() || nsContentUtils::ShouldResistFingerprinting()) { return mZeroTime; } - return TimeStampToReducedDOMHighResOrFetchStart(mDomainLookupStart); + return TimeStampToReducedDOMHighResOrFetchStart(aPerformance, + mDomainLookupStart); } DOMTimeMilliSec PerformanceTiming::DomainLookupStart() { - return static_cast(DomainLookupStartHighRes()); + return static_cast(mTimingData->DomainLookupStartHighRes(mPerformance)); } DOMHighResTimeStamp -PerformanceTiming::DomainLookupEndHighRes() +PerformanceTimingData::DomainLookupEndHighRes(Performance* aPerformance) { + MOZ_ASSERT(aPerformance); + if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized() || nsContentUtils::ShouldResistFingerprinting()) { return mZeroTime; } // Bug 1155008 - nsHttpTransaction is racy. Return DomainLookupStart when null - return mDomainLookupEnd.IsNull() ? DomainLookupStartHighRes() - : nsRFPService::ReduceTimePrecisionAsMSecs( - TimeStampToDOMHighRes(mDomainLookupEnd)); + return mDomainLookupEnd.IsNull() + ? DomainLookupStartHighRes(aPerformance) + : nsRFPService::ReduceTimePrecisionAsMSecs( + TimeStampToDOMHighRes(aPerformance, mDomainLookupEnd)); } DOMTimeMilliSec PerformanceTiming::DomainLookupEnd() { - return static_cast(DomainLookupEndHighRes()); + return static_cast(mTimingData->DomainLookupEndHighRes(mPerformance)); } DOMHighResTimeStamp -PerformanceTiming::ConnectStartHighRes() +PerformanceTimingData::ConnectStartHighRes(Performance* aPerformance) { + MOZ_ASSERT(aPerformance); + if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized() || nsContentUtils::ShouldResistFingerprinting()) { return mZeroTime; } - return mConnectStart.IsNull() ? DomainLookupEndHighRes() - : nsRFPService::ReduceTimePrecisionAsMSecs( - TimeStampToDOMHighRes(mConnectStart)); + return mConnectStart.IsNull() + ? DomainLookupEndHighRes(aPerformance) + : nsRFPService::ReduceTimePrecisionAsMSecs( + TimeStampToDOMHighRes(aPerformance, mConnectStart)); } DOMTimeMilliSec PerformanceTiming::ConnectStart() { - return static_cast(ConnectStartHighRes()); + return static_cast(mTimingData->ConnectStartHighRes(mPerformance)); } DOMHighResTimeStamp -PerformanceTiming::SecureConnectionStartHighRes() +PerformanceTimingData::SecureConnectionStartHighRes(Performance* aPerformance) { + MOZ_ASSERT(aPerformance); + if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized() || nsContentUtils::ShouldResistFingerprinting()) { return mZeroTime; @@ -392,39 +432,45 @@ PerformanceTiming::SecureConnectionStartHighRes() return !mSecureConnection ? 0 // We use 0 here, because mZeroTime is sometimes set to the navigation // start time. - : (mSecureConnectionStart.IsNull() ? mZeroTime - : nsRFPService::ReduceTimePrecisionAsMSecs( - TimeStampToDOMHighRes(mSecureConnectionStart))); + : (mSecureConnectionStart.IsNull() + ? mZeroTime + : nsRFPService::ReduceTimePrecisionAsMSecs( + TimeStampToDOMHighRes(aPerformance, mSecureConnectionStart))); } DOMTimeMilliSec PerformanceTiming::SecureConnectionStart() { - return static_cast(SecureConnectionStartHighRes()); + return static_cast(mTimingData->SecureConnectionStartHighRes(mPerformance)); } DOMHighResTimeStamp -PerformanceTiming::ConnectEndHighRes() +PerformanceTimingData::ConnectEndHighRes(Performance* aPerformance) { + MOZ_ASSERT(aPerformance); + if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized() || nsContentUtils::ShouldResistFingerprinting()) { return mZeroTime; } // Bug 1155008 - nsHttpTransaction is racy. Return ConnectStart when null - return mConnectEnd.IsNull() ? ConnectStartHighRes() - : nsRFPService::ReduceTimePrecisionAsMSecs( - TimeStampToDOMHighRes(mConnectEnd)); + return mConnectEnd.IsNull() + ? ConnectStartHighRes(aPerformance) + : nsRFPService::ReduceTimePrecisionAsMSecs( + TimeStampToDOMHighRes(aPerformance, mConnectEnd)); } DOMTimeMilliSec PerformanceTiming::ConnectEnd() { - return static_cast(ConnectEndHighRes()); + return static_cast(mTimingData->ConnectEndHighRes(mPerformance)); } DOMHighResTimeStamp -PerformanceTiming::RequestStartHighRes() +PerformanceTimingData::RequestStartHighRes(Performance* aPerformance) { + MOZ_ASSERT(aPerformance); + if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized() || nsContentUtils::ShouldResistFingerprinting()) { return mZeroTime; @@ -434,18 +480,20 @@ PerformanceTiming::RequestStartHighRes() mRequestStart = mWorkerRequestStart; } - return TimeStampToReducedDOMHighResOrFetchStart(mRequestStart); + return TimeStampToReducedDOMHighResOrFetchStart(aPerformance, mRequestStart); } DOMTimeMilliSec PerformanceTiming::RequestStart() { - return static_cast(RequestStartHighRes()); + return static_cast(mTimingData->RequestStartHighRes(mPerformance)); } DOMHighResTimeStamp -PerformanceTiming::ResponseStartHighRes() +PerformanceTimingData::ResponseStartHighRes(Performance* aPerformance) { + MOZ_ASSERT(aPerformance); + if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized() || nsContentUtils::ShouldResistFingerprinting()) { return mZeroTime; @@ -459,18 +507,20 @@ PerformanceTiming::ResponseStartHighRes() (!mRequestStart.IsNull() && mResponseStart < mRequestStart)) { mResponseStart = mRequestStart; } - return TimeStampToReducedDOMHighResOrFetchStart(mResponseStart); + return TimeStampToReducedDOMHighResOrFetchStart(aPerformance, mResponseStart); } DOMTimeMilliSec PerformanceTiming::ResponseStart() { - return static_cast(ResponseStartHighRes()); + return static_cast(mTimingData->ResponseStartHighRes(mPerformance)); } DOMHighResTimeStamp -PerformanceTiming::ResponseEndHighRes() +PerformanceTimingData::ResponseEndHighRes(Performance* aPerformance) { + MOZ_ASSERT(aPerformance); + if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized() || nsContentUtils::ShouldResistFingerprinting()) { return mZeroTime; @@ -483,21 +533,16 @@ PerformanceTiming::ResponseEndHighRes() mResponseEnd = mWorkerResponseEnd; } // Bug 1155008 - nsHttpTransaction is racy. Return ResponseStart when null - return mResponseEnd.IsNull() ? ResponseStartHighRes() - : nsRFPService::ReduceTimePrecisionAsMSecs( - TimeStampToDOMHighRes(mResponseEnd)); + return mResponseEnd.IsNull() + ? ResponseStartHighRes(aPerformance) + : nsRFPService::ReduceTimePrecisionAsMSecs( + TimeStampToDOMHighRes(aPerformance, mResponseEnd)); } DOMTimeMilliSec PerformanceTiming::ResponseEnd() { - return static_cast(ResponseEndHighRes()); -} - -bool -PerformanceTiming::IsInitialized() const -{ - return mInitialized; + return static_cast(mTimingData->ResponseEndHighRes(mPerformance)); } JSObject* diff --git a/dom/performance/PerformanceTiming.h b/dom/performance/PerformanceTiming.h index 2f449171453b..8ab305cf8389 100644 --- a/dom/performance/PerformanceTiming.h +++ b/dom/performance/PerformanceTiming.h @@ -20,6 +20,190 @@ class nsITimedChannel; namespace mozilla { namespace dom { +class PerformanceTimingData final +{ +public: + PerformanceTimingData(nsITimedChannel* aChannel, + nsIHttpChannel* aHttpChannel, + DOMHighResTimeStamp aZeroTime); + + bool IsInitialized() const + { + return mInitialized; + } + + const nsString& NextHopProtocol() const + { + return mNextHopProtocol; + } + + uint64_t TransferSize() const + { + return mTimingAllowed ? mTransferSize : 0; + } + + uint64_t EncodedBodySize() const + { + return mTimingAllowed ? mEncodedBodySize : 0; + } + + uint64_t DecodedBodySize() const + { + return mTimingAllowed ? mDecodedBodySize : 0; + } + + /** + * @param aStamp + * The TimeStamp recorded for a specific event. This TimeStamp can + * be null. + * @return the duration of an event with a given TimeStamp, relative to the + * navigationStart TimeStamp (the moment the user landed on the + * page), if the given TimeStamp is valid. Otherwise, it will return + * the FetchStart timing value. + */ + inline DOMHighResTimeStamp + TimeStampToReducedDOMHighResOrFetchStart(Performance* aPerformance, + TimeStamp aStamp) + { + MOZ_ASSERT(aPerformance); + + return (!aStamp.IsNull()) + ? nsRFPService::ReduceTimePrecisionAsMSecs( + TimeStampToDOMHighRes(aPerformance, aStamp)) + : FetchStartHighRes(aPerformance); + } + + /** + * The nsITimedChannel records an absolute timestamp for each event. + * The nsDOMNavigationTiming will record the moment when the user landed on + * the page. This is a window.performance unique timestamp, so it can be used + * for all the events (navigation timing and resource timing events). + * + * The algorithm operates in 2 steps: + * 1. The first step is to subtract the two timestamps: the argument (the + * event's timestamp) and the navigation start timestamp. This will result in + * a relative timestamp of the event (relative to the navigation start - + * window.performance.timing.navigationStart). + * 2. The second step is to add any required offset (the mZeroTime). For now, + * this offset value is either 0 (for the resource timing), or equal to + * "performance.navigationStart" (for navigation timing). + * For the resource timing, mZeroTime is set to 0, causing the result to be a + * relative time. + * For the navigation timing, mZeroTime is set to "performance.navigationStart" + * causing the result be an absolute time. + * + * @param aStamp + * The TimeStamp recorded for a specific event. This TimeStamp can't + * be null. + * @return number of milliseconds value as one of: + * - relative to the navigation start time, time the user has landed on the + * page + * - an absolute wall clock time since the unix epoch + */ + inline DOMHighResTimeStamp + TimeStampToDOMHighRes(Performance* aPerformance, TimeStamp aStamp) const + { + MOZ_ASSERT(aPerformance); + MOZ_ASSERT(!aStamp.IsNull()); + + TimeDuration duration = + aStamp - aPerformance->GetDOMTiming()->GetNavigationStartTimeStamp(); + return duration.ToMilliseconds() + mZeroTime; + } + + // The last channel's AsyncOpen time. This may occur before the FetchStart + // in some cases. + DOMHighResTimeStamp AsyncOpenHighRes(Performance* aPerformance); + + // High resolution (used by resource timing) + DOMHighResTimeStamp WorkerStartHighRes(Performance* aPerformance); + DOMHighResTimeStamp FetchStartHighRes(Performance* aPerformance); + DOMHighResTimeStamp RedirectStartHighRes(Performance* aPerformance); + DOMHighResTimeStamp RedirectEndHighRes(Performance* aPerformance); + DOMHighResTimeStamp DomainLookupStartHighRes(Performance* aPerformance); + DOMHighResTimeStamp DomainLookupEndHighRes(Performance* aPerformance); + DOMHighResTimeStamp ConnectStartHighRes(Performance* aPerformance); + DOMHighResTimeStamp SecureConnectionStartHighRes(Performance* aPerformance); + DOMHighResTimeStamp ConnectEndHighRes(Performance* aPerformance); + DOMHighResTimeStamp RequestStartHighRes(Performance* aPerformance); + DOMHighResTimeStamp ResponseStartHighRes(Performance* aPerformance); + DOMHighResTimeStamp ResponseEndHighRes(Performance* aPerformance); + + DOMHighResTimeStamp ZeroTime() const { return mZeroTime; } + + uint8_t RedirectCountReal() const { return mRedirectCount; } + uint8_t GetRedirectCount() const; + + bool AllRedirectsSameOrigin() const { return mAllRedirectsSameOrigin; } + + // If this is false the values of redirectStart/End will be 0 This is false if + // no redirects occured, or if any of the responses failed the + // timing-allow-origin check in HttpBaseChannel::TimingAllowCheck + bool ShouldReportCrossOriginRedirect() const; + + // Cached result of CheckAllowedOrigin. If false, security sensitive + // attributes of the resourceTiming object will be set to 0 + bool TimingAllowed() const + { + return mTimingAllowed; + } + +private: + // Checks if the resource is either same origin as the page that started + // the load, or if the response contains the Timing-Allow-Origin header + // with a value of * or matching the domain of the loading Principal + bool CheckAllowedOrigin(nsIHttpChannel* aResourceChannel, + nsITimedChannel* aChannel); + + nsString mNextHopProtocol; + + TimeStamp mAsyncOpen; + TimeStamp mRedirectStart; + TimeStamp mRedirectEnd; + TimeStamp mDomainLookupStart; + TimeStamp mDomainLookupEnd; + TimeStamp mConnectStart; + TimeStamp mSecureConnectionStart; + TimeStamp mConnectEnd; + TimeStamp mRequestStart; + TimeStamp mResponseStart; + TimeStamp mCacheReadStart; + TimeStamp mResponseEnd; + TimeStamp mCacheReadEnd; + + // ServiceWorker interception timing information + TimeStamp mWorkerStart; + TimeStamp mWorkerRequestStart; + TimeStamp mWorkerResponseEnd; + + // This is an offset that will be added to each timing ([ms] resolution). + // There are only 2 possible values: (1) logicaly equal to navigationStart + // TimeStamp (results are absolute timstamps - wallclock); (2) "0" (results + // are relative to the navigation start). + DOMHighResTimeStamp mZeroTime; + + DOMHighResTimeStamp mFetchStart; + + uint64_t mEncodedBodySize; + uint64_t mTransferSize; + uint64_t mDecodedBodySize; + + uint8_t mRedirectCount; + + bool mAllRedirectsSameOrigin; + + // If the resourceTiming object should have non-zero redirectStart and + // redirectEnd attributes. It is false if there were no redirects, or if any + // of the responses didn't pass the timing-allow-check + bool mReportCrossOriginRedirect; + + bool mSecureConnection; + + bool mTimingAllowed; + + bool mInitialized; +}; + // Script "performance.timing" object class PerformanceTiming final : public nsWrapperCache { @@ -60,57 +244,6 @@ public: return mPerformance; } - /** - * @param aStamp - * The TimeStamp recorded for a specific event. This TimeStamp can - * be null. - * @return the duration of an event with a given TimeStamp, relative to the - * navigationStart TimeStamp (the moment the user landed on the - * page), if the given TimeStamp is valid. Otherwise, it will return - * the FetchStart timing value. - */ - inline DOMHighResTimeStamp TimeStampToReducedDOMHighResOrFetchStart(TimeStamp aStamp) - { - return (!aStamp.IsNull()) - ? nsRFPService::ReduceTimePrecisionAsMSecs(TimeStampToDOMHighRes(aStamp)) - : FetchStartHighRes(); - } - - /** - * The nsITimedChannel records an absolute timestamp for each event. - * The nsDOMNavigationTiming will record the moment when the user landed on - * the page. This is a window.performance unique timestamp, so it can be used - * for all the events (navigation timing and resource timing events). - * - * The algorithm operates in 2 steps: - * 1. The first step is to subtract the two timestamps: the argument (the - * envet's timesramp) and the navigation start timestamp. This will result in - * a relative timestamp of the event (relative to the navigation start - - * window.performance.timing.navigationStart). - * 2. The second step is to add any required offset (the mZeroTime). For now, - * this offset value is either 0 (for the resource timing), or equal to - * "performance.navigationStart" (for navigation timing). - * For the resource timing, mZeroTime is set to 0, causing the result to be a - * relative time. - * For the navigation timing, mZeroTime is set to "performance.navigationStart" - * causing the result be an absolute time. - * - * @param aStamp - * The TimeStamp recorded for a specific event. This TimeStamp can't - * be null. - * @return number of milliseconds value as one of: - * - relative to the navigation start time, time the user has landed on the - * page - * - an absolute wall clock time since the unix epoch - */ - inline DOMHighResTimeStamp TimeStampToDOMHighRes(TimeStamp aStamp) const - { - MOZ_ASSERT(!aStamp.IsNull()); - TimeDuration duration = - aStamp - GetDOMTiming()->GetNavigationStartTimeStamp(); - return duration.ToMilliseconds() + mZeroTime; - } - virtual JSObject* WrapObject(JSContext *cx, JS::Handle aGivenProto) override; @@ -145,40 +278,6 @@ public: GetDOMTiming()->GetUnloadEventEnd()); } - uint8_t GetRedirectCount() const; - - // Checks if the resource is either same origin as the page that started - // the load, or if the response contains the Timing-Allow-Origin header - // with a value of * or matching the domain of the loading Principal - bool CheckAllowedOrigin(nsIHttpChannel* aResourceChannel, nsITimedChannel* aChannel); - - // Cached result of CheckAllowedOrigin. If false, security sensitive - // attributes of the resourceTiming object will be set to 0 - bool TimingAllowed() const; - - // If this is false the values of redirectStart/End will be 0 - // This is false if no redirects occured, or if any of the responses failed - // the timing-allow-origin check in HttpBaseChannel::TimingAllowCheck - bool ShouldReportCrossOriginRedirect() const; - - // The last channel's AsyncOpen time. This may occur before the FetchStart - // in some cases. - DOMHighResTimeStamp AsyncOpenHighRes(); - - // High resolution (used by resource timing) - DOMHighResTimeStamp WorkerStartHighRes(); - DOMHighResTimeStamp FetchStartHighRes(); - DOMHighResTimeStamp RedirectStartHighRes(); - DOMHighResTimeStamp RedirectEndHighRes(); - DOMHighResTimeStamp DomainLookupStartHighRes(); - DOMHighResTimeStamp DomainLookupEndHighRes(); - DOMHighResTimeStamp ConnectStartHighRes(); - DOMHighResTimeStamp SecureConnectionStartHighRes(); - DOMHighResTimeStamp ConnectEndHighRes(); - DOMHighResTimeStamp RequestStartHighRes(); - DOMHighResTimeStamp ResponseStartHighRes(); - DOMHighResTimeStamp ResponseEndHighRes(); - // Low resolution (used by navigation timing) DOMTimeMilliSec FetchStart(); DOMTimeMilliSec RedirectStart(); @@ -272,53 +371,19 @@ public: GetDOMTiming()->GetTimeToNonBlankPaint()); } + PerformanceTimingData* Data() const + { + return mTimingData.get(); + } + private: ~PerformanceTiming(); - bool IsInitialized() const; - void InitializeTimingInfo(nsITimedChannel* aChannel); - bool IsTopLevelContentDocument() const; RefPtr mPerformance; - DOMHighResTimeStamp mFetchStart; - // This is an offset that will be added to each timing ([ms] resolution). - // There are only 2 possible values: (1) logicaly equal to navigationStart - // TimeStamp (results are absolute timstamps - wallclock); (2) "0" (results - // are relative to the navigation start). - DOMHighResTimeStamp mZeroTime; - - TimeStamp mAsyncOpen; - TimeStamp mRedirectStart; - TimeStamp mRedirectEnd; - TimeStamp mDomainLookupStart; - TimeStamp mDomainLookupEnd; - TimeStamp mConnectStart; - TimeStamp mSecureConnectionStart; - TimeStamp mConnectEnd; - TimeStamp mRequestStart; - TimeStamp mResponseStart; - TimeStamp mCacheReadStart; - TimeStamp mResponseEnd; - TimeStamp mCacheReadEnd; - - // ServiceWorker interception timing information - TimeStamp mWorkerStart; - TimeStamp mWorkerRequestStart; - TimeStamp mWorkerResponseEnd; - - uint8_t mRedirectCount; - bool mTimingAllowed; - bool mAllRedirectsSameOrigin; - bool mInitialized; - - // If the resourceTiming object should have non-zero redirectStart and - // redirectEnd attributes. It is false if there were no redirects, or if - // any of the responses didn't pass the timing-allow-check - bool mReportCrossOriginRedirect; - - bool mSecureConnection; + UniquePtr mTimingData; }; } // namespace dom