Bug 1424341 Round the Performance Timing APIs when privacy.reduceTimerPrecision is set draft
authorTom Ritter <tom@mozilla.com>
Wed, 10 Jan 2018 15:51:23 -0600
changeset 718835 33d81b8b54039ca55625b5a98ec87002f804ac8f
parent 718834 8f02e33c813cb77d408649ee8c09f3ace7929654
child 718836 dac8763669c1c6f0068f527edff612baa010bc8b
push id95052
push userbmo:tom@mozilla.com
push dateWed, 10 Jan 2018 21:56:43 +0000
bugs1424341
milestone59.0a1
Bug 1424341 Round the Performance Timing APIs when privacy.reduceTimerPrecision is set MozReview-Commit-ID: LrAmrIfKk39
dom/performance/Performance.cpp
dom/performance/PerformanceNavigationTiming.h
dom/performance/PerformanceTiming.cpp
dom/performance/PerformanceTiming.h
--- a/dom/performance/Performance.cpp
+++ b/dom/performance/Performance.cpp
@@ -131,17 +131,18 @@ Performance::Now() const
 DOMHighResTimeStamp
 Performance::TimeOrigin()
 {
   if (!mPerformanceService) {
     mPerformanceService = PerformanceService::GetOrCreate();
   }
 
   MOZ_ASSERT(mPerformanceService);
-  return mPerformanceService->TimeOrigin(CreationTimeStamp());
+  return nsRFPService::ReduceTimePrecisionAsMSecs(
+    mPerformanceService->TimeOrigin(CreationTimeStamp()));
 }
 
 JSObject*
 Performance::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
 {
   return PerformanceBinding::Wrap(aCx, this, aGivenProto);
 }
 
--- a/dom/performance/PerformanceNavigationTiming.h
+++ b/dom/performance/PerformanceNavigationTiming.h
@@ -5,16 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_PerformanceNavigationTiming_h___
 #define mozilla_dom_PerformanceNavigationTiming_h___
 
 #include "nsCOMPtr.h"
 #include "nsIChannel.h"
 #include "nsITimedChannel.h"
