Bug 1425458 - Resource timing entries Workers - part 2 - PerformanceTimingData, r=smaug

This commit is contained in:
Andrea Marchesini
2018-01-24 17:17:31 +01:00
parent f676942138
commit 73da7daec1
8 changed files with 415 additions and 359 deletions

View File

@@ -159,14 +159,14 @@ PerformanceMainThread::AddEntry(nsIHttpChannel* channel,
// The last argument is the "zero time" (offset). Since we don't want // 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 // any offset for the resource timing, this will be set to "0" - the
// resource timing returns a relative timing (no offset). // resource timing returns a relative timing (no offset).
RefPtr<PerformanceTiming> performanceTiming = UniquePtr<PerformanceTimingData> performanceTimingData(
new PerformanceTiming(this, timedChannel, channel, new PerformanceTimingData(timedChannel, channel, 0));
0);
// The PerformanceResourceTiming object will use the PerformanceTiming // The PerformanceResourceTiming object will use the PerformanceTiming
// object to get all the required timings. // object to get all the required timings.
RefPtr<PerformanceResourceTiming> performanceEntry = RefPtr<PerformanceResourceTiming> 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 // If the initiator type had no valid value, then set it to the default
// ("other") value. // ("other") value.
@@ -326,10 +326,9 @@ PerformanceMainThread::EnsureDocEntry()
{ {
if (!mDocEntry && nsContentUtils::IsPerformanceNavigationTimingEnabled()) { if (!mDocEntry && nsContentUtils::IsPerformanceNavigationTimingEnabled()) {
nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(mChannel); nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(mChannel);
RefPtr<PerformanceTiming> timing = UniquePtr<PerformanceTimingData> timing(
new PerformanceTiming(this, mChannel, nullptr, 0); new PerformanceTimingData(mChannel, nullptr, 0));
mDocEntry = new PerformanceNavigationTiming(timing, this, mDocEntry = new PerformanceNavigationTiming(Move(timing), this);
httpChannel);
} }
} }

View File

@@ -36,7 +36,7 @@ PerformanceNavigation::WrapObject(JSContext *cx,
uint16_t uint16_t
PerformanceNavigation::RedirectCount() const PerformanceNavigation::RedirectCount() const
{ {
return GetPerformanceTiming()->GetRedirectCount(); return GetPerformanceTiming()->Data()->GetRedirectCount();
} }
} // dom namespace } // dom namespace

View File

@@ -24,55 +24,55 @@ PerformanceNavigationTiming::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aG
DOMHighResTimeStamp DOMHighResTimeStamp
PerformanceNavigationTiming::UnloadEventStart() const PerformanceNavigationTiming::UnloadEventStart() const
{ {
return mTiming->GetDOMTiming()->GetUnloadEventStartHighRes(); return mPerformance->GetDOMTiming()->GetUnloadEventStartHighRes();
} }
DOMHighResTimeStamp DOMHighResTimeStamp
PerformanceNavigationTiming::UnloadEventEnd() const PerformanceNavigationTiming::UnloadEventEnd() const
{ {
return mTiming->GetDOMTiming()->GetUnloadEventEndHighRes(); return mPerformance->GetDOMTiming()->GetUnloadEventEndHighRes();
} }
DOMHighResTimeStamp DOMHighResTimeStamp
PerformanceNavigationTiming::DomInteractive() const PerformanceNavigationTiming::DomInteractive() const
{ {
return mTiming->GetDOMTiming()->GetDomInteractiveHighRes(); return mPerformance->GetDOMTiming()->GetDomInteractiveHighRes();
} }
DOMHighResTimeStamp DOMHighResTimeStamp
PerformanceNavigationTiming::DomContentLoadedEventStart() const PerformanceNavigationTiming::DomContentLoadedEventStart() const
{ {
return mTiming->GetDOMTiming()->GetDomContentLoadedEventStartHighRes(); return mPerformance->GetDOMTiming()->GetDomContentLoadedEventStartHighRes();
} }
DOMHighResTimeStamp DOMHighResTimeStamp
PerformanceNavigationTiming::DomContentLoadedEventEnd() const PerformanceNavigationTiming::DomContentLoadedEventEnd() const
{ {
return mTiming->GetDOMTiming()->GetDomContentLoadedEventEndHighRes(); return mPerformance->GetDOMTiming()->GetDomContentLoadedEventEndHighRes();
} }
DOMHighResTimeStamp DOMHighResTimeStamp
PerformanceNavigationTiming::DomComplete() const PerformanceNavigationTiming::DomComplete() const
{ {
return mTiming->GetDOMTiming()->GetDomCompleteHighRes(); return mPerformance->GetDOMTiming()->GetDomCompleteHighRes();
} }
DOMHighResTimeStamp DOMHighResTimeStamp
PerformanceNavigationTiming::LoadEventStart() const PerformanceNavigationTiming::LoadEventStart() const
{ {
return mTiming->GetDOMTiming()->GetLoadEventStartHighRes(); return mPerformance->GetDOMTiming()->GetLoadEventStartHighRes();
} }
DOMHighResTimeStamp DOMHighResTimeStamp
PerformanceNavigationTiming::LoadEventEnd() const PerformanceNavigationTiming::LoadEventEnd() const
{ {
return mTiming->GetDOMTiming()->GetLoadEventEndHighRes(); return mPerformance->GetDOMTiming()->GetLoadEventEndHighRes();
} }
NavigationType NavigationType
PerformanceNavigationTiming::Type() const PerformanceNavigationTiming::Type() const
{ {
switch(mTiming->GetDOMTiming()->GetType()) { switch(mPerformance->GetDOMTiming()->GetType()) {
case nsDOMNavigationTiming::TYPE_NAVIGATE: case nsDOMNavigationTiming::TYPE_NAVIGATE:
return NavigationType::Navigate; return NavigationType::Navigate;
break; break;
@@ -92,5 +92,5 @@ PerformanceNavigationTiming::Type() const
uint16_t uint16_t
PerformanceNavigationTiming::RedirectCount() const PerformanceNavigationTiming::RedirectCount() const
{ {
return mTiming->GetRedirectCount(); return mTimingData->GetRedirectCount();
} }

View File

@@ -29,11 +29,10 @@ public:
// so that timestamps are relative to startTime, as opposed to the // so that timestamps are relative to startTime, as opposed to the
// performance.timing object for which timestamps are absolute and has a // performance.timing object for which timestamps are absolute and has a
// zeroTime initialized to navigationStart // zeroTime initialized to navigationStart
explicit PerformanceNavigationTiming(PerformanceTiming* aPerformanceTiming, PerformanceNavigationTiming(UniquePtr<PerformanceTimingData>&& aPerformanceTiming,
Performance* aPerformance, Performance* aPerformance)
nsIHttpChannel* aChannel) : PerformanceResourceTiming(Move(aPerformanceTiming), aPerformance,
: PerformanceResourceTiming(aPerformanceTiming, aPerformance, NS_LITERAL_STRING("document")) {
NS_LITERAL_STRING("document"), aChannel) {
SetEntryType(NS_LITERAL_STRING("navigation")); SetEntryType(NS_LITERAL_STRING("navigation"));
SetInitiatorType(NS_LITERAL_STRING("navigation")); SetInitiatorType(NS_LITERAL_STRING("navigation"));
} }

View File

@@ -11,7 +11,7 @@ using namespace mozilla::dom;
NS_IMPL_CYCLE_COLLECTION_INHERITED(PerformanceResourceTiming, NS_IMPL_CYCLE_COLLECTION_INHERITED(PerformanceResourceTiming,
PerformanceEntry, PerformanceEntry,
mTiming) mPerformance)
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(PerformanceResourceTiming, NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(PerformanceResourceTiming,
PerformanceEntry) PerformanceEntry)
@@ -23,45 +23,14 @@ NS_INTERFACE_MAP_END_INHERITING(PerformanceEntry)
NS_IMPL_ADDREF_INHERITED(PerformanceResourceTiming, PerformanceEntry) NS_IMPL_ADDREF_INHERITED(PerformanceResourceTiming, PerformanceEntry)
NS_IMPL_RELEASE_INHERITED(PerformanceResourceTiming, PerformanceEntry) NS_IMPL_RELEASE_INHERITED(PerformanceResourceTiming, PerformanceEntry)
PerformanceResourceTiming::PerformanceResourceTiming(PerformanceTiming* aPerformanceTiming, PerformanceResourceTiming::PerformanceResourceTiming(UniquePtr<PerformanceTimingData>&& aPerformanceTiming,
Performance* aPerformance, Performance* aPerformance,
const nsAString& aName, const nsAString& aName)
nsIHttpChannel* aChannel) : PerformanceEntry(aPerformance->GetParentObject(), aName, NS_LITERAL_STRING("resource"))
: PerformanceEntry(aPerformance->GetParentObject(), aName, NS_LITERAL_STRING("resource")), , mTimingData(Move(aPerformanceTiming))
mTiming(aPerformanceTiming), , mPerformance(aPerformance)
mEncodedBodySize(0),
mTransferSize(0),
mDecodedBodySize(0)
{ {
MOZ_ASSERT(aPerformance, "Parent performance object should be provided"); 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() PerformanceResourceTiming::~PerformanceResourceTiming()
@@ -78,13 +47,14 @@ PerformanceResourceTiming::StartTime() const
// Ignore zero values. The RedirectStart and WorkerStart values // Ignore zero values. The RedirectStart and WorkerStart values
// can come from earlier redirected channels prior to the AsyncOpen // can come from earlier redirected channels prior to the AsyncOpen
// time being recorded. // time being recorded.
DOMHighResTimeStamp redirect = mTiming->RedirectStartHighRes(); DOMHighResTimeStamp redirect =
mTimingData->RedirectStartHighRes(mPerformance);
redirect = redirect ? redirect : DBL_MAX; redirect = redirect ? redirect : DBL_MAX;
DOMHighResTimeStamp worker = mTiming->WorkerStartHighRes(); DOMHighResTimeStamp worker = mTimingData->WorkerStartHighRes(mPerformance);
worker = worker ? worker : DBL_MAX; worker = worker ? worker : DBL_MAX;
DOMHighResTimeStamp asyncOpen = mTiming->AsyncOpenHighRes(); DOMHighResTimeStamp asyncOpen = mTimingData->AsyncOpenHighRes(mPerformance);
return std::min(asyncOpen, std::min(redirect, worker)); return std::min(asyncOpen, std::min(redirect, worker));
} }
@@ -106,5 +76,7 @@ PerformanceResourceTiming::SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSize
{ {
return PerformanceEntry::SizeOfExcludingThis(aMallocSizeOf) + return PerformanceEntry::SizeOfExcludingThis(aMallocSizeOf) +
mInitiatorType.SizeOfExcludingThisIfUnshared(aMallocSizeOf) + mInitiatorType.SizeOfExcludingThisIfUnshared(aMallocSizeOf) +
mNextHopProtocol.SizeOfExcludingThisIfUnshared(aMallocSizeOf); (mTimingData
? mTimingData->NextHopProtocol().SizeOfExcludingThisIfUnshared(aMallocSizeOf)
: 0);
} }

View File

@@ -7,9 +7,8 @@
#ifndef mozilla_dom_PerformanceResourceTiming_h___ #ifndef mozilla_dom_PerformanceResourceTiming_h___
#define mozilla_dom_PerformanceResourceTiming_h___ #define mozilla_dom_PerformanceResourceTiming_h___
#include "mozilla/UniquePtr.h"
#include "nsCOMPtr.h" #include "nsCOMPtr.h"
#include "nsIChannel.h"
#include "nsITimedChannel.h"
#include "Performance.h" #include "Performance.h"
#include "PerformanceEntry.h" #include "PerformanceEntry.h"
#include "PerformanceTiming.h" #include "PerformanceTiming.h"
@@ -28,10 +27,9 @@ public:
PerformanceResourceTiming, PerformanceResourceTiming,
PerformanceEntry) PerformanceEntry)
PerformanceResourceTiming(PerformanceTiming* aPerformanceTiming, PerformanceResourceTiming(UniquePtr<PerformanceTimingData>&& aPerformanceTimingData,
Performance* aPerformance, Performance* aPerformance,
const nsAString& aName, const nsAString& aName);
nsIHttpChannel* aChannel = nullptr);
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override; virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
@@ -55,88 +53,85 @@ public:
void GetNextHopProtocol(nsAString& aNextHopProtocol) const void GetNextHopProtocol(nsAString& aNextHopProtocol) const
{ {
aNextHopProtocol = mNextHopProtocol; if (mTimingData) {
} aNextHopProtocol = mTimingData->NextHopProtocol();
}
void SetNextHopProtocol(const nsAString& aNextHopProtocol)
{
mNextHopProtocol = aNextHopProtocol;
} }
DOMHighResTimeStamp WorkerStart() const { DOMHighResTimeStamp WorkerStart() const {
return mTiming return mTimingData
? mTiming->WorkerStartHighRes() ? mTimingData->WorkerStartHighRes(mPerformance)
: 0; : 0;
} }
DOMHighResTimeStamp FetchStart() const { DOMHighResTimeStamp FetchStart() const {
return mTiming return mTimingData
? mTiming->FetchStartHighRes() ? mTimingData->FetchStartHighRes(mPerformance)
: 0; : 0;
} }
DOMHighResTimeStamp RedirectStart() const { DOMHighResTimeStamp RedirectStart() const {
// We have to check if all the redirect URIs had the same origin (since // We have to check if all the redirect URIs had the same origin (since
// there is no check in RedirectEndHighRes()) // there is no check in RedirectEndHighRes())
return mTiming && mTiming->ShouldReportCrossOriginRedirect() return mTimingData && mTimingData->ShouldReportCrossOriginRedirect()
? mTiming->RedirectStartHighRes() ? mTimingData->RedirectStartHighRes(mPerformance)
: 0; : 0;
} }
DOMHighResTimeStamp RedirectEnd() const { DOMHighResTimeStamp RedirectEnd() const {
// We have to check if all the redirect URIs had the same origin (since // We have to check if all the redirect URIs had the same origin (since
// there is no check in RedirectEndHighRes()) // there is no check in RedirectEndHighRes())
return mTiming && mTiming->ShouldReportCrossOriginRedirect() return mTimingData && mTimingData->ShouldReportCrossOriginRedirect()
? mTiming->RedirectEndHighRes() ? mTimingData->RedirectEndHighRes(mPerformance)
: 0; : 0;
} }
DOMHighResTimeStamp DomainLookupStart() const { DOMHighResTimeStamp DomainLookupStart() const {
return mTiming && mTiming->TimingAllowed() return mTimingData && mTimingData->TimingAllowed()
? mTiming->DomainLookupStartHighRes() ? mTimingData->DomainLookupStartHighRes(mPerformance)
: 0; : 0;
} }
DOMHighResTimeStamp DomainLookupEnd() const { DOMHighResTimeStamp DomainLookupEnd() const {
return mTiming && mTiming->TimingAllowed() return mTimingData && mTimingData->TimingAllowed()
? mTiming->DomainLookupEndHighRes() ? mTimingData->DomainLookupEndHighRes(mPerformance)
: 0; : 0;
} }
DOMHighResTimeStamp ConnectStart() const { DOMHighResTimeStamp ConnectStart() const {
return mTiming && mTiming->TimingAllowed() return mTimingData && mTimingData->TimingAllowed()
? mTiming->ConnectStartHighRes() ? mTimingData->ConnectStartHighRes(mPerformance)
: 0; : 0;
} }
DOMHighResTimeStamp ConnectEnd() const { DOMHighResTimeStamp ConnectEnd() const {
return mTiming && mTiming->TimingAllowed() return mTimingData && mTimingData->TimingAllowed()
? mTiming->ConnectEndHighRes() ? mTimingData->ConnectEndHighRes(mPerformance)
: 0; : 0;
} }
DOMHighResTimeStamp RequestStart() const { DOMHighResTimeStamp RequestStart() const {
return mTiming && mTiming->TimingAllowed() return mTimingData && mTimingData->TimingAllowed()
? mTiming->RequestStartHighRes() ? mTimingData->RequestStartHighRes(mPerformance)
: 0; : 0;
} }
DOMHighResTimeStamp ResponseStart() const { DOMHighResTimeStamp ResponseStart() const {
return mTiming && mTiming->TimingAllowed() return mTimingData && mTimingData->TimingAllowed()
? mTiming->ResponseStartHighRes() ? mTimingData->ResponseStartHighRes(mPerformance)
: 0; : 0;
} }
DOMHighResTimeStamp ResponseEnd() const { DOMHighResTimeStamp ResponseEnd() const {
return mTiming return mTimingData
? mTiming->ResponseEndHighRes() ? mTimingData->ResponseEndHighRes(mPerformance)
: 0; : 0;
} }
DOMHighResTimeStamp SecureConnectionStart() const DOMHighResTimeStamp SecureConnectionStart() const
{ {
return mTiming && mTiming->TimingAllowed() return mTimingData && mTimingData->TimingAllowed()
? mTiming->SecureConnectionStartHighRes() ? mTimingData->SecureConnectionStartHighRes(mPerformance)
: 0; : 0;
} }
@@ -147,32 +142,17 @@ public:
uint64_t TransferSize() const uint64_t TransferSize() const
{ {
return mTiming && mTiming->TimingAllowed() ? mTransferSize : 0; return mTimingData ? mTimingData->TransferSize() : 0;
} }
uint64_t EncodedBodySize() const uint64_t EncodedBodySize() const
{ {
return mTiming && mTiming->TimingAllowed() ? mEncodedBodySize : 0; return mTimingData ? mTimingData->EncodedBodySize() : 0;
} }
uint64_t DecodedBodySize() const uint64_t DecodedBodySize() const
{ {
return mTiming && mTiming->TimingAllowed() ? mDecodedBodySize : 0; return mTimingData ? mTimingData->DecodedBodySize() : 0;
}
void SetEncodedBodySize(uint64_t aEncodedBodySize)
{
mEncodedBodySize = aEncodedBodySize;
}
void SetTransferSize(uint64_t aTransferSize)
{
mTransferSize = aTransferSize;
}
void SetDecodedBodySize(uint64_t aDecodedBodySize)
{
mDecodedBodySize = aDecodedBodySize;
} }
size_t size_t
@@ -180,17 +160,13 @@ public:
protected: protected:
virtual ~PerformanceResourceTiming(); virtual ~PerformanceResourceTiming();
void SetPropertiesFromChannel(nsIHttpChannel* aChannel);
size_t size_t
SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const override; SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const override;
nsString mInitiatorType; nsString mInitiatorType;
nsString mNextHopProtocol; UniquePtr<PerformanceTimingData> mTimingData;
RefPtr<PerformanceTiming> mTiming; RefPtr<Performance> mPerformance;
uint64_t mEncodedBodySize;
uint64_t mTransferSize;
uint64_t mDecodedBodySize;
}; };
} // namespace dom } // namespace dom

