Bug 1064706 - Save timing info in nsPerformanceTiming to avoid keeping a ref to the channel. r=bz, a=lsblakk
authorValentin Gosu <valentin.gosu@gmail.com>
Tue, 21 Oct 2014 15:49:40 +0300
changeset 233553 ae1d3d25aec3bae5d031cfa5565c2639720f50c1
parent 233552 f3f48b61e7d6ea96ed5b4459750a2b68c609a89b
child 233554 3a36eb03ce30e8259a93371e90d47011c344fa3a
push id1
push usersledru@mozilla.com
push dateThu, 04 Dec 2014 17:57:20 +0000
reviewersbz, lsblakk
bugs1064706
milestone35.0a2
Bug 1064706 - Save timing info in nsPerformanceTiming to avoid keeping a ref to the channel. r=bz, a=lsblakk
dom/base/nsPerformance.cpp
dom/base/nsPerformance.h
--- a/dom/base/nsPerformance.cpp
+++ b/dom/base/nsPerformance.cpp
@@ -28,123 +28,143 @@ NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(ns
 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(nsPerformanceTiming, AddRef)
 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(nsPerformanceTiming, Release)
 
 nsPerformanceTiming::nsPerformanceTiming(nsPerformance* aPerformance,
                                          nsITimedChannel* aChannel,
                                          nsIHttpChannel* aHttpChannel,
                                          DOMHighResTimeStamp aZeroTime)
   : mPerformance(aPerformance),
-    mChannel(aChannel),
     mFetchStart(0.0),
     mZeroTime(aZeroTime),
+    mRedirectCount(0),
     mTimingAllowed(true),
+    mAllRedirectsSameOrigin(true),
+    mInitialized(!!aChannel),
     mReportCrossOriginRedirect(true)
 {
   MOZ_ASSERT(aPerformance, "Parent performance object should be provided");
 
   if (!nsContentUtils::IsPerformanceTimingEnabled()) {
     mZeroTime = 0;
   }
 
   // The aHttpChannel argument is null if this nsPerformanceTiming object
   // is being used for the navigation timing (document) and has a non-null
   // value for the resource timing (any resources within the page).
   if (aHttpChannel) {
-    mTimingAllowed = CheckAllowedOrigin(aHttpChannel);
+    mTimingAllowed = CheckAllowedOrigin(aHttpChannel, aChannel);
     bool redirectsPassCheck = false;
-    mChannel->GetAllRedirectsPassTimingAllowCheck(&redirectsPassCheck);
+    aChannel->GetAllRedirectsPassTimingAllowCheck(&redirectsPassCheck);
     mReportCrossOriginRedirect = mTimingAllowed && redirectsPassCheck;
   }
+
+  InitializeTimingInfo(aChannel);
+}
+
+// Copy the timing info from the channel so we don't need to keep the channel
+// alive just to get the timestamps.
+void
+nsPerformanceTiming::InitializeTimingInfo(nsITimedChannel* aChannel)
+{
+  if (aChannel) {
+    aChannel->GetAsyncOpen(&mAsyncOpen);
+    aChannel->GetAllRedirectsSameOrigin(&mAllRedirectsSameOrigin);
+    aChannel->GetRedirectCount(&mRedirectCount);
+    aChannel->GetRedirectStart(&mRedirectStart);
+    aChannel->GetRedirectEnd(&mRedirectEnd);
+    aChannel->GetDomainLookupStart(&mDomainLookupStart);
+    aChannel->GetDomainLookupEnd(&mDomainLookupEnd);
+    aChannel->GetConnectStart(&mConnectStart);
+    aChannel->GetConnectEnd(&mConnectEnd);
+    aChannel->GetRequestStart(&mRequestStart);
+    aChannel->GetResponseStart(&mResponseStart);
+    aChannel->GetCacheReadStart(&mCacheReadStart);
+    aChannel->GetResponseEnd(&mResponseEnd);
+    aChannel->GetCacheReadEnd(&mCacheReadEnd);
+  }
 }
 
 nsPerformanceTiming::~nsPerformanceTiming()
 {
 }
 
 DOMHighResTimeStamp
 nsPerformanceTiming::FetchStartHighRes()
 {
   if (!mFetchStart) {
     if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized()) {
       return mZeroTime;
     }
-    TimeStamp stamp;
-    mChannel->GetAsyncOpen(&stamp);
-    MOZ_ASSERT(!stamp.IsNull(), "The fetch start time stamp should always be "
+    MOZ_ASSERT(!mAsyncOpen.IsNull(), "The fetch start time stamp should always be "
         "valid if the performance timing is enabled");
-    mFetchStart = (!stamp.IsNull())
-        ? TimeStampToDOMHighRes(stamp)
+    mFetchStart = (!mAsyncOpen.IsNull())
+        ? TimeStampToDOMHighRes(mAsyncOpen)
         : 0.0;
   }
   return mFetchStart;
 }
 
 DOMTimeMilliSec
 nsPerformanceTiming::FetchStart()
 {
   return static_cast<int64_t>(FetchStartHighRes());
 }
 
 bool
-nsPerformanceTiming::CheckAllowedOrigin(nsIHttpChannel* aResourceChannel)
+nsPerformanceTiming::CheckAllowedOrigin(nsIHttpChannel* aResourceChannel,
+                                        nsITimedChannel* aChannel)
 {
   if (!IsInitialized()) {
     return false;
   }
 
   // Check that the current document passes the ckeck.
   nsCOMPtr<nsILoadInfo> loadInfo;
   aResourceChannel->GetLoadInfo(getter_AddRefs(loadInfo));
   if (!loadInfo) {
     return false;
   }
   nsCOMPtr<nsIPrincipal> principal = loadInfo->LoadingPrincipal();
 
   // Check if the resource is either same origin as the page that started
   // the load, or if the response contains the proper Timing-Allow-Origin
   // header with the domain of the page that started the load.
-  return mChannel->TimingAllowCheck(principal);
+  return aChannel->TimingAllowCheck(principal);
 }
 
 bool
 nsPerformanceTiming::TimingAllowed() const
 {
   return mTimingAllowed;
 }
 
 uint16_t
 nsPerformanceTiming::GetRedirectCount() const
 {
   if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized()) {
     return 0;
   }
-  bool sameOrigin;
-  mChannel->GetAllRedirectsSameOrigin(&sameOrigin);
-  if (!sameOrigin) {
+  if (!mAllRedirectsSameOrigin) {
     return 0;
   }
-  uint16_t redirectCount;
-  mChannel->GetRedirectCount(&redirectCount);
-  return redirectCount;
+  return mRedirectCount;
 }
 
 bool
 nsPerformanceTiming::ShouldReportCrossOriginRedirect() const
 {
   if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized()) {
     return false;
   }
 
   // If the redirect count is 0, or if one of the cross-origin
   // redirects doesn't have the proper Timing-Allow-Origin header,
   // then RedirectStart and RedirectEnd will be set to zero
-  uint16_t redirectCount;
-  mChannel->GetRedirectCount(&redirectCount);
-  return (redirectCount != 0) && mReportCrossOriginRedirect;
+  return (mRedirectCount != 0) && mReportCrossOriginRedirect;
 }
 
 /**
  * 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 (nsPerformanceTiming::RedirectStart()
@@ -153,32 +173,28 @@ nsPerformanceTiming::ShouldReportCrossOr
  * @return a valid timing if the Performance Timing is enabled
  */
 DOMHighResTimeStamp
 nsPerformanceTiming::RedirectStartHighRes()
 {
   if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized()) {
     return mZeroTime;
   }