+#include "nsRFPService.h"
 #include "mozilla/dom/PerformanceResourceTiming.h"
 #include "mozilla/dom/PerformanceNavigationTimingBinding.h"
 #include "nsIHttpChannel.h"
 
 namespace mozilla {
 namespace dom {
 
 // https://www.w3.org/TR/navigation-timing-2/#sec-PerformanceNavigationTiming
@@ -34,17 +35,17 @@ public:
     : PerformanceResourceTiming(aPerformanceTiming, aPerformance,
                                 NS_LITERAL_STRING("document"), aChannel) {
       SetEntryType(NS_LITERAL_STRING("navigation"));
       SetInitiatorType(NS_LITERAL_STRING("navigation"));
     }
 
   DOMHighResTimeStamp Duration() const override
   {
-    return LoadEventEnd() - StartTime();
+    return nsRFPService::ReduceTimePrecisionAsMSecs(LoadEventEnd() - StartTime());
   }
 
   DOMHighResTimeStamp StartTime() const override
   {
     return 0;
   }
 
   JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
--- a/dom/performance/PerformanceTiming.cpp
+++ b/dom/performance/PerformanceTiming.cpp
@@ -21,17 +21,17 @@ NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(Per
 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(PerformanceTiming, Release)
 
 PerformanceTiming::PerformanceTiming(Performance* aPerformance,
                                      nsITimedChannel* aChannel,
                                      nsIHttpChannel* aHttpChannel,
                                      DOMHighResTimeStamp aZeroTime)
   : mPerformance(aPerformance),
     mFetchStart(0.0),
-    mZeroTime(aZeroTime),
+    mZeroTime(nsRFPService::ReduceTimePrecisionAsMSecs(aZeroTime)),
     mRedirectCount(0),
     mTimingAllowed(true),
     mAllRedirectsSameOrigin(true),
     mInitialized(!!aChannel),
     mReportCrossOriginRedirect(true)
 {
   MOZ_ASSERT(aPerformance, "Parent performance object should be provided");
 
@@ -164,17 +164,17 @@ PerformanceTiming::FetchStartHighRes()
     if (!mAsyncOpen.IsNull()) {
       if (!mWorkerRequestStart.IsNull() && mWorkerRequestStart > mAsyncOpen) {
         mFetchStart = TimeStampToDOMHighRes(mWorkerRequestStart);
       } else {
         mFetchStart = TimeStampToDOMHighRes(mAsyncOpen);
       }
     }
   }
-  return mFetchStart;
+  return nsRFPService::ReduceTimePrecisionAsMSecs(mFetchStart);
 }
 
 DOMTimeMilliSec
 PerformanceTiming::FetchStart()
 {
   return static_cast<int64_t>(FetchStartHighRes());
 }
 
@@ -243,27 +243,27 @@ PerformanceTiming::ShouldReportCrossOrig
 
 DOMHighResTimeStamp
 PerformanceTiming::AsyncOpenHighRes()
 {
   if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized() ||
       nsContentUtils::ShouldResistFingerprinting() || mAsyncOpen.IsNull()) {
     return mZeroTime;
   }
-  return TimeStampToDOMHighRes(mAsyncOpen);
+  return nsRFPService::ReduceTimePrecisionAsMSecs(TimeStampToDOMHighRes(mAsyncOpen));
 }
 
 DOMHighResTimeStamp
 PerformanceTiming::WorkerStartHighRes()
 {
   if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized() ||
       nsContentUtils::ShouldResistFingerprinting() || mWorkerStart.IsNull()) {
     return mZeroTime;
   }
-  return TimeStampToDOMHighRes(mWorkerStart);
+  return nsRFPService::ReduceTimePrecisionAsMSecs(TimeStampToDOMHighRes(mWorkerStart));
 }
 
 /**
  * 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()
@@ -273,17 +273,18 @@ PerformanceTiming::WorkerStartHighRes()
  */
 DOMHighResTimeStamp
 PerformanceTiming::RedirectStartHighRes()
 {
   if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized() ||
       nsContentUtils::ShouldResistFingerprinting()) {
     return mZeroTime;
   }
-  return TimeStampToDOMHighResOrFetchStart(mRedirectStart);
+  return nsRFPService::ReduceTimePrecisionAsMSecs(
+    TimeStampToDOMHighResOrFetchStart(mRedirectStart));
 }
 
 DOMTimeMilliSec
 PerformanceTiming::RedirectStart()
 {
   if (!IsInitialized()) {
     return 0;
   }
@@ -307,17 +308,18 @@ PerformanceTiming::RedirectStart()
  */
 DOMHighResTimeStamp
 PerformanceTiming::RedirectEndHighRes()
 {
   if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized() ||
       nsContentUtils::ShouldResistFingerprinting()) {
     return mZeroTime;
   }
-  return TimeStampToDOMHighResOrFetchStart(mRedirectEnd);
+  return nsRFPService::ReduceTimePrecisionAsMSecs(
+    TimeStampToDOMHighResOrFetchStart(mRedirectEnd));
 }
 
 DOMTimeMilliSec
 PerformanceTiming::RedirectEnd()
 {
   if (!IsInitialized()) {
     return 0;
   }
@@ -331,17 +333,18 @@ PerformanceTiming::RedirectEnd()
 
 DOMHighResTimeStamp
 PerformanceTiming::DomainLookupStartHighRes()
 {
   if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized() ||
       nsContentUtils::ShouldResistFingerprinting()) {
     return mZeroTime;
   }
-  return TimeStampToDOMHighResOrFetchStart(mDomainLookupStart);
+  return nsRFPService::ReduceTimePrecisionAsMSecs(
+    TimeStampToDOMHighResOrFetchStart(mDomainLookupStart));
 }
 
 DOMTimeMilliSec
 PerformanceTiming::DomainLookupStart()
 {
   return static_cast<int64_t>(DomainLookupStartHighRes());
 }
 
