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
--- 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',