View File

@@ -24,35 +24,49 @@ PerformanceTiming::PerformanceTiming(Performance* aPerformance,
nsITimedChannel* aChannel, nsITimedChannel* aChannel,
nsIHttpChannel* aHttpChannel, nsIHttpChannel* aHttpChannel,
DOMHighResTimeStamp aZeroTime) DOMHighResTimeStamp aZeroTime)
: mPerformance(aPerformance), : mPerformance(aPerformance)
mFetchStart(0.0),
mZeroTime(nsRFPService::ReduceTimePrecisionAsMSecs(aZeroTime)),
mRedirectCount(0),
mTimingAllowed(true),
mAllRedirectsSameOrigin(true),
mInitialized(!!aChannel),
mReportCrossOriginRedirect(true)
{ {
MOZ_ASSERT(aPerformance, "Parent performance object should be provided"); 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() || if (!nsContentUtils::IsPerformanceTimingEnabled() ||
nsContentUtils::ShouldResistFingerprinting()) { nsContentUtils::ShouldResistFingerprinting()) {
mZeroTime = 0; 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<nsIURI> uri; nsCOMPtr<nsIURI> uri;
if (aHttpChannel) { if (aHttpChannel) {
aHttpChannel->GetURI(getter_AddRefs(uri)); aHttpChannel->GetURI(getter_AddRefs(uri));
@@ -69,23 +83,7 @@ PerformanceTiming::PerformanceTiming(Performance* aPerformance,
mSecureConnection = false; 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) { if (aChannel) {
aChannel->GetAsyncOpen(&mAsyncOpen); aChannel->GetAsyncOpen(&mAsyncOpen);
aChannel->GetAllRedirectsSameOrigin(&mAllRedirectsSameOrigin); aChannel->GetAllRedirectsSameOrigin(&mAllRedirectsSameOrigin);
@@ -110,11 +108,11 @@ PerformanceTiming::InitializeTimingInfo(nsITimedChannel* aChannel)
aChannel->GetHandleFetchEventEnd(&mWorkerResponseEnd); aChannel->GetHandleFetchEventEnd(&mWorkerResponseEnd);
// The performance timing api essentially requires that the event timestamps // The performance timing api essentially requires that the event timestamps
// have a strict relation with each other. The truth, however, is the browser // have a strict relation with each other. The truth, however, is the
// engages in a number of speculative activities that sometimes mean connections // browser engages in a number of speculative activities that sometimes mean
// and lookups begin at different times. Workaround that here by clamping // connections and lookups begin at different times. Workaround that here by
// these values to what we expect FetchStart to be. This means the later of // clamping these values to what we expect FetchStart to be. This means the
// AsyncOpen or WorkerStart times. // later of AsyncOpen or WorkerStart times.
if (!mAsyncOpen.IsNull()) { if (!mAsyncOpen.IsNull()) {
// We want to clamp to the expected FetchStart value. This is later of // We want to clamp to the expected FetchStart value. This is later of
// the AsyncOpen and WorkerStart values. // 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() PerformanceTiming::~PerformanceTiming()
@@ -152,8 +173,10 @@ PerformanceTiming::~PerformanceTiming()
} }
DOMHighResTimeStamp DOMHighResTimeStamp
PerformanceTiming::FetchStartHighRes() PerformanceTimingData::FetchStartHighRes(Performance* aPerformance)
{ {
MOZ_ASSERT(aPerformance);
if (!mFetchStart) { if (!mFetchStart) {
if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized() || if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized() ||
nsContentUtils::ShouldResistFingerprinting()) { nsContentUtils::ShouldResistFingerprinting()) {
@@ -163,9 +186,9 @@ PerformanceTiming::FetchStartHighRes()
"valid if the performance timing is enabled"); "valid if the performance timing is enabled");
if (!mAsyncOpen.IsNull()) { if (!mAsyncOpen.IsNull()) {
if (!mWorkerRequestStart.IsNull() && mWorkerRequestStart > mAsyncOpen) { if (!mWorkerRequestStart.IsNull() && mWorkerRequestStart > mAsyncOpen) {
mFetchStart = TimeStampToDOMHighRes(mWorkerRequestStart); mFetchStart = TimeStampToDOMHighRes(aPerformance, mWorkerRequestStart);
} else { } else {
mFetchStart = TimeStampToDOMHighRes(mAsyncOpen); mFetchStart = TimeStampToDOMHighRes(aPerformance, mAsyncOpen);
} }
} }
} }
@@ -175,12 +198,12 @@ PerformanceTiming::FetchStartHighRes()
DOMTimeMilliSec DOMTimeMilliSec
PerformanceTiming::FetchStart() PerformanceTiming::FetchStart()
{ {
return static_cast<int64_t>(FetchStartHighRes()); return static_cast<int64_t>(mTimingData->FetchStartHighRes(mPerformance));
} }
bool bool
PerformanceTiming::CheckAllowedOrigin(nsIHttpChannel* aResourceChannel, PerformanceTimingData::CheckAllowedOrigin(nsIHttpChannel* aResourceChannel,
nsITimedChannel* aChannel) nsITimedChannel* aChannel)
{ {
if (!IsInitialized()) { if (!IsInitialized()) {
return false; return false;
@@ -208,14 +231,8 @@ PerformanceTiming::CheckAllowedOrigin(nsIHttpChannel* aResourceChannel,
return aChannel->TimingAllowCheck(principal); return aChannel->TimingAllowCheck(principal);
} }
bool
PerformanceTiming::TimingAllowed() const
{
return mTimingAllowed;
}
uint8_t uint8_t
PerformanceTiming::GetRedirectCount() const PerformanceTimingData::GetRedirectCount() const
{ {
if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized() || if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized() ||
nsContentUtils::ShouldResistFingerprinting()) { nsContentUtils::ShouldResistFingerprinting()) {
@@ -228,7 +245,7 @@ PerformanceTiming::GetRedirectCount() const
} }
bool bool
PerformanceTiming::ShouldReportCrossOriginRedirect() const PerformanceTimingData::ShouldReportCrossOriginRedirect() const
{ {
if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized() || if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized() ||
nsContentUtils::ShouldResistFingerprinting()) { nsContentUtils::ShouldResistFingerprinting()) {
@@ -242,23 +259,29 @@ PerformanceTiming::ShouldReportCrossOriginRedirect() const
} }
DOMHighResTimeStamp DOMHighResTimeStamp
PerformanceTiming::AsyncOpenHighRes() PerformanceTimingData::AsyncOpenHighRes(Performance* aPerformance)
{ {
MOZ_ASSERT(aPerformance);
if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized() || if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized() ||
nsContentUtils::ShouldResistFingerprinting() || mAsyncOpen.IsNull()) { nsContentUtils::ShouldResistFingerprinting() || mAsyncOpen.IsNull()) {
return mZeroTime; return mZeroTime;
} }
return nsRFPService::ReduceTimePrecisionAsMSecs(TimeStampToDOMHighRes(mAsyncOpen)); return nsRFPService::ReduceTimePrecisionAsMSecs(
TimeStampToDOMHighRes(aPerformance, mAsyncOpen));
} }
DOMHighResTimeStamp DOMHighResTimeStamp
PerformanceTiming::WorkerStartHighRes() PerformanceTimingData::WorkerStartHighRes(Performance* aPerformance)
{ {
MOZ_ASSERT(aPerformance);
if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized() || if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized() ||
nsContentUtils::ShouldResistFingerprinting() || mWorkerStart.IsNull()) { nsContentUtils::ShouldResistFingerprinting() || mWorkerStart.IsNull()) {
return mZeroTime; 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 * @return a valid timing if the Performance Timing is enabled
*/ */
DOMHighResTimeStamp DOMHighResTimeStamp
PerformanceTiming::RedirectStartHighRes() PerformanceTimingData::RedirectStartHighRes(Performance* aPerformance)
{ {
MOZ_ASSERT(aPerformance);
if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized() || if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized() ||
nsContentUtils::ShouldResistFingerprinting()) { nsContentUtils::ShouldResistFingerprinting()) {
return mZeroTime; return mZeroTime;
} }
return TimeStampToReducedDOMHighResOrFetchStart(mRedirectStart); return TimeStampToReducedDOMHighResOrFetchStart(aPerformance, mRedirectStart);
} }
DOMTimeMilliSec DOMTimeMilliSec
PerformanceTiming::RedirectStart() PerformanceTiming::RedirectStart()
{ {
if (!IsInitialized()) { if (!mTimingData->IsInitialized()) {
return 0; return 0;
} }
// We have to check if all the redirect URIs had the same origin (since there // We have to check if all the redirect URIs had the same origin (since there
// is no check in RedirectStartHighRes()) // is no check in RedirectStartHighRes())
if (mAllRedirectsSameOrigin && mRedirectCount) { if (mTimingData->AllRedirectsSameOrigin() &&
return static_cast<int64_t>(RedirectStartHighRes()); mTimingData->RedirectCountReal()) {
return static_cast<int64_t>(mTimingData->RedirectStartHighRes(mPerformance));
} }
return 0; return 0;
} }
@@ -306,85 +332,99 @@ PerformanceTiming::RedirectStart()
* @return a valid timing if the Performance Timing is enabled * @return a valid timing if the Performance Timing is enabled
*/ */
DOMHighResTimeStamp DOMHighResTimeStamp
PerformanceTiming::RedirectEndHighRes() PerformanceTimingData::RedirectEndHighRes(Performance* aPerformance)
{ {
MOZ_ASSERT(aPerformance);
if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized() || if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized() ||
nsContentUtils::ShouldResistFingerprinting()) { nsContentUtils::ShouldResistFingerprinting()) {
return mZeroTime; return mZeroTime;
} }
return TimeStampToReducedDOMHighResOrFetchStart(mRedirectEnd); return TimeStampToReducedDOMHighResOrFetchStart(aPerformance, mRedirectEnd);
} }
DOMTimeMilliSec DOMTimeMilliSec
PerformanceTiming::RedirectEnd() PerformanceTiming::RedirectEnd()
{ {
if (!IsInitialized()) { if (!mTimingData->IsInitialized()) {
return 0; return 0;
} }
// We have to check if all the redirect URIs had the same origin (since there // We have to check if all the redirect URIs had the same origin (since there
// is no check in RedirectEndHighRes()) // is no check in RedirectEndHighRes())
if (mAllRedirectsSameOrigin && mRedirectCount) { if (mTimingData->AllRedirectsSameOrigin() &&
return static_cast<int64_t>(RedirectEndHighRes()); mTimingData->RedirectCountReal()) {
return static_cast<int64_t>(mTimingData->RedirectEndHighRes(mPerformance));
} }
return 0; return 0;
} }
DOMHighResTimeStamp DOMHighResTimeStamp
PerformanceTiming::DomainLookupStartHighRes() PerformanceTimingData::DomainLookupStartHighRes(Performance* aPerformance)
{ {
MOZ_ASSERT(aPerformance);
if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized() || if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized() ||
nsContentUtils::ShouldResistFingerprinting()) { nsContentUtils::ShouldResistFingerprinting()) {
return mZeroTime; return mZeroTime;
} }
return TimeStampToReducedDOMHighResOrFetchStart(mDomainLookupStart); return TimeStampToReducedDOMHighResOrFetchStart(aPerformance,
mDomainLookupStart);
} }
DOMTimeMilliSec DOMTimeMilliSec
PerformanceTiming::DomainLookupStart() PerformanceTiming::DomainLookupStart()
{ {
return static_cast<int64_t>(DomainLookupStartHighRes()); return static_cast<int64_t>(mTimingData->DomainLookupStartHighRes(mPerformance));
} }
DOMHighResTimeStamp DOMHighResTimeStamp
PerformanceTiming::DomainLookupEndHighRes() PerformanceTimingData::DomainLookupEndHighRes(Performance* aPerformance)
{ {
MOZ_ASSERT(aPerformance);
if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized() || if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized() ||
nsContentUtils::ShouldResistFingerprinting()) { nsContentUtils::ShouldResistFingerprinting()) {
return mZeroTime; return mZeroTime;
} }
// Bug 1155008 - nsHttpTransaction is racy. Return DomainLookupStart when null // Bug 1155008 - nsHttpTransaction is racy. Return DomainLookupStart when null
return mDomainLookupEnd.IsNull() ? DomainLookupStartHighRes() return mDomainLookupEnd.IsNull()
: nsRFPService::ReduceTimePrecisionAsMSecs( ? DomainLookupStartHighRes(aPerformance)
TimeStampToDOMHighRes(mDomainLookupEnd)); : nsRFPService::ReduceTimePrecisionAsMSecs(
TimeStampToDOMHighRes(aPerformance, mDomainLookupEnd));
} }
DOMTimeMilliSec DOMTimeMilliSec
PerformanceTiming::DomainLookupEnd() PerformanceTiming::DomainLookupEnd()
{ {
return static_cast<int64_t>(DomainLookupEndHighRes()); return static_cast<int64_t>(mTimingData->DomainLookupEndHighRes(mPerformance));
} }
DOMHighResTimeStamp DOMHighResTimeStamp
PerformanceTiming::ConnectStartHighRes() PerformanceTimingData::ConnectStartHighRes(Performance* aPerformance)
{ {
MOZ_ASSERT(aPerformance);
if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized() || if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized() ||
nsContentUtils::ShouldResistFingerprinting()) { nsContentUtils::ShouldResistFingerprinting()) {
return mZeroTime; return mZeroTime;
} }
return mConnectStart.IsNull() ? DomainLookupEndHighRes() return mConnectStart.IsNull()
: nsRFPService::ReduceTimePrecisionAsMSecs( ? DomainLookupEndHighRes(aPerformance)
TimeStampToDOMHighRes(mConnectStart)); : nsRFPService::ReduceTimePrecisionAsMSecs(
TimeStampToDOMHighRes(aPerformance, mConnectStart));
} }
DOMTimeMilliSec DOMTimeMilliSec
PerformanceTiming::ConnectStart() PerformanceTiming::ConnectStart()
{ {
return static_cast<int64_t>(ConnectStartHighRes()); return static_cast<int64_t>(mTimingData->ConnectStartHighRes(mPerformance));
} }
DOMHighResTimeStamp DOMHighResTimeStamp
PerformanceTiming::SecureConnectionStartHighRes() PerformanceTimingData::SecureConnectionStartHighRes(Performance* aPerformance)
{ {
MOZ_ASSERT(aPerformance);
if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized() || if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized() ||
nsContentUtils::ShouldResistFingerprinting()) { nsContentUtils::ShouldResistFingerprinting()) {
return mZeroTime; return mZeroTime;
@@ -392,39 +432,45 @@ PerformanceTiming::SecureConnectionStartHighRes()
return !mSecureConnection return !mSecureConnection
? 0 // We use 0 here, because mZeroTime is sometimes set to the navigation ? 0 // We use 0 here, because mZeroTime is sometimes set to the navigation
// start time. // start time.
: (mSecureConnectionStart.IsNull() ? mZeroTime : (mSecureConnectionStart.IsNull()
: nsRFPService::ReduceTimePrecisionAsMSecs( ? mZeroTime
TimeStampToDOMHighRes(mSecureConnectionStart))); : nsRFPService::ReduceTimePrecisionAsMSecs(
TimeStampToDOMHighRes(aPerformance, mSecureConnectionStart)));
} }
DOMTimeMilliSec DOMTimeMilliSec
PerformanceTiming::SecureConnectionStart() PerformanceTiming::SecureConnectionStart()
{ {
return static_cast<int64_t>(SecureConnectionStartHighRes()); return static_cast<int64_t>(mTimingData->SecureConnectionStartHighRes(mPerformance));
} }
DOMHighResTimeStamp DOMHighResTimeStamp
PerformanceTiming::ConnectEndHighRes() PerformanceTimingData::ConnectEndHighRes(Performance* aPerformance)
{ {
MOZ_ASSERT(aPerformance);
if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized() || if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized() ||
nsContentUtils::ShouldResistFingerprinting()) { nsContentUtils::ShouldResistFingerprinting()) {
return mZeroTime; return mZeroTime;
} }
// Bug 1155008 - nsHttpTransaction is racy. Return ConnectStart when null // Bug 1155008 - nsHttpTransaction is racy. Return ConnectStart when null
return mConnectEnd.IsNull() ? ConnectStartHighRes() return mConnectEnd.IsNull()
: nsRFPService::ReduceTimePrecisionAsMSecs( ? ConnectStartHighRes(aPerformance)
TimeStampToDOMHighRes(mConnectEnd)); : nsRFPService::ReduceTimePrecisionAsMSecs(
TimeStampToDOMHighRes(aPerformance, mConnectEnd));
} }
DOMTimeMilliSec DOMTimeMilliSec
PerformanceTiming::ConnectEnd() PerformanceTiming::ConnectEnd()
{ {
return static_cast<int64_t>(ConnectEndHighRes()); return static_cast<int64_t>(mTimingData->ConnectEndHighRes(mPerformance));
} }
DOMHighResTimeStamp DOMHighResTimeStamp
PerformanceTiming::RequestStartHighRes() PerformanceTimingData::RequestStartHighRes(Performance* aPerformance)
{ {
MOZ_ASSERT(aPerformance);
if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized() || if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized() ||
nsContentUtils::ShouldResistFingerprinting()) { nsContentUtils::ShouldResistFingerprinting()) {
return mZeroTime; return mZeroTime;
@@ -434,18 +480,20 @@ PerformanceTiming::RequestStartHighRes()
mRequestStart = mWorkerRequestStart; mRequestStart = mWorkerRequestStart;
} }
return TimeStampToReducedDOMHighResOrFetchStart(mRequestStart); return TimeStampToReducedDOMHighResOrFetchStart(aPerformance, mRequestStart);
} }
DOMTimeMilliSec DOMTimeMilliSec
PerformanceTiming::RequestStart() PerformanceTiming::RequestStart()
{ {
return static_cast<int64_t>(RequestStartHighRes()); return static_cast<int64_t>(mTimingData->RequestStartHighRes(mPerformance));
} }
DOMHighResTimeStamp DOMHighResTimeStamp
PerformanceTiming::ResponseStartHighRes() PerformanceTimingData::ResponseStartHighRes(Performance* aPerformance)
{ {
MOZ_ASSERT(aPerformance);
if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized() || if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized() ||
nsContentUtils::ShouldResistFingerprinting()) { nsContentUtils::ShouldResistFingerprinting()) {
return mZeroTime; return mZeroTime;
@@ -459,18 +507,20 @@ PerformanceTiming::ResponseStartHighRes()
(!mRequestStart.IsNull() && mResponseStart < mRequestStart)) { (!mRequestStart.IsNull() && mResponseStart < mRequestStart)) {
mResponseStart = mRequestStart; mResponseStart = mRequestStart;
} }
return TimeStampToReducedDOMHighResOrFetchStart(mResponseStart); return TimeStampToReducedDOMHighResOrFetchStart(aPerformance, mResponseStart);
} }
DOMTimeMilliSec DOMTimeMilliSec
PerformanceTiming::ResponseStart() PerformanceTiming::ResponseStart()
{ {
return static_cast<int64_t>(ResponseStartHighRes()); return static_cast<int64_t>(mTimingData->ResponseStartHighRes(mPerformance));
} }
DOMHighResTimeStamp DOMHighResTimeStamp
PerformanceTiming::ResponseEndHighRes() PerformanceTimingData::ResponseEndHighRes(Performance* aPerformance)
{ {
MOZ_ASSERT(aPerformance);
if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized() || if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized() ||
nsContentUtils::ShouldResistFingerprinting()) { nsContentUtils::ShouldResistFingerprinting()) {
return mZeroTime; return mZeroTime;
@@ -483,21 +533,16 @@ PerformanceTiming::ResponseEndHighRes()
mResponseEnd = mWorkerResponseEnd; mResponseEnd = mWorkerResponseEnd;
} }
// Bug 1155008 - nsHttpTransaction is racy. Return ResponseStart when null // Bug 1155008 - nsHttpTransaction is racy. Return ResponseStart when null
return mResponseEnd.IsNull() ? ResponseStartHighRes() return mResponseEnd.IsNull()
: nsRFPService::ReduceTimePrecisionAsMSecs( ? ResponseStartHighRes(aPerformance)
TimeStampToDOMHighRes(mResponseEnd)); : nsRFPService::ReduceTimePrecisionAsMSecs(
TimeStampToDOMHighRes(aPerformance, mResponseEnd));
} }
DOMTimeMilliSec DOMTimeMilliSec
PerformanceTiming::ResponseEnd() PerformanceTiming::ResponseEnd()
{ {
return static_cast<int64_t>(ResponseEndHighRes()); return static_cast<int64_t>(mTimingData->ResponseEndHighRes(mPerformance));
}
bool
PerformanceTiming::IsInitialized() const
{
return mInitialized;
} }
JSObject* JSObject*

