Bug 1423495 - Part4: Create doc entry form http channel if server timing headers are found for a document load r=baku
authorKershaw Chang <kechang@mozilla.com>, Valentin Gosu <valentin.gosu@gmail.com>
Fri, 12 Jan 2018 03:13:00 +0100
changeset 468820 11804549931f5e8e2e71c5bcdd3221b41e8d54d8
parent 468819 d06281128204219694c0770acc0d0ec928d6647f
child 468821 26e3cf3458025c17087b0219dea9064af67f1d80
push id9165
push userasasaki@mozilla.com
push dateThu, 26 Apr 2018 21:04:54 +0000
treeherdermozilla-beta@064c3804de2e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbaku
bugs1423495
milestone61.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1423495 - Part4: Create doc entry form http channel if server timing headers are found for a document load r=baku Currently, the document entry is created at the first time when some JS code tries to access it. But for the case when server timing headers exist for a document loading channel, we need to create the document entry and save the server timing data in the document entry. If we don’t do this, the server timing data would be lost since the http channel will be deleted. MozReview-Commit-ID: B5ksAZvZACq
dom/performance/PerformanceMainThread.cpp
dom/performance/PerformanceMainThread.h
dom/performance/PerformanceStorage.h
dom/performance/PerformanceStorageWorker.h
netwerk/protocol/http/HttpBaseChannel.cpp
netwerk/protocol/http/HttpBaseChannel.h
netwerk/protocol/http/HttpChannelChild.cpp
netwerk/protocol/http/InterceptedHttpChannel.cpp
netwerk/protocol/http/nsHttpChannel.cpp
--- a/dom/performance/PerformanceMainThread.cpp
+++ b/dom/performance/PerformanceMainThread.cpp
@@ -292,16 +292,30 @@ PerformanceMainThread::EnsureDocEntry()
     if (httpChannel) {
       timing->SetPropertiesFromHttpChannel(httpChannel);
     }
 
     mDocEntry = new PerformanceNavigationTiming(Move(timing), this);
   }
 }
 
