Bug 1423495 - Part1: Implement PerformanceServerTiming, r=baku draft
authorKershaw Chang <kechang@mozilla.com>, Valentin Gosu <valentin.gosu@gmail.com>
Wed, 10 Jan 2018 04:01:00 +0100
changeset 786589 7e0d0321e71eb0af9591ead76dc163996fbaf819
parent 786226 9dcde577687cd5519b2156728f033c322e142a51
child 786590 a0f5bde872ca9e066764d90ab80d7848988f37a8
push id107535
push uservalentin.gosu@gmail.com
push dateMon, 23 Apr 2018 16:35:48 +0000
reviewersbaku
bugs1423495
milestone61.0a1
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',