@@ -349,34 +352,36 @@ DOMHighResTimeStamp
 PerformanceTiming::DomainLookupEndHighRes()
 {
   if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized() ||
       nsContentUtils::ShouldResistFingerprinting()) {
     return mZeroTime;
   }
   // Bug 1155008 - nsHttpTransaction is racy. Return DomainLookupStart when null
   return mDomainLookupEnd.IsNull() ? DomainLookupStartHighRes()
-                                   : TimeStampToDOMHighRes(mDomainLookupEnd);
+                                   : nsRFPService::ReduceTimePrecisionAsMSecs(
+                                       TimeStampToDOMHighRes(mDomainLookupEnd));
 }
 
 DOMTimeMilliSec
 PerformanceTiming::DomainLookupEnd()
 {
   return static_cast<int64_t>(DomainLookupEndHighRes());
 }
 
 DOMHighResTimeStamp
 PerformanceTiming::ConnectStartHighRes()
 {
   if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized() ||
       nsContentUtils::ShouldResistFingerprinting()) {
     return mZeroTime;
   }
   return mConnectStart.IsNull() ? DomainLookupEndHighRes()
-                                : TimeStampToDOMHighRes(mConnectStart);
+                                : nsRFPService::ReduceTimePrecisionAsMSecs(
+                                    TimeStampToDOMHighRes(mConnectStart));
 }
 
 DOMTimeMilliSec
 PerformanceTiming::ConnectStart()
 {
   return static_cast<int64_t>(ConnectStartHighRes());
 }
 
@@ -386,17 +391,18 @@ PerformanceTiming::SecureConnectionStart
   if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized() ||
       nsContentUtils::ShouldResistFingerprinting()) {
     return mZeroTime;
   }
   return !mSecureConnection
     ? 0 // We use 0 here, because mZeroTime is sometimes set to the navigation
         // start time.
     : (mSecureConnectionStart.IsNull() ? mZeroTime
-                                       : TimeStampToDOMHighRes(mSecureConnectionStart));
+                                       : nsRFPService::ReduceTimePrecisionAsMSecs(
+                                           TimeStampToDOMHighRes(mSecureConnectionStart)));
 }
 
 DOMTimeMilliSec
 PerformanceTiming::SecureConnectionStart()
 {
   return static_cast<int64_t>(SecureConnectionStartHighRes());
 }
 
@@ -404,17 +410,18 @@ DOMHighResTimeStamp
 PerformanceTiming::ConnectEndHighRes()
 {
   if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized() ||
       nsContentUtils::ShouldResistFingerprinting()) {
     return mZeroTime;
   }
   // Bug 1155008 - nsHttpTransaction is racy. Return ConnectStart when null
   return mConnectEnd.IsNull() ? ConnectStartHighRes()
-                              : TimeStampToDOMHighRes(mConnectEnd);
+                              : nsRFPService::ReduceTimePrecisionAsMSecs(
+                                  TimeStampToDOMHighRes(mConnectEnd));
 }
 
 DOMTimeMilliSec
 PerformanceTiming::ConnectEnd()
 {
   return static_cast<int64_t>(ConnectEndHighRes());
 }
 
@@ -425,17 +432,18 @@ PerformanceTiming::RequestStartHighRes()
       nsContentUtils::ShouldResistFingerprinting()) {
     return mZeroTime;
   }
 
   if (mRequestStart.IsNull()) {
     mRequestStart = mWorkerRequestStart;
   }
 
-  return TimeStampToDOMHighResOrFetchStart(mRequestStart);
+  return nsRFPService::ReduceTimePrecisionAsMSecs(
+    TimeStampToDOMHighResOrFetchStart(mRequestStart));
 }
 
 DOMTimeMilliSec
 PerformanceTiming::RequestStart()
 {
   return static_cast<int64_t>(RequestStartHighRes());
 }
 
