Bug 1423495 - Part1: Implement PerformanceServerTiming, r=baku
authorKershaw Chang <kechang@mozilla.com>, Valentin Gosu <valentin.gosu@gmail.com>
Wed, 10 Jan 2018 04:01:00 +0100
changeset 471365 ecf85551434a3048a74ad259dc3164c440d10692
parent 471364 c7f6d061d06ca85fcb8e54946cd90ceb93a604d1
child 471366 ca970fc93a320009dadfa83a5ff28e122ead2bf4
push id1728
push userjlund@mozilla.com
push dateMon, 18 Jun 2018 21:12:27 +0000
treeherdermozilla-release@c296fde26f5f [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 - Part1: Implement PerformanceServerTiming, r=baku This patch: 1. Introduces PerformanceServerTiming.webidl. 2. Adds serverTiming in PerformanceResourceTiming.webidl. 3. Gets serverTiming data from nsITimedChannel and keeps it in the PerformanceTimng class. MozReview-Commit-ID: 9mkGkHbxopC
dom/performance/PerformanceResourceTiming.cpp
dom/performance/PerformanceResourceTiming.h
dom/performance/PerformanceServerTiming.cpp
dom/performance/PerformanceServerTiming.h
dom/performance/PerformanceTiming.cpp
dom/performance/PerformanceTiming.h
dom/performance/moz.build
dom/webidl/PerformanceResourceTiming.webidl
dom/webidl/PerformanceServerTiming.webidl
dom/webidl/moz.build
--- a/dom/performance/PerformanceResourceTiming.cpp
+++ b/dom/performance/PerformanceResourceTiming.cpp
@@ -2,16 +2,17 @@
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "PerformanceResourceTiming.h"
 #include "mozilla/dom/PerformanceResourceTimingBinding.h"
 #include "nsNetUtil.h"
+#include "nsArrayUtils.h"
 
 using namespace mozilla::dom;
 
 NS_IMPL_CYCLE_COLLECTION_INHERITED(PerformanceResourceTiming,
                                    PerformanceEntry,
                                    mPerformance)
 
 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(PerformanceResourceTiming,
@@ -82,16 +83,46 @@ PerformanceResourceTiming::SizeOfExcludi
 {
   return PerformanceEntry::SizeOfExcludingThis(aMallocSizeOf) +
          mInitiatorType.SizeOfExcludingThisIfUnshared(aMallocSizeOf) +
          (mTimingData
             ? mTimingData->NextHopProtocol().SizeOfExcludingThisIfUnshared(aMallocSizeOf)
             : 0);
 }
 
+void
+PerformanceResourceTiming::GetServerTiming(
+                            nsTArray<RefPtr<PerformanceServerTiming>>& aRetval,
+                            Maybe<nsIPrincipal*>& aSubjectPrincipal)
+{
+  aRetval.Clear();
+  if (!TimingAllowedForCaller(aSubjectPrincipal)) {
+    return;
+  }
+
+  nsCOMPtr<nsIArray> serverTimingArray = mTimingData->GetServerTiming();
+  if (!serverTimingArray) {
+    return;
+  }
+
+  uint32_t length = 0;
+  if (NS_WARN_IF(NS_FAILED(serverTimingArray->GetLength(&length)))) {
+    return;
+  }
+
+  for (uint32_t index = 0; index < length; ++index) {
+    nsCOMPtr<nsIServerTiming> serverTiming =
+      do_QueryElementAt(serverTimingArray, index);
+    MOZ_ASSERT(serverTiming);
+
+    aRetval.AppendElement(
+      new PerformanceServerTiming(GetParentObject(), serverTiming));
+  }
+}
+
 bool
 PerformanceResourceTiming::TimingAllowedForCaller(Maybe<nsIPrincipal*>& aCaller) const
 {
   if (!mTimingData) {
     return false;
   }
 
   if (mTimingData->TimingAllowed()) {
--- a/dom/performance/PerformanceResourceTiming.h
+++ b/dom/performance/PerformanceResourceTiming.h
@@ -6,16 +6,17 @@
 
 #ifndef mozilla_dom_PerformanceResourceTiming_h___
 #define mozilla_dom_PerformanceResourceTiming_h___
 
 #include "mozilla/UniquePtr.h"
 #include "nsCOMPtr.h"
 #include "Performance.h"
 #include "PerformanceEntry.h"
+#include "PerformanceServerTiming.h"
 #include "PerformanceTiming.h"
 
 namespace mozilla {
 namespace dom {
 
 // http://www.w3.org/TR/resource-timing/#performanceresourcetiming
 class PerformanceResourceTiming : public PerformanceEntry
 {
@@ -156,16 +157,19 @@ public:
 
   uint64_t DecodedBodySize(Maybe<nsIPrincipal*>& aSubjectPrincipal) const
   {
     return TimingAllowedForCaller(aSubjectPrincipal)
         ? mTimingData->DecodedBodySize()
         : 0;
   }
 
+  void GetServerTiming(nsTArray<RefPtr<PerformanceServerTiming>>& aRetval,
+                       Maybe<nsIPrincipal*>& aSubjectPrincipal);
+
   size_t
   SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const override;
 
 protected:
   virtual ~PerformanceResourceTiming();
 
   size_t
   SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const override;
new file mode 100644
--- /dev/null
+++ b/dom/performance/PerformanceServerTiming.cpp
@@ -0,0 +1,79 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "PerformanceServerTiming.h"
+
+#include "mozilla/dom/PerformanceServerTimingBinding.h"
+#include "nsITimedChannel.h"
+
+namespace mozilla {
+namespace dom {
+
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(PerformanceServerTiming, mParent)
+
+NS_IMPL_CYCLE_COLLECTING_ADDREF(PerformanceServerTiming)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(PerformanceServerTiming)
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(PerformanceServerTiming)
+  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
+  NS_INTERFACE_MAP_ENTRY(nsISupports)
+NS_INTERFACE_MAP_END
+
+JSObject*
+PerformanceServerTiming::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
+{
+  return mozilla::dom::PerformanceServerTimingBinding::Wrap(aCx, this, aGivenProto);
+}
+
+void
+PerformanceServerTiming::GetName(nsAString& aName) const
+{
+  aName.Truncate();
+
+  if (!mServerTiming) {
+    return;
+  }
+
+  nsAutoCString name;
+  if (NS_WARN_IF(NS_FAILED(mServerTiming->GetName(name)))) {
+    return;
+  }
+
+  aName.Assign(NS_ConvertUTF8toUTF16(name));
+}
+
+DOMHighResTimeStamp
+PerformanceServerTiming::Duration() const
+{
+  if (!mServerTiming) {
+    return 0;
+  }
+
+  double duration = 0;
+  if (NS_WARN_IF(NS_FAILED(mServerTiming->GetDuration(&duration)))) {
+    return 0;
+  }
+
+  return duration;
+}
+
+void
+PerformanceServerTiming::GetDescription(nsAString& aDescription) const
+{
+  if (!mServerTiming) {
+    return;
+  }
+
+  nsAutoCString description;
+  if (NS_WARN_IF(NS_FAILED(mServerTiming->GetDescription(description)))) {
+    return;
+  }
+
+  aDescription.Assign(NS_ConvertUTF8toUTF16(description));
+}
+
+} // dom namespace
+} // mozilla namespace
new file mode 100644
--- /dev/null
+++ b/dom/performance/PerformanceServerTiming.h
@@ -0,0 +1,58 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_PerformanceServerTiming_h
+#define mozilla_dom_PerformanceServerTiming_h
+
+#include "mozilla/Attributes.h"
+#include "nsWrapperCache.h"
+#include "nsString.h"
+
+class nsIServerTiming;
+class nsISupports;
+
+namespace mozilla {
+namespace dom {
+
+class PerformanceServerTiming final : public nsISupports,
+                                      public nsWrapperCache
+{
+public:
+  PerformanceServerTiming(nsISupports* aParent, nsIServerTiming* aServerTiming)
+    : mParent(aParent)
+    , mServerTiming(aServerTiming)
+  {
+    MOZ_ASSERT(mServerTiming);
+  }
+
+  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(PerformanceServerTiming)
+
+  JSObject*
+  WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
+
+  nsISupports* GetParentObject() const
+  {
+    return mParent;
+  }
+
+  void GetName(nsAString& aName) const;
+
+  DOMHighResTimeStamp Duration() const;
+
+  void GetDescription(nsAString& aDescription) const;
+
+private:
+  ~PerformanceServerTiming() = default;
+
+  nsCOMPtr<nsISupports> mParent;
+  nsCOMPtr<nsIServerTiming> mServerTiming;
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_PerformanceServerTiming_h
--- a/dom/performance/PerformanceTiming.cpp
+++ b/dom/performance/PerformanceTiming.cpp
@@ -157,16 +157,18 @@ PerformanceTimingData::PerformanceTiming
     aChannel->GetCacheReadEnd(&mCacheReadEnd);
 
     aChannel->GetDispatchFetchEventStart(&mWorkerStart);
     aChannel->GetHandleFetchEventStart(&mWorkerRequestStart);
     // TODO: Track when FetchEvent.respondWith() promise resolves as
     //       ServiceWorker interception responseStart?
     aChannel->GetHandleFetchEventEnd(&mWorkerResponseEnd);
 
+    aChannel->GetServerTiming(getter_AddRefs(mServerTiming));
+
     // The performance timing api essentially requires that the event timestamps
     // have a strict relation with each other. The truth, however, is the
     // browser engages in a number of speculative activities that sometimes mean
     // connections and lookups begin at different times. Workaround that here by
     // clamping these values to what we expect FetchStart to be.  This means the
     // later of AsyncOpen or WorkerStart times.
     if (!mAsyncOpen.IsNull()) {
       // We want to clamp to the expected FetchStart value.  This is later of
@@ -666,10 +668,23 @@ PerformanceTiming::IsTopLevelContentDocu
   nsCOMPtr<nsIDocShellTreeItem> rootItem;
   Unused << docShell->GetSameTypeRootTreeItem(getter_AddRefs(rootItem));
   if (rootItem.get() != static_cast<nsIDocShellTreeItem*>(docShell.get())) {
     return false;
   }
   return rootItem->ItemType() == nsIDocShellTreeItem::typeContent;
 }
 
+already_AddRefed<nsIArray>
+PerformanceTimingData::GetServerTiming() const
+{
+  if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized() ||
+      !TimingAllowed() ||
+      nsContentUtils::ShouldResistFingerprinting()) {
+    return nullptr;
+  }
+
+  nsCOMPtr<nsIArray> serverTiming = mServerTiming;
+  return serverTiming.forget();
+}
+
 } // dom namespace
 } // mozilla namespace
--- a/dom/performance/PerformanceTiming.h
+++ b/dom/performance/PerformanceTiming.h
@@ -164,23 +164,26 @@ public:
 
   // Cached result of CheckAllowedOrigin. If false, security sensitive
   // attributes of the resourceTiming object will be set to 0
   bool TimingAllowed() const
   {
     return mTimingAllowed;
   }
 
+  already_AddRefed<nsIArray> GetServerTiming() const;
+
 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);
 
+  nsCOMPtr<nsIArray> mServerTiming;
   nsString mNextHopProtocol;
 
   TimeStamp mAsyncOpen;
   TimeStamp mRedirectStart;
   TimeStamp mRedirectEnd;
   TimeStamp mDomainLookupStart;
   TimeStamp mDomainLookupEnd;
   TimeStamp mConnectStart;
--- a/dom/performance/moz.build
+++ b/dom/performance/moz.build
@@ -12,16 +12,17 @@ EXPORTS.mozilla.dom += [
     'PerformanceEntry.h',
     'PerformanceMark.h',
     'PerformanceMeasure.h',
     'PerformanceNavigation.h',
     'PerformanceNavigationTiming.h',
     'PerformanceObserver.h',
     'PerformanceObserverEntryList.h',
     'PerformanceResourceTiming.h',
+    'PerformanceServerTiming.h',
     'PerformanceService.h',
     'PerformanceStorage.h',
     'PerformanceStorageWorker.h',
     'PerformanceTiming.h',
 ]
 
 UNIFIED_SOURCES += [
     'Performance.cpp',
@@ -29,16 +30,17 @@ UNIFIED_SOURCES += [
     'PerformanceMainThread.cpp',
     'PerformanceMark.cpp',
     'PerformanceMeasure.cpp',
     'PerformanceNavigation.cpp',
     'PerformanceNavigationTiming.cpp',
     'PerformanceObserver.cpp',
     'PerformanceObserverEntryList.cpp',
     'PerformanceResourceTiming.cpp',
+    'PerformanceServerTiming.cpp',
     'PerformanceService.cpp',
     'PerformanceStorageWorker.cpp',
     'PerformanceTiming.cpp',
     'PerformanceWorker.cpp',
 ]
 
 MOCHITEST_MANIFESTS += [ 'tests/mochitest.ini' ]
 
--- a/dom/webidl/PerformanceResourceTiming.webidl
+++ b/dom/webidl/PerformanceResourceTiming.webidl
@@ -44,10 +44,15 @@ interface PerformanceResourceTiming : Pe
 
   [NeedsSubjectPrincipal]
   readonly attribute unsigned long long transferSize;
   [NeedsSubjectPrincipal]
   readonly attribute unsigned long long encodedBodySize;
   [NeedsSubjectPrincipal]
   readonly attribute unsigned long long decodedBodySize;
 
+  // TODO: Use FrozenArray once available. (Bug 1236777)
+  // readonly attribute FrozenArray<PerformanceServerTiming> serverTiming;
+  [SecureContext, Frozen, Cached, Pure, NeedsSubjectPrincipal]
+  readonly attribute sequence<PerformanceServerTiming> serverTiming;
+
   jsonifier;
 };
new file mode 100644
--- /dev/null
+++ b/dom/webidl/PerformanceServerTiming.webidl
@@ -0,0 +1,20 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * The origin of this IDL file is
+ * https://w3c.github.io/server-timing/
+ *
+ * Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
+ * liability, trademark and document use rules apply.
+ */
+
+[SecureContext,Exposed=(Window,Worker)]
+interface PerformanceServerTiming {
+  readonly attribute DOMString           name;
+  readonly attribute DOMHighResTimeStamp duration;
+  readonly attribute DOMString           description;
+
+  jsonifier;
+};
--- a/dom/webidl/moz.build
+++ b/dom/webidl/moz.build
@@ -708,16 +708,17 @@ WEBIDL_FILES = [
     'PerformanceEntry.webidl',
     'PerformanceMark.webidl',
     'PerformanceMeasure.webidl',
     'PerformanceNavigation.webidl',
     'PerformanceNavigationTiming.webidl',
     'PerformanceObserver.webidl',
     'PerformanceObserverEntryList.webidl',
     'PerformanceResourceTiming.webidl',
+    'PerformanceServerTiming.webidl',
     'PerformanceTiming.webidl',
     'PeriodicWave.webidl',
     'Permissions.webidl',
     'PermissionStatus.webidl',
     'Plugin.webidl',
     'PluginArray.webidl',
     'PointerEvent.webidl',
     'PopupBoxObject.webidl',