Bug 1425462 Pass in a time origin for the Performance APIs. At least I think I got them all... draft
authorTom Ritter <tom@mozilla.com>
Wed, 24 Jan 2018 16:40:28 -0600
changeset 724418 50223c82296d05d2b5da5bab03aa70e6e06bee3f
parent 724417 f8877990df49108a1883258c6cdbc5b9d6571edd
child 747145 16a4ac85dea78cffb35df4d46c4591ad5cc806a8
push id96741
push userbmo:tom@mozilla.com
push dateWed, 24 Jan 2018 22:45:52 +0000
bugs1425462
milestone59.0a1
Bug 1425462 Pass in a time origin for the Performance APIs. At least I think I got them all... MozReview-Commit-ID: 7em25TgqUrD
dom/performance/PerformanceTiming.cpp
dom/performance/PerformanceTiming.h
--- a/dom/performance/PerformanceTiming.cpp
+++ b/dom/performance/PerformanceTiming.cpp
@@ -22,16 +22,17 @@ NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(P
 
 PerformanceTiming::PerformanceTiming(Performance* aPerformance,
                                      nsITimedChannel* aChannel,
                                      nsIHttpChannel* aHttpChannel,
                                      DOMHighResTimeStamp aZeroTime)
   : mPerformance(aPerformance),
     mFetchStart(0.0),
     mZeroTime(nsRFPService::ReduceTimePrecisionAsMSecs(aZeroTime)),
+    mPerformanceTimingType(aZeroTime == 0 ? RESOURCE_TIMING : NAVIGATION_TIMING),
     mRedirectCount(0),
     mTimingAllowed(true),
     mAllRedirectsSameOrigin(true),
     mInitialized(!!aChannel),
     mReportCrossOriginRedirect(true)
 {
   MOZ_ASSERT(aPerformance, "Parent performance object should be provided");
 
@@ -152,29 +153,30 @@ PerformanceTiming::~PerformanceTiming()
 }
 
 DOMHighResTimeStamp
 PerformanceTiming::FetchStartHighRes()
 {
   if (!mFetchStart) {
     if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized() ||
         nsContentUtils::ShouldResistFingerprinting()) {
-      return mZeroTime;
+      return nsRFPService::ReduceTimePrecisionAsMSecs(mZeroTime, 0, false);
     }
     MOZ_ASSERT(!mAsyncOpen.IsNull(), "The fetch start time stamp should always be "
         "valid if the performance timing is enabled");
     if (!mAsyncOpen.IsNull()) {
       if (!mWorkerRequestStart.IsNull() && mWorkerRequestStart > mAsyncOpen) {
         mFetchStart = TimeStampToDOMHighRes(mWorkerRequestStart);
       } else {
         mFetchStart = TimeStampToDOMHighRes(mAsyncOpen);
       }
     }
   }
-  return nsRFPService::ReduceTimePrecisionAsMSecs(mFetchStart);
+  return nsRFPService::ReduceTimePrecisionAsMSecs(mFetchStart,
+    GetAbsoluteTimeReferencePoint(), false);
 }
 
 DOMTimeMilliSec
 PerformanceTiming::FetchStart()
 {
   return static_cast<int64_t>(FetchStartHighRes());
 }
 
@@ -243,27 +245,29 @@ PerformanceTiming::ShouldReportCrossOrig
 
 DOMHighResTimeStamp
 PerformanceTiming::AsyncOpenHighRes()
 {
   if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized() ||
       nsContentUtils::ShouldResistFingerprinting() || mAsyncOpen.IsNull()) {
     return mZeroTime;
   }
-  return nsRFPService::ReduceTimePrecisionAsMSecs(TimeStampToDOMHighRes(mAsyncOpen));
+  return nsRFPService::ReduceTimePrecisionAsMSecs(
+    TimeStampToDOMHighRes(mAsyncOpen), GetAbsoluteTimeReferencePoint(), false);
 }
 
 DOMHighResTimeStamp
 PerformanceTiming::WorkerStartHighRes()
 {
   if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized() ||
       nsContentUtils::ShouldResistFingerprinting() || mWorkerStart.IsNull()) {
     return mZeroTime;
   }