@@ -450,17 +458,18 @@ PerformanceTiming::ResponseStartHighRes(
      (!mCacheReadStart.IsNull() && mCacheReadStart < mResponseStart)) {
     mResponseStart = mCacheReadStart;
   }
 
   if (mResponseStart.IsNull() ||
       (!mRequestStart.IsNull() && mResponseStart < mRequestStart)) {
     mResponseStart = mRequestStart;
   }
-  return TimeStampToDOMHighResOrFetchStart(mResponseStart);
+  return nsRFPService::ReduceTimePrecisionAsMSecs(
+    TimeStampToDOMHighResOrFetchStart(mResponseStart));
 }
 
 DOMTimeMilliSec
 PerformanceTiming::ResponseStart()
 {
   return static_cast<int64_t>(ResponseStartHighRes());
 }
 
@@ -475,17 +484,18 @@ PerformanceTiming::ResponseEndHighRes()
      (!mCacheReadEnd.IsNull() && mCacheReadEnd < mResponseEnd)) {
     mResponseEnd = mCacheReadEnd;
   }
   if (mResponseEnd.IsNull()) {
     mResponseEnd = mWorkerResponseEnd;
   }
   // Bug 1155008 - nsHttpTransaction is racy. Return ResponseStart when null
   return mResponseEnd.IsNull() ? ResponseStartHighRes()
-                               : TimeStampToDOMHighRes(mResponseEnd);
+                               : nsRFPService::ReduceTimePrecisionAsMSecs(
+                                   TimeStampToDOMHighRes(mResponseEnd));
 }
 
 DOMTimeMilliSec
 PerformanceTiming::ResponseEnd()
 {
   return static_cast<int64_t>(ResponseEndHighRes());
 }
 
--- a/dom/performance/PerformanceTiming.h
+++ b/dom/performance/PerformanceTiming.h
@@ -5,16 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_PerformanceTiming_h
 #define mozilla_dom_PerformanceTiming_h
 
 #include "mozilla/Attributes.h"
 #include "nsContentUtils.h"
 #include "nsDOMNavigationTiming.h"