-  mozilla::TimeStamp stamp;
-  mChannel->GetRedirectStart(&stamp);
-  return TimeStampToDOMHighResOrFetchStart(stamp);
+  return TimeStampToDOMHighResOrFetchStart(mRedirectStart);
 }
 
 DOMTimeMilliSec
 nsPerformanceTiming::RedirectStart()
 {
   if (!IsInitialized()) {
     return mZeroTime;
   }
   // We have to check if all the redirect URIs had the same origin (since there
   // is no check in RedirectStartHighRes())
-  bool sameOrigin;
-  mChannel->GetAllRedirectsSameOrigin(&sameOrigin);
-  if (sameOrigin) {
+  if (mAllRedirectsSameOrigin) {
     return static_cast<int64_t>(RedirectStartHighRes());
   }
   return 0;
 }
 
 /**
  * RedirectEndHighRes() is used by both the navigation timing and the resource
  * timing. Since, navigation timing and resource timing check and interpret
@@ -190,170 +206,150 @@ nsPerformanceTiming::RedirectStart()
  * @return a valid timing if the Performance Timing is enabled
  */
 DOMHighResTimeStamp
 nsPerformanceTiming::RedirectEndHighRes()
 {
   if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized()) {
     return mZeroTime;
   }
-  mozilla::TimeStamp stamp;
-  mChannel->GetRedirectEnd(&stamp);
-  return TimeStampToDOMHighResOrFetchStart(stamp);
+  return TimeStampToDOMHighResOrFetchStart(mRedirectEnd);
 }
 
 DOMTimeMilliSec
 nsPerformanceTiming::RedirectEnd()
 {
   if (!IsInitialized()) {
     return mZeroTime;
   }
   // We have to check if all the redirect URIs had the same origin (since there
   // is no check in RedirectEndHighRes())
-  bool sameOrigin;
-  mChannel->GetAllRedirectsSameOrigin(&sameOrigin);
-  if (sameOrigin) {
+  if (mAllRedirectsSameOrigin) {
     return static_cast<int64_t>(RedirectEndHighRes());
   }
   return 0;
 }
 
 DOMHighResTimeStamp
 nsPerformanceTiming::DomainLookupStartHighRes()
 {
   if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized()) {
     return mZeroTime;
   }
-  mozilla::TimeStamp stamp;
-  mChannel->GetDomainLookupStart(&stamp);
-  return TimeStampToDOMHighResOrFetchStart(stamp);
+  return TimeStampToDOMHighResOrFetchStart(mDomainLookupStart);
 }
 
 DOMTimeMilliSec
 nsPerformanceTiming::DomainLookupStart()
 {
   return static_cast<int64_t>(DomainLookupStartHighRes());
 }
 
 DOMHighResTimeStamp
 nsPerformanceTiming::DomainLookupEndHighRes()
 {
   if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized()) {
     return mZeroTime;
   }