View File

@@ -20,6 +20,190 @@ class nsITimedChannel;
namespace mozilla { namespace mozilla {
namespace dom { 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 // Script "performance.timing" object
class PerformanceTiming final : public nsWrapperCache class PerformanceTiming final : public nsWrapperCache
{ {
@@ -60,57 +244,6 @@ public:
return mPerformance; 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, virtual JSObject* WrapObject(JSContext *cx,
JS::Handle<JSObject*> aGivenProto) override; JS::Handle<JSObject*> aGivenProto) override;
@@ -145,40 +278,6 @@ public:
GetDOMTiming()->GetUnloadEventEnd()); 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) // Low resolution (used by navigation timing)
DOMTimeMilliSec FetchStart(); DOMTimeMilliSec FetchStart();
DOMTimeMilliSec RedirectStart(); DOMTimeMilliSec RedirectStart();
@@ -272,53 +371,19 @@ public:
GetDOMTiming()->GetTimeToNonBlankPaint()); GetDOMTiming()->GetTimeToNonBlankPaint());
} }
PerformanceTimingData* Data() const
{
return mTimingData.get();
}
private: private:
~PerformanceTiming(); ~PerformanceTiming();
bool IsInitialized() const;
void InitializeTimingInfo(nsITimedChannel* aChannel);
bool IsTopLevelContentDocument() const; bool IsTopLevelContentDocument() const;
RefPtr<Performance> mPerformance; RefPtr<Performance> mPerformance;
DOMHighResTimeStamp mFetchStart;
// This is an offset that will be added to each timing ([ms] resolution). UniquePtr<PerformanceTimingData> mTimingData;
// 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;
}; };
} // namespace dom } // namespace dom