+void
+PerformanceMainThread::CreateDocumentEntry(nsITimedChannel* aChannel)
+{
+  MOZ_ASSERT(aChannel);
+  MOZ_ASSERT(!mDocEntry, "mDocEntry should be null.");
+
+  if (!nsContentUtils::IsPerformanceNavigationTimingEnabled()) {
+    return;
+  }
+
+  UniquePtr<PerformanceTimingData> timing(
+      new PerformanceTimingData(aChannel, nullptr, 0));
+  mDocEntry = new PerformanceNavigationTiming(Move(timing), this);
+}
 
 void
 PerformanceMainThread::GetEntries(nsTArray<RefPtr<PerformanceEntry>>& aRetval)
 {
   // We return an empty list when 'privacy.resistFingerprinting' is on.
   if (nsContentUtils::ShouldResistFingerprinting()) {
     aRetval.Clear();
     return;
--- a/dom/performance/PerformanceMainThread.h
+++ b/dom/performance/PerformanceMainThread.h
@@ -32,16 +32,18 @@ public:
 
   virtual PerformanceTiming* Timing() override;
 
   virtual PerformanceNavigation* Navigation() override;
 
   virtual void AddEntry(nsIHttpChannel* channel,
                         nsITimedChannel* timedChannel) override;
 
+  void CreateDocumentEntry(nsITimedChannel* aChannel) override;
+
   TimeStamp CreationTimeStamp() const override;
 
   DOMHighResTimeStamp CreationTime() const override;
 
   virtual void GetMozMemory(JSContext *aCx,
                             JS::MutableHandle<JSObject*> aObj) override;
 
   virtual nsDOMNavigationTiming* GetDOMTiming() const override
--- a/dom/performance/PerformanceStorage.h
+++ b/dom/performance/PerformanceStorage.h
@@ -20,16 +20,18 @@ class PerformanceTimingData;
 class PerformanceStorage
 {
 public:
   NS_INLINE_DECL_PURE_VIRTUAL_REFCOUNTING
 
   virtual void AddEntry(nsIHttpChannel* aChannel,
                         nsITimedChannel* aTimedChannel) = 0;
 
+  virtual void CreateDocumentEntry(nsITimedChannel* aChannel) = 0;
+
 protected:
   virtual ~PerformanceStorage() {}
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_PerformanceStorage_h
--- a/dom/performance/PerformanceStorageWorker.h
+++ b/dom/performance/PerformanceStorageWorker.h
@@ -25,16 +25,21 @@ public:
   static already_AddRefed<PerformanceStorageWorker>
   Create(WorkerPrivate* aWorkerPrivate);
 
   void ShutdownOnWorker();
 
   void AddEntry(nsIHttpChannel* aChannel,
                 nsITimedChannel* aTimedChannel) override;
 
+  void CreateDocumentEntry(nsITimedChannel* aChannel) override
+  {
+    MOZ_CRASH("This should not be called on workers.");
+  }
+
   void AddEntryOnWorker(UniquePtr<PerformanceProxyData>&& aData);
 
 private:
   PerformanceStorageWorker();
   ~PerformanceStorageWorker();
 
   Mutex mMutex;
 
--- a/netwerk/protocol/http/HttpBaseChannel.cpp
+++ b/netwerk/protocol/http/HttpBaseChannel.cpp
@@ -4245,21 +4245,16 @@ HttpBaseChannel::GetPerformanceStorage()
   }
 
   // If a custom performance storage is set, let's use it.
   mozilla::dom::PerformanceStorage* performanceStorage = mLoadInfo->GetPerformanceStorage();
   if (performanceStorage) {
     return performanceStorage;
   }
 
-  // We don't need to report the resource timing entry for a TYPE_DOCUMENT load.
-  if (mLoadInfo->GetExternalContentPolicyType() == nsIContentPolicy::TYPE_DOCUMENT) {
-    return nullptr;
-  }
-
   nsCOMPtr<nsIDOMDocument> domDocument;
   mLoadInfo->GetLoadingDocument(getter_AddRefs(domDocument));
   if (!domDocument) {
     return nullptr;
   }
 
   nsCOMPtr<nsIDocument> loadingDocument = do_QueryInterface(domDocument);
   if (!loadingDocument) {
@@ -4282,16 +4277,41 @@ HttpBaseChannel::GetPerformanceStorage()
   mozilla::dom::Performance* performance = innerWindow->GetPerformance();
   if (!performance) {
     return nullptr;
   }
 
   return performance->AsPerformanceStorage();
 }
 
+void
+HttpBaseChannel::MaybeReportTimingData()
+{
+  // We don't need to report the resource timing entry for a TYPE_DOCUMENT load.
+  // But for the case that Server-Timing headers are existed for
+  // a document load, we have to create the document entry early
+  // with the timed channel. This is the only way to make
+  // server timing data availeble in the document entry.
+  if (mLoadInfo->GetExternalContentPolicyType() == nsIContentPolicy::TYPE_DOCUMENT) {
+    if ((mResponseHead && mResponseHead->HasHeader(nsHttp::Server_Timing)) ||
+        (mResponseTrailers && mResponseTrailers->HasHeader(nsHttp::Server_Timing))) {
+      mozilla::dom::PerformanceStorage* documentPerformance = GetPerformanceStorage();
+      if (documentPerformance) {
+        documentPerformance->CreateDocumentEntry(this);
+      }
+    }
+    return;
+  }
+
+  mozilla::dom::PerformanceStorage* documentPerformance = GetPerformanceStorage();
+  if (documentPerformance) {
+      documentPerformance->AddEntry(this, this);
+  }
+}
+
 NS_IMETHODIMP
 HttpBaseChannel::SetReportResourceTiming(bool enabled) {
   mReportTiming = enabled;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 HttpBaseChannel::GetReportResourceTiming(bool* _retval) {
--- a/netwerk/protocol/http/HttpBaseChannel.h
+++ b/netwerk/protocol/http/HttpBaseChannel.h
@@ -424,16 +424,17 @@ protected:
 
   // This is fired only when a cookie is created due to the presence of
   // Set-Cookie header in the response header of any network request.
   // This notification will come only after the "http-on-examine-response"
   // was fired.
   void NotifySetCookie(char const *aCookie);
 
   mozilla::dom::PerformanceStorage* GetPerformanceStorage();
+  void MaybeReportTimingData();
   nsIURI* GetReferringPage();
   nsPIDOMWindowInner* GetInnerDOMWindow();
 
   void AddCookiesToRequest();
   virtual MOZ_MUST_USE nsresult
   SetupReplacementChannel(nsIURI *, nsIChannel *, bool preserveMethod,
                           uint32_t redirectFlags);
 
--- a/netwerk/protocol/http/HttpChannelChild.cpp
+++ b/netwerk/protocol/http/HttpChannelChild.cpp
@@ -1208,20 +1208,17 @@ void
 HttpChannelChild::DoPreOnStopRequest(nsresult aStatus)
 {
   LOG(("HttpChannelChild::DoPreOnStopRequest [this=%p status=%" PRIx32 "]\n",
        this, static_cast<uint32_t>(aStatus)));
   mIsPending = false;
 
   MaybeCallSynthesizedCallback();
 
-  PerformanceStorage* performanceStorage = GetPerformanceStorage();
-  if (performanceStorage) {
-      performanceStorage->AddEntry(this, this);
-  }
+  MaybeReportTimingData();
 
   if (!mCanceled && NS_SUCCEEDED(mStatus)) {
     mStatus = aStatus;
   }
 
   CollectOMTTelemetry();
 }
 
--- a/netwerk/protocol/http/InterceptedHttpChannel.cpp
+++ b/netwerk/protocol/http/InterceptedHttpChannel.cpp
@@ -1079,20 +1079,17 @@ InterceptedHttpChannel::OnStopRequest(ns
   // progress when OnStopRequest() is triggered.  Report any left over
   // progress immediately.  The extra runnable will then do nothing thanks
   // to the ReleaseListeners() call below.
   MaybeCallStatusAndProgress();
 
   mIsPending = false;
 
   // Register entry to the PerformanceStorage resource timing
-  mozilla::dom::PerformanceStorage* performanceStorage = GetPerformanceStorage();
-  if (performanceStorage) {
-    performanceStorage->AddEntry(this, this);
-  }
+  MaybeReportTimingData();
 
   if (mListener) {
     mListener->OnStopRequest(this, mListenerContext, mStatus);
   }
 
   gHttpHandler->OnStopRequest(this);
 
   ReleaseListeners();
--- a/netwerk/protocol/http/nsHttpChannel.cpp
+++ b/netwerk/protocol/http/nsHttpChannel.cpp
@@ -7426,20 +7426,17 @@ nsHttpChannel::OnStopRequest(nsIRequest 
                      static_cast<uint32_t>(rv)));
             }
         }
     }
 
     ReportRcwnStats(isFromNet);
 
     // Register entry to the PerformanceStorage resource timing
-    mozilla::dom::PerformanceStorage* performanceStorage = GetPerformanceStorage();
-    if (performanceStorage) {
-        performanceStorage->AddEntry(this, this);
-    }
+    MaybeReportTimingData();
 
     if (mListener) {
         LOG(("nsHttpChannel %p calling OnStopRequest\n", this));
         MOZ_ASSERT(mOnStartRequestCalled,
                    "OnStartRequest should be called before OnStopRequest");
         MOZ_ASSERT(!mOnStopRequestCalled,
                    "We should not call OnStopRequest twice");
         mListener->OnStopRequest(this, mListenerContext, status);