-  mozilla::TimeStamp stamp;
-  mChannel->GetDomainLookupEnd(&stamp);
-  return TimeStampToDOMHighResOrFetchStart(stamp);
+  return TimeStampToDOMHighResOrFetchStart(mDomainLookupEnd);
 }
 
 DOMTimeMilliSec
 nsPerformanceTiming::DomainLookupEnd()
 {
   return static_cast<int64_t>(DomainLookupEndHighRes());
 }
 
 DOMHighResTimeStamp
 nsPerformanceTiming::ConnectStartHighRes()
 {
   if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized()) {
     return mZeroTime;
   }
-  mozilla::TimeStamp stamp;
-  mChannel->GetConnectStart(&stamp);
-  return TimeStampToDOMHighResOrFetchStart(stamp);
+  return TimeStampToDOMHighResOrFetchStart(mConnectStart);
 }
 
 DOMTimeMilliSec
 nsPerformanceTiming::ConnectStart()
 {
   return static_cast<int64_t>(ConnectStartHighRes());
 }
 
 DOMHighResTimeStamp
 nsPerformanceTiming::ConnectEndHighRes()
 {
   if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized()) {
     return mZeroTime;
   }
-  mozilla::TimeStamp stamp;
-  mChannel->GetConnectEnd(&stamp);
-  return TimeStampToDOMHighResOrFetchStart(stamp);
+  return TimeStampToDOMHighResOrFetchStart(mConnectEnd);
 }
 
 DOMTimeMilliSec
 nsPerformanceTiming::ConnectEnd()
 {
   return static_cast<int64_t>(ConnectEndHighRes());
 }
 
 DOMHighResTimeStamp
 nsPerformanceTiming::RequestStartHighRes()
 {
   if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized()) {
     return mZeroTime;
   }