-  return nsRFPService::ReduceTimePrecisionAsMSecs(TimeStampToDOMHighRes(mWorkerStart));
+  return nsRFPService::ReduceTimePrecisionAsMSecs(
+    TimeStampToDOMHighRes(mWorkerStart), GetAbsoluteTimeReferencePoint(), false);
 }
 
 /**
  * RedirectStartHighRes() is used by both the navigation timing and the
  * resource timing. Since, navigation timing and resource timing check and
  * interpret cross-domain redirects in a different manner,
  * RedirectStartHighRes() will make no checks for cross-domain redirect.
  * It's up to the consumers of this method (PerformanceTiming::RedirectStart()
@@ -350,17 +354,18 @@ PerformanceTiming::DomainLookupEndHighRe
 {
   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));
+                                       TimeStampToDOMHighRes(mDomainLookupEnd),
+                                       GetAbsoluteTimeReferencePoint(), false);
 }
 
 DOMTimeMilliSec
 PerformanceTiming::DomainLookupEnd()
 {
   return static_cast<int64_t>(DomainLookupEndHighRes());
 }
 
@@ -368,17 +373,18 @@ DOMHighResTimeStamp
 PerformanceTiming::ConnectStartHighRes()
 {
   if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized() ||
       nsContentUtils::ShouldResistFingerprinting()) {
     return mZeroTime;
   }
   return mConnectStart.IsNull() ? DomainLookupEndHighRes()
                                 : nsRFPService::ReduceTimePrecisionAsMSecs(
-                                    TimeStampToDOMHighRes(mConnectStart));
+                                    TimeStampToDOMHighRes(mConnectStart),
+                                    GetAbsoluteTimeReferencePoint(), false);
 }
 
 DOMTimeMilliSec
 PerformanceTiming::ConnectStart()
 {
   return static_cast<int64_t>(ConnectStartHighRes());
 }
 
@@ -389,17 +395,18 @@ PerformanceTiming::SecureConnectionStart
       nsContentUtils::ShouldResistFingerprinting()) {
     return mZeroTime;
   }
   return !mSecureConnection
     ? 0 // We use 0 here, because mZeroTime is sometimes set to the navigation
         // start time.
     : (mSecureConnectionStart.IsNull() ? mZeroTime
                                        : nsRFPService::ReduceTimePrecisionAsMSecs(
-                                           TimeStampToDOMHighRes(mSecureConnectionStart)));
+                                           TimeStampToDOMHighRes(mSecureConnectionStart),
+                                           GetAbsoluteTimeReferencePoint(), false));
 }
 
 DOMTimeMilliSec
 PerformanceTiming::SecureConnectionStart()
 {
   return static_cast<int64_t>(SecureConnectionStartHighRes());
 }
 
@@ -408,17 +415,18 @@ PerformanceTiming::ConnectEndHighRes()
 {
   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));
+                                  TimeStampToDOMHighRes(mConnectEnd),
+                                  GetAbsoluteTimeReferencePoint(), false);
 }
 
 DOMTimeMilliSec
 PerformanceTiming::ConnectEnd()
 {
   return static_cast<int64_t>(ConnectEndHighRes());
 }
 
@@ -480,17 +488,18 @@ PerformanceTiming::ResponseEndHighRes()
     mResponseEnd = mCacheReadEnd;
   }
   if (mResponseEnd.IsNull()) {
     mResponseEnd = mWorkerResponseEnd;
   }
   // Bug 1155008 - nsHttpTransaction is racy. Return ResponseStart when null
   return mResponseEnd.IsNull() ? ResponseStartHighRes()
                                : nsRFPService::ReduceTimePrecisionAsMSecs(
-                                   TimeStampToDOMHighRes(mResponseEnd));
+                                   TimeStampToDOMHighRes(mResponseEnd),
+                                   GetAbsoluteTimeReferencePoint(), false);
 }
 
 DOMTimeMilliSec
 PerformanceTiming::ResponseEnd()
 {
   return static_cast<int64_t>(ResponseEndHighRes());
 }
 
--- a/dom/performance/PerformanceTiming.h
+++ b/dom/performance/PerformanceTiming.h
@@ -67,17 +67,18 @@ public:
    * @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))
+        ? nsRFPService::ReduceTimePrecisionAsMSecs(TimeStampToDOMHighRes(aStamp),
+            GetAbsoluteTimeReferencePoint(), false)
         : 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).
@@ -117,37 +118,40 @@ public:
   // PerformanceNavigation WebIDL methods
   DOMTimeMilliSec NavigationStart() const
   {
     if (!nsContentUtils::IsPerformanceTimingEnabled() ||
         nsContentUtils::ShouldResistFingerprinting()) {
       return 0;
     }
     return nsRFPService::ReduceTimePrecisionAsMSecs(
-      GetDOMTiming()->GetNavigationStart(), 0, false);
+      GetDOMTiming()->GetNavigationStart(),
+      GetAbsoluteTimeReferencePoint(), false);
   }
 
   DOMTimeMilliSec UnloadEventStart()
   {
     if (!nsContentUtils::IsPerformanceTimingEnabled() ||
         nsContentUtils::ShouldResistFingerprinting()) {
       return 0;
     }
     return nsRFPService::ReduceTimePrecisionAsMSecs(
-      GetDOMTiming()->GetUnloadEventStart());
+      GetDOMTiming()->GetUnloadEventStart(),
+      GetAbsoluteTimeReferencePoint(), false);
   }
 
   DOMTimeMilliSec UnloadEventEnd()
   {
     if (!nsContentUtils::IsPerformanceTimingEnabled() ||
         nsContentUtils::ShouldResistFingerprinting()) {
       return 0;
     }
     return nsRFPService::ReduceTimePrecisionAsMSecs(
-      GetDOMTiming()->GetUnloadEventEnd());
+      GetDOMTiming()->GetUnloadEventEnd(),
+      GetAbsoluteTimeReferencePoint(), false);
   }
 
   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);
@@ -194,106 +198,134 @@ public:
 
   DOMTimeMilliSec DomLoading()
   {
     if (!nsContentUtils::IsPerformanceTimingEnabled() ||
         nsContentUtils::ShouldResistFingerprinting()) {
       return 0;
     }
     return nsRFPService::ReduceTimePrecisionAsMSecs(
-      GetDOMTiming()->GetDomLoading());
+      GetDOMTiming()->GetDomLoading(),
+      GetAbsoluteTimeReferencePoint(), false);
   }
 
   DOMTimeMilliSec DomInteractive() const
   {
     if (!nsContentUtils::IsPerformanceTimingEnabled() ||
         nsContentUtils::ShouldResistFingerprinting()) {
       return 0;
     }
     return nsRFPService::ReduceTimePrecisionAsMSecs(
-      GetDOMTiming()->GetDomInteractive());
+      GetDOMTiming()->GetDomInteractive(), 0, false);
   }
 
   DOMTimeMilliSec DomContentLoadedEventStart() const
   {
     if (!nsContentUtils::IsPerformanceTimingEnabled() ||
         nsContentUtils::ShouldResistFingerprinting()) {
       return 0;
     }
     return nsRFPService::ReduceTimePrecisionAsMSecs(
-      GetDOMTiming()->GetDomContentLoadedEventStart());
+      GetDOMTiming()->GetDomContentLoadedEventStart(),
+      GetAbsoluteTimeReferencePoint(), false);
   }
 
   DOMTimeMilliSec DomContentLoadedEventEnd() const
   {
     if (!nsContentUtils::IsPerformanceTimingEnabled() ||
         nsContentUtils::ShouldResistFingerprinting()) {
       return 0;
     }
     return nsRFPService::ReduceTimePrecisionAsMSecs(
-      GetDOMTiming()->GetDomContentLoadedEventEnd());
+      GetDOMTiming()->GetDomContentLoadedEventEnd(),
+      GetAbsoluteTimeReferencePoint(), false);
   }
 
   DOMTimeMilliSec DomComplete() const
   {
     if (!nsContentUtils::IsPerformanceTimingEnabled() ||
         nsContentUtils::ShouldResistFingerprinting()) {
       return 0;
     }
     return nsRFPService::ReduceTimePrecisionAsMSecs(
-      GetDOMTiming()->GetDomComplete());
+      GetDOMTiming()->GetDomComplete(),
+      GetAbsoluteTimeReferencePoint(), false);
   }
 
   DOMTimeMilliSec LoadEventStart() const
   {
     if (!nsContentUtils::IsPerformanceTimingEnabled() ||
         nsContentUtils::ShouldResistFingerprinting()) {
       return 0;
     }
     return nsRFPService::ReduceTimePrecisionAsMSecs(
-      GetDOMTiming()->GetLoadEventStart());
+      GetDOMTiming()->GetLoadEventStart(),
+      GetAbsoluteTimeReferencePoint(), false);
   }
 
   DOMTimeMilliSec LoadEventEnd() const
   {
     if (!nsContentUtils::IsPerformanceTimingEnabled() ||
         nsContentUtils::ShouldResistFingerprinting()) {
       return 0;
     }
     return nsRFPService::ReduceTimePrecisionAsMSecs(
-      GetDOMTiming()->GetLoadEventEnd());
+      GetDOMTiming()->GetLoadEventEnd(),
+      GetAbsoluteTimeReferencePoint(), false);
   }
 
   DOMTimeMilliSec TimeToNonBlankPaint() const
   {
     if (!nsContentUtils::IsPerformanceTimingEnabled() ||
         nsContentUtils::ShouldResistFingerprinting()) {
       return 0;
     }
     return nsRFPService::ReduceTimePrecisionAsMSecs(
-      GetDOMTiming()->GetTimeToNonBlankPaint());
+      GetDOMTiming()->GetTimeToNonBlankPaint(),
+      GetAbsoluteTimeReferencePoint(), false);
   }
 
 private:
   ~PerformanceTiming();
 
   bool IsInitialized() const;
   void InitializeTimingInfo(nsITimedChannel* aChannel);
 
   bool IsTopLevelContentDocument() const;
 
+  // Returns a value that should be added to the various timestamps
+  // to convert to milliseconds since the epoch
+  inline DOMTimeMilliSec GetAbsoluteTimeReferencePoint() const
+  {
+    return mPerformanceTimingType == RESOURCE_TIMING ? 
+      this->GetDOMTiming()->GetNavigationStartHighRes() : 0;
+  }
+
   RefPtr<Performance> 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;
 
+  enum PerformanceTimingType {
+    // Resource timing entries have relative timestamps and a zero mZeroTime
+    // They are access as part of performance.getEntriesByType("resource")
+    // or equivalent
+    RESOURCE_TIMING,
+    // Navigation timing entries are exposed by performance.timing.XXX, have
+    // a non-zero mZeroTime but have absolute timestamps. One should not
+    // add mZeroTime to the TimeStamp value; but one may subtract mZeroTime
+    // to get a duration.
+    NAVIGATION_TIMING
+  };
+  PerformanceTimingType mPerformanceTimingType;
+
   TimeStamp mAsyncOpen;
   TimeStamp mRedirectStart;
   TimeStamp mRedirectEnd;
   TimeStamp mDomainLookupStart;
   TimeStamp mDomainLookupEnd;
   TimeStamp mConnectStart;
   TimeStamp mSecureConnectionStart;
   TimeStamp mConnectEnd;