+#include "nsRFPService.h"
 #include "nsWrapperCache.h"
 #include "Performance.h"
 
 class nsIHttpChannel;
 class nsITimedChannel;
 
 namespace mozilla {
 namespace dom {
@@ -102,48 +103,52 @@ public:
    * 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;
+    return nsRFPService::ReduceTimePrecisionAsMSecs(
+      duration.ToMilliseconds() + mZeroTime);
   }
 
   virtual JSObject* WrapObject(JSContext *cx,
                                JS::Handle<JSObject*> aGivenProto) override;
 
   // PerformanceNavigation WebIDL methods
   DOMTimeMilliSec NavigationStart() const
   {
     if (!nsContentUtils::IsPerformanceTimingEnabled() ||
         nsContentUtils::ShouldResistFingerprinting()) {
       return 0;
     }
-    return GetDOMTiming()->GetNavigationStart();
+    return nsRFPService::ReduceTimePrecisionAsMSecs(
+      GetDOMTiming()->GetNavigationStart());
   }
 
   DOMTimeMilliSec UnloadEventStart()
   {
     if (!nsContentUtils::IsPerformanceTimingEnabled() ||
         nsContentUtils::ShouldResistFingerprinting()) {
       return 0;
     }
-    return GetDOMTiming()->GetUnloadEventStart();
+    return nsRFPService::ReduceTimePrecisionAsMSecs(
+      GetDOMTiming()->GetUnloadEventStart());
   }
 
   DOMTimeMilliSec UnloadEventEnd()
   {
     if (!nsContentUtils::IsPerformanceTimingEnabled() ||
         nsContentUtils::ShouldResistFingerprinting()) {
       return 0;
     }
-    return GetDOMTiming()->GetUnloadEventEnd();
+    return nsRFPService::ReduceTimePrecisionAsMSecs(
+      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);
@@ -189,80 +194,88 @@ public:
   DOMTimeMilliSec ResponseEnd();
 
   DOMTimeMilliSec DomLoading()
   {
     if (!nsContentUtils::IsPerformanceTimingEnabled() ||
         nsContentUtils::ShouldResistFingerprinting()) {
       return 0;
     }
-    return GetDOMTiming()->GetDomLoading();
+    return nsRFPService::ReduceTimePrecisionAsMSecs(
+      GetDOMTiming()->GetDomLoading());
   }
 
   DOMTimeMilliSec DomInteractive() const
   {
     if (!nsContentUtils::IsPerformanceTimingEnabled() ||
         nsContentUtils::ShouldResistFingerprinting()) {
       return 0;
     }
-    return GetDOMTiming()->GetDomInteractive();
+    return nsRFPService::ReduceTimePrecisionAsMSecs(
+      GetDOMTiming()->GetDomInteractive());
   }
 
   DOMTimeMilliSec DomContentLoadedEventStart() const
   {
     if (!nsContentUtils::IsPerformanceTimingEnabled() ||
         nsContentUtils::ShouldResistFingerprinting()) {
       return 0;
     }
-    return GetDOMTiming()->GetDomContentLoadedEventStart();
+    return nsRFPService::ReduceTimePrecisionAsMSecs(
+      GetDOMTiming()->GetDomContentLoadedEventStart());
   }
 
   DOMTimeMilliSec DomContentLoadedEventEnd() const
   {
     if (!nsContentUtils::IsPerformanceTimingEnabled() ||
         nsContentUtils::ShouldResistFingerprinting()) {
       return 0;
     }
-    return GetDOMTiming()->GetDomContentLoadedEventEnd();
+    return nsRFPService::ReduceTimePrecisionAsMSecs(
+      GetDOMTiming()->GetDomContentLoadedEventEnd());
   }
 
   DOMTimeMilliSec DomComplete() const
   {
     if (!nsContentUtils::IsPerformanceTimingEnabled() ||
         nsContentUtils::ShouldResistFingerprinting()) {
       return 0;
     }
-    return GetDOMTiming()->GetDomComplete();
+    return nsRFPService::ReduceTimePrecisionAsMSecs(
+      GetDOMTiming()->GetDomComplete());
   }
 
   DOMTimeMilliSec LoadEventStart() const
   {
     if (!nsContentUtils::IsPerformanceTimingEnabled() ||
         nsContentUtils::ShouldResistFingerprinting()) {
       return 0;
     }
-    return GetDOMTiming()->GetLoadEventStart();
+    return nsRFPService::ReduceTimePrecisionAsMSecs(
+      GetDOMTiming()->GetLoadEventStart());
   }
 
   DOMTimeMilliSec LoadEventEnd() const
   {
     if (!nsContentUtils::IsPerformanceTimingEnabled() ||
         nsContentUtils::ShouldResistFingerprinting()) {
       return 0;
     }
-    return GetDOMTiming()->GetLoadEventEnd();
+    return nsRFPService::ReduceTimePrecisionAsMSecs(
+      GetDOMTiming()->GetLoadEventEnd());
   }
 
   DOMTimeMilliSec TimeToNonBlankPaint() const
   {
     if (!nsContentUtils::IsPerformanceTimingEnabled() ||
         nsContentUtils::ShouldResistFingerprinting()) {
       return 0;
     }
-    return GetDOMTiming()->GetTimeToNonBlankPaint();
+    return nsRFPService::ReduceTimePrecisionAsMSecs(
+      GetDOMTiming()->GetTimeToNonBlankPaint());
   }
 
 private:
   ~PerformanceTiming();
 
   bool IsInitialized() const;
   void InitializeTimingInfo(nsITimedChannel* aChannel);