-  mozilla::TimeStamp stamp;
-  mChannel->GetRequestStart(&stamp);
-  return TimeStampToDOMHighResOrFetchStart(stamp);
+  return TimeStampToDOMHighResOrFetchStart(mRequestStart);
 }
 
 DOMTimeMilliSec
 nsPerformanceTiming::RequestStart()
 {
   return static_cast<int64_t>(RequestStartHighRes());
 }
 
 DOMHighResTimeStamp
 nsPerformanceTiming::ResponseStartHighRes()
 {
   if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized()) {
     return mZeroTime;
   }
-  mozilla::TimeStamp stamp;
-  mChannel->GetResponseStart(&stamp);
-  mozilla::TimeStamp cacheStamp;
-  mChannel->GetCacheReadStart(&cacheStamp);
-  if (stamp.IsNull() || (!cacheStamp.IsNull() && cacheStamp < stamp)) {
-    stamp = cacheStamp;
+  if (mResponseStart.IsNull() ||
+     (!mCacheReadStart.IsNull() && mCacheReadStart < mResponseStart)) {
+    mResponseStart = mCacheReadStart;
   }
-  return TimeStampToDOMHighResOrFetchStart(stamp);
+  return TimeStampToDOMHighResOrFetchStart(mResponseStart);
 }
 
 DOMTimeMilliSec
 nsPerformanceTiming::ResponseStart()
 {
   return static_cast<int64_t>(ResponseStartHighRes());
 }
 
 DOMHighResTimeStamp
 nsPerformanceTiming::ResponseEndHighRes()
 {
   if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized()) {
     return mZeroTime;
   }
-  mozilla::TimeStamp stamp;
-  mChannel->GetResponseEnd(&stamp);
-  mozilla::TimeStamp cacheStamp;
-  mChannel->GetCacheReadEnd(&cacheStamp);
-  if (stamp.IsNull() || (!cacheStamp.IsNull() && cacheStamp < stamp)) {
-    stamp = cacheStamp;
+  if (mResponseEnd.IsNull() ||
+     (!mCacheReadEnd.IsNull() && mCacheReadEnd < mResponseEnd)) {
+    mResponseEnd = mCacheReadEnd;
   }
-  return TimeStampToDOMHighResOrFetchStart(stamp);
+  return TimeStampToDOMHighResOrFetchStart(mResponseEnd);
 }
 
 DOMTimeMilliSec
 nsPerformanceTiming::ResponseEnd()
 {
   return static_cast<int64_t>(ResponseEndHighRes());
 }
 
 bool
 nsPerformanceTiming::IsInitialized() const
 {
-  return !!mChannel;
+  return mInitialized;
 }
 
 JSObject*
 nsPerformanceTiming::WrapObject(JSContext *cx)
 {
   return dom::PerformanceTimingBinding::Wrap(cx, this);
 }
 
--- a/dom/base/nsPerformance.h
+++ b/dom/base/nsPerformance.h
@@ -137,17 +137,17 @@ public:
     }
     return GetDOMTiming()->GetUnloadEventEnd();
   }
 
   uint16_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);
+  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;
@@ -217,25 +217,41 @@ public:
       return 0;
     }
     return GetDOMTiming()->GetLoadEventEnd();
   }
 
 private:
   ~nsPerformanceTiming();
   bool IsInitialized() const;
+  void InitializeTimingInfo(nsITimedChannel* aChannel);
   nsRefPtr<nsPerformance> mPerformance;
-  nsCOMPtr<nsITimedChannel> mChannel;
   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 mConnectEnd;
+  TimeStamp mRequestStart;
+  TimeStamp mResponseStart;
+  TimeStamp mCacheReadStart;
+  TimeStamp mResponseEnd;
+  TimeStamp mCacheReadEnd;
+  uint16_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;
 };
 
 // Script "performance.navigation" object