Browse Source

performance api updates

Frank-Rainer Grahl 3 months ago
parent
commit
bf36d9aca9

+ 471 - 0
mozilla-release/patches/1423495-1-61a1.patch

@@ -0,0 +1,471 @@
+# HG changeset patch
+# User Kershaw Chang <kechang@mozilla.com>, Valentin Gosu <valentin.gosu@gmail.com>
+# Date 1515553260 -3600
+#      Wed Jan 10 04:01:00 2018 +0100
+# Node ID ecf85551434a3048a74ad259dc3164c440d10692
+# Parent  69f6c14b9d965d85d1e682fe972e6a65fe7b5219
+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
+
+diff --git a/dom/performance/PerformanceResourceTiming.cpp b/dom/performance/PerformanceResourceTiming.cpp
+--- a/dom/performance/PerformanceResourceTiming.cpp
++++ b/dom/performance/PerformanceResourceTiming.cpp
+@@ -1,16 +1,17 @@
+ /* -*- 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 "PerformanceResourceTiming.h"
+ #include "mozilla/dom/PerformanceResourceTimingBinding.h"
++#include "nsArrayUtils.h"
+ 
+ using namespace mozilla::dom;
+ 
+ NS_IMPL_CYCLE_COLLECTION_INHERITED(PerformanceResourceTiming,
+                                    PerformanceEntry,
+                                    mPerformance)
+ 
+ NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(PerformanceResourceTiming,
+@@ -75,8 +76,53 @@ size_t
+ PerformanceResourceTiming::SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
+ {
+   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));
++  }
++}
++
++// Actually from Bug 1441336. Fix it later.
++bool
++PerformanceResourceTiming::TimingAllowedForCaller(Maybe<nsIPrincipal*>& aCaller) const
++{
++  if (!mTimingData) {
++    return false;
++  }
++
++  if (mTimingData->TimingAllowed()) {
++    return true;
++  }
++
++  return true;
++}
+diff --git a/dom/performance/PerformanceResourceTiming.h b/dom/performance/PerformanceResourceTiming.h
+--- 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
+ {
+@@ -150,25 +151,32 @@ public:
+     return mTimingData ? mTimingData->EncodedBodySize() : 0;
+   }
+ 
+   uint64_t DecodedBodySize() const
+   {
+     return mTimingData ? 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;
+ 
++  // Actually from Bug 1441336. Fix it later.
++  bool
++  TimingAllowedForCaller(Maybe<nsIPrincipal*>& aCaller) const;
++
+   nsString mInitiatorType;
+   UniquePtr<PerformanceTimingData> mTimingData;
+   RefPtr<Performance> mPerformance;
+ };
+ 
+ } // namespace dom
+ } // namespace mozilla
+ 
+diff --git a/dom/performance/PerformanceServerTiming.cpp b/dom/performance/PerformanceServerTiming.cpp
+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
+diff --git a/dom/performance/PerformanceServerTiming.h b/dom/performance/PerformanceServerTiming.h
+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
+diff --git a/dom/performance/PerformanceTiming.cpp b/dom/performance/PerformanceTiming.cpp
+--- a/dom/performance/PerformanceTiming.cpp
++++ b/dom/performance/PerformanceTiming.cpp
+@@ -154,16 +154,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
+@@ -625,10 +627,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
+diff --git a/dom/performance/PerformanceTiming.h b/dom/performance/PerformanceTiming.h
+--- a/dom/performance/PerformanceTiming.h
++++ b/dom/performance/PerformanceTiming.h
+@@ -157,23 +157,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;
+diff --git a/dom/performance/moz.build b/dom/performance/moz.build
+--- 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' ]
+ 
+diff --git a/dom/webidl/PerformanceResourceTiming.webidl b/dom/webidl/PerformanceResourceTiming.webidl
+--- a/dom/webidl/PerformanceResourceTiming.webidl
++++ b/dom/webidl/PerformanceResourceTiming.webidl
+@@ -28,10 +28,15 @@ interface PerformanceResourceTiming : Pe
+   readonly attribute DOMHighResTimeStamp requestStart;
+   readonly attribute DOMHighResTimeStamp responseStart;
+   readonly attribute DOMHighResTimeStamp responseEnd;
+ 
+   readonly attribute unsigned long long transferSize;
+   readonly attribute unsigned long long encodedBodySize;
+   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;
+ };
+diff --git a/dom/webidl/PerformanceServerTiming.webidl b/dom/webidl/PerformanceServerTiming.webidl
+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;
++};
+diff --git a/dom/webidl/moz.build b/dom/webidl/moz.build
+--- a/dom/webidl/moz.build
++++ b/dom/webidl/moz.build
+@@ -706,16 +706,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',

+ 185 - 0
mozilla-release/patches/1423495-2-61a1.patch

@@ -0,0 +1,185 @@
+# HG changeset patch
+# User Kershaw Chang <kechang@mozilla.com>, Valentin Gosu <valentin.gosu@gmail.com>
+# Date 1515553320 -3600
+#      Wed Jan 10 04:02:00 2018 +0100
+# Node ID ca970fc93a320009dadfa83a5ff28e122ead2bf4
+# Parent  ecf85551434a3048a74ad259dc3164c440d10692
+Bug 1423495 - Part2: Test case, r=baku
+
+Test steps:
+1. Create a XHR to get serverTiming.sjs.
+2. Add Server-Timing headers in serverTiming.sjs.
+3. Check if the value from PerformanceResourceTiming is correct.
+
+MozReview-Commit-ID: KOQhoFQv4fy
+
+diff --git a/dom/performance/tests/mochitest.ini b/dom/performance/tests/mochitest.ini
+--- a/dom/performance/tests/mochitest.ini
++++ b/dom/performance/tests/mochitest.ini
+@@ -4,17 +4,21 @@ support-files =
+   test_performance_user_timing.js
+   test_worker_performance_now.js
+   worker_performance_user_timing.js
+   worker_performance_observer.js
+   sharedworker_performance_user_timing.js
+   test_worker_performance_entries.js
+   test_worker_performance_entries.sjs
+   empty.js
++  serverTiming.sjs
+ 
+ [test_performance_observer.html]
+ [test_performance_user_timing.html]
+ [test_worker_user_timing.html]
+ [test_worker_observer.html]
+ [test_sharedWorker_performance_user_timing.html]
+ [test_worker_performance_now.html]
+ [test_timeOrigin.html]
+ [test_worker_performance_entries.html]
++[test_performance_server_timing.html]
++scheme = https
++[test_performance_server_timing_plain_http.html]
+diff --git a/dom/performance/tests/serverTiming.sjs b/dom/performance/tests/serverTiming.sjs
+new file mode 100644
+--- /dev/null
++++ b/dom/performance/tests/serverTiming.sjs
+@@ -0,0 +1,32 @@
++
++var responseServerTiming = [{metric:"metric1", duration:"123.4", description:"description1"},
++                           {metric:"metric2", duration:"456.78", description:"description2"}];
++var trailerServerTiming = [{metric:"metric3", duration:"789.11", description:"description3"},
++                           {metric:"metric4", duration:"1112.13", description:"description4"}];
++
++function createServerTimingHeader(headerData) {
++  var header = "";
++  for (var i = 0; i < headerData.length; i++) {
++    header += "Server-Timing:" + headerData[i].metric + ";" +
++              "dur=" + headerData[i].duration + ";" +
++              "desc=" + headerData[i].description + "\r\n";
++  }
++  return header;
++}
++
++function handleRequest(request, response)
++{
++  var body = "c\r\ndata reached\r\n3\r\nhej\r\n0\r\n";
++
++  response.seizePower();
++  response.write("HTTP/1.1 200 OK\r\n");
++  response.write("Content-Type: text/plain\r\n");
++  response.write(createServerTimingHeader(responseServerTiming));
++
++  response.write("Transfer-Encoding: chunked\r\n");
++  response.write("\r\n");
++  response.write(body);
++  response.write(createServerTimingHeader(trailerServerTiming));
++  response.write("\r\n");
++  response.finish();
++}
+diff --git a/dom/performance/tests/test_performance_server_timing.html b/dom/performance/tests/test_performance_server_timing.html
+new file mode 100644
+--- /dev/null
++++ b/dom/performance/tests/test_performance_server_timing.html
+@@ -0,0 +1,58 @@
++<!--
++  Any copyright is dedicated to the Public Domain.
++  http://creativecommons.org/publicdomain/zero/1.0/
++-->
++<!DOCTYPE html>
++<html>
++<head>
++<meta charset=utf-8>
++<title>Test for PerformanceServerTiming</title>
++<script src="/resources/testharness.js"></script>
++<script src="/resources/testharnessreport.js"></script>
++</head>
++<body>
++<div id="log"></div>
++<script>
++function makeXHR(aUrl) {
++  var xmlhttp = new XMLHttpRequest();
++  xmlhttp.open("get", aUrl, true);
++  xmlhttp.send();
++}
++
++// Note that |responseServerTiming| and |trailerServerTiming| SHOULD be synced with
++// the ones in serverTiming.sjs.
++var responseServerTiming = [{metric:"metric1", duration:"123.4", description:"description1"},
++                            {metric:"metric2", duration:"456.78", description:"description2"}];
++var trailerServerTiming = [{metric:"metric3", duration:"789.11", description:"description3"},
++                           {metric:"metric4", duration:"1112.13", description:"description4"}];
++
++function checkServerTimingContent(serverTiming) {
++  var expectedResult = responseServerTiming.concat(trailerServerTiming);
++  assert_equals(serverTiming.length, expectedResult.length);
++
++  for (var i = 0; i < expectedResult.length; i++) {
++    assert_equals(serverTiming[i].name, expectedResult[i].metric);
++    assert_equals(serverTiming[i].description, expectedResult[i].description);
++    assert_equals(serverTiming[i].duration, parseFloat(expectedResult[i].duration));
++  }
++}
++
++promise_test(t => {
++  var promise = new Promise(resolve => {
++    performance.clearResourceTimings();
++
++    var observer = new PerformanceObserver(list => resolve(list));
++    observer.observe({entryTypes: ['resource']});
++    t.add_cleanup(() => observer.disconnect());
++  });
++
++  makeXHR("serverTiming.sjs");
++
++  return promise.then(list => {
++    assert_equals(list.getEntries().length, 1);
++    checkServerTimingContent(list.getEntries()[0].serverTiming);
++  });
++}, "server-timing test");
++
++</script>
++</body>
+diff --git a/dom/performance/tests/test_performance_server_timing_plain_http.html b/dom/performance/tests/test_performance_server_timing_plain_http.html
+new file mode 100644
+--- /dev/null
++++ b/dom/performance/tests/test_performance_server_timing_plain_http.html
+@@ -0,0 +1,40 @@
++<!--
++  Any copyright is dedicated to the Public Domain.
++  http://creativecommons.org/publicdomain/zero/1.0/
++-->
++<!DOCTYPE html>
++<html>
++<head>
++<meta charset=utf-8>
++<title>Plain HTTP Test for PerformanceServerTiming</title>
++<script src="/resources/testharness.js"></script>
++<script src="/resources/testharnessreport.js"></script>
++</head>
++<body>
++<div id="log"></div>
++<script>
++function makeXHR(aUrl) {
++  var xmlhttp = new XMLHttpRequest();
++  xmlhttp.open("get", aUrl, true);
++  xmlhttp.send();
++}
++
++promise_test(t => {
++  var promise = new Promise(resolve => {
++    performance.clearResourceTimings();
++
++    var observer = new PerformanceObserver(list => resolve(list));
++    observer.observe({entryTypes: ['resource']});
++    t.add_cleanup(() => observer.disconnect());
++  });
++
++  makeXHR("serverTiming.sjs");
++
++  return promise.then(list => {
++    assert_equals(list.getEntries().length, 1);
++    assert_equals(list.getEntries()[0].serverTiming, undefined);
++  });
++}, "server-timing test");
++
++</script>
++</body>

+ 76 - 0
mozilla-release/patches/1423495-3-61a1.patch

@@ -0,0 +1,76 @@
+# HG changeset patch
+# User Kershaw Chang <kechang@mozilla.com>, Valentin Gosu <valentin.gosu@gmail.com>
+# Date 1515553320 -3600
+#      Wed Jan 10 04:02:00 2018 +0100
+# Node ID d06281128204219694c0770acc0d0ec928d6647f
+# Parent  ca970fc93a320009dadfa83a5ff28e122ead2bf4
+Bug 1423495 - Part3: Add PerformanceServerTiming to test_interface.js, r=baku
+
+MozReview-Commit-ID: 663c9sudEIR
+
+diff --git a/dom/serviceworkers/test/test_serviceworker_interfaces.js b/dom/serviceworkers/test/test_serviceworker_interfaces.js
+--- a/dom/serviceworkers/test/test_serviceworker_interfaces.js
++++ b/dom/serviceworkers/test/test_serviceworker_interfaces.js
+@@ -184,16 +184,18 @@ var interfaceNamesInGlobalScope =
+     "PerformanceMeasure",
+ // IMPORTANT: Do not change this list without review from a DOM peer!
+     "PerformanceObserver",
+ // IMPORTANT: Do not change this list without review from a DOM peer!
+     "PerformanceObserverEntryList",
+ // IMPORTANT: Do not change this list without review from a DOM peer!
+     "PerformanceResourceTiming",
+ // IMPORTANT: Do not change this list without review from a DOM peer!
++    "PerformanceServerTiming",
++// IMPORTANT: Do not change this list without review from a DOM peer!
+     "ProgressEvent",
+ // IMPORTANT: Do not change this list without review from a DOM peer!
+     "PushEvent",
+ // IMPORTANT: Do not change this list without review from a DOM peer!
+     "PushManager",
+ // IMPORTANT: Do not change this list without review from a DOM peer!
+     "PushMessageData",
+ // IMPORTANT: Do not change this list without review from a DOM peer!
+diff --git a/dom/tests/mochitest/general/test_interfaces.js b/dom/tests/mochitest/general/test_interfaces.js
+--- a/dom/tests/mochitest/general/test_interfaces.js
++++ b/dom/tests/mochitest/general/test_interfaces.js
+@@ -764,16 +764,18 @@ var interfaceNamesInGlobalScope =
+     {name: "PerformanceNavigationTiming", insecureContext: true},
+ // IMPORTANT: Do not change this list without review from a DOM peer!
+     {name: "PerformanceObserver", insecureContext: true},
+ // IMPORTANT: Do not change this list without review from a DOM peer!
+     {name: "PerformanceObserverEntryList", insecureContext: true},
+ // IMPORTANT: Do not change this list without review from a DOM peer!
+     {name: "PerformanceResourceTiming", insecureContext: true},
+ // IMPORTANT: Do not change this list without review from a DOM peer!
++    {name: "PerformanceServerTiming", insecureContext: false},
++// IMPORTANT: Do not change this list without review from a DOM peer!
+     {name: "PerformanceTiming", insecureContext: true},
+ // IMPORTANT: Do not change this list without review from a DOM peer!
+     {name: "PeriodicWave", insecureContext: true},
+ // IMPORTANT: Do not change this list without review from a DOM peer!
+     {name: "Permissions", insecureContext: true},
+ // IMPORTANT: Do not change this list without review from a DOM peer!
+     {name: "PermissionStatus", insecureContext: true},
+ // IMPORTANT: Do not change this list without review from a DOM peer!
+diff --git a/dom/workers/test/test_worker_interfaces.js b/dom/workers/test/test_worker_interfaces.js
+--- a/dom/workers/test/test_worker_interfaces.js
++++ b/dom/workers/test/test_worker_interfaces.js
+@@ -184,16 +184,18 @@ var interfaceNamesInGlobalScope =
+     {name: "PerformanceMeasure", insecureContext: true},
+ // IMPORTANT: Do not change this list without review from a DOM peer!
+     {name: "PerformanceObserver", insecureContext: true},
+ // IMPORTANT: Do not change this list without review from a DOM peer!
+     {name: "PerformanceObserverEntryList", insecureContext: true},
+ // IMPORTANT: Do not change this list without review from a DOM peer!
+     {name: "PerformanceResourceTiming", insecureContext: true},
+ // IMPORTANT: Do not change this list without review from a DOM peer!
++    {name: "PerformanceServerTiming", insecureContext: false},
++// IMPORTANT: Do not change this list without review from a DOM peer!
+     {name: "ProgressEvent", insecureContext: true},
+ // IMPORTANT: Do not change this list without review from a DOM peer!
+     {name: "PushManager", insecureContext: true},
+ // IMPORTANT: Do not change this list without review from a DOM peer!
+     {name: "PushSubscription", insecureContext: true},
+ // IMPORTANT: Do not change this list without review from a DOM peer!
+     {name: "PushSubscriptionOptions", insecureContext: true},
+ // IMPORTANT: Do not change this list without review from a DOM peer!

+ 281 - 0
mozilla-release/patches/1423495-4no5-61a1.patch

@@ -0,0 +1,281 @@
+# HG changeset patch
+# User Kershaw Chang <kechang@mozilla.com>, Valentin Gosu <valentin.gosu@gmail.com>
+# Date 1515723180 -3600
+#      Fri Jan 12 03:13:00 2018 +0100
+# Node ID 11804549931f5e8e2e71c5bcdd3221b41e8d54d8
+# Parent  5d9495a52eb69317db7add55a510f53b3a2de8fa
+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
+
+diff --git a/dom/performance/PerformanceMainThread.cpp b/dom/performance/PerformanceMainThread.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(std::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;
+diff --git a/dom/performance/PerformanceMainThread.h b/dom/performance/PerformanceMainThread.h
+--- 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
+diff --git a/dom/performance/PerformanceStorage.h b/dom/performance/PerformanceStorage.h
+--- 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
+diff --git a/dom/performance/PerformanceStorageWorker.h b/dom/performance/PerformanceStorageWorker.h
+--- a/dom/performance/PerformanceStorageWorker.h
++++ b/dom/performance/PerformanceStorageWorker.h
+@@ -27,17 +27,22 @@ public:
+ 
+   void InitializeOnWorker();
+ 
+   void ShutdownOnWorker();
+ 
+   void AddEntry(nsIHttpChannel* aChannel,
+                 nsITimedChannel* aTimedChannel) override;
+ 
+-  void AddEntryOnWorker(UniquePtr<PerformanceProxyData>&& aData);
++  void CreateDocumentEntry(nsITimedChannel* aChannel) override
++  {
++    MOZ_CRASH("This should not be called on workers.");
++  }
++
++void AddEntryOnWorker(UniquePtr<PerformanceProxyData>&& aData);
+ 
+ private:
+   explicit PerformanceStorageWorker(WorkerPrivate* aWorkerPrivate);
+   ~PerformanceStorageWorker();
+ 
+   Mutex mMutex;
+ 
+   // Protected by mutex.
+diff --git a/netwerk/protocol/http/HttpBaseChannel.cpp b/netwerk/protocol/http/HttpBaseChannel.cpp
+--- a/netwerk/protocol/http/HttpBaseChannel.cpp
++++ b/netwerk/protocol/http/HttpBaseChannel.cpp
+@@ -4186,21 +4186,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() == nsIContentPolicyBase::TYPE_DOCUMENT) {
+-    return nullptr;
+-  }
+-
+   nsCOMPtr<nsIDOMDocument> domDocument;
+   mLoadInfo->GetLoadingDocument(getter_AddRefs(domDocument));
+   if (!domDocument) {
+     return nullptr;
+   }
+ 
+   nsCOMPtr<nsIDocument> loadingDocument = do_QueryInterface(domDocument);
+   if (!loadingDocument) {
+@@ -4223,16 +4218,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) {
+diff --git a/netwerk/protocol/http/HttpBaseChannel.h b/netwerk/protocol/http/HttpBaseChannel.h
+--- a/netwerk/protocol/http/HttpBaseChannel.h
++++ b/netwerk/protocol/http/HttpBaseChannel.h
+@@ -421,16 +421,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);
+ 
+diff --git a/netwerk/protocol/http/HttpChannelChild.cpp b/netwerk/protocol/http/HttpChannelChild.cpp
+--- a/netwerk/protocol/http/HttpChannelChild.cpp
++++ b/netwerk/protocol/http/HttpChannelChild.cpp
+@@ -1226,20 +1226,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;
+   }
+ }
+ 
+ void
+ HttpChannelChild::DoOnStopRequest(nsIRequest* aRequest, nsresult aChannelStatus, nsISupports* aContext)
+diff --git a/netwerk/protocol/http/InterceptedHttpChannel.cpp b/netwerk/protocol/http/InterceptedHttpChannel.cpp
+--- a/netwerk/protocol/http/InterceptedHttpChannel.cpp
++++ b/netwerk/protocol/http/InterceptedHttpChannel.cpp
+@@ -1042,20 +1042,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();
+diff --git a/netwerk/protocol/http/nsHttpChannel.cpp b/netwerk/protocol/http/nsHttpChannel.cpp
+--- a/netwerk/protocol/http/nsHttpChannel.cpp
++++ b/netwerk/protocol/http/nsHttpChannel.cpp
+@@ -7168,20 +7168,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);

+ 323 - 0
mozilla-release/patches/1423495-6-61a1.patch

@@ -0,0 +1,323 @@
+# HG changeset patch
+# User Valentin Gosu <valentin.gosu@gmail.com>
+# Date 1524567852 -7200
+#      Tue Apr 24 13:04:12 2018 +0200
+# Node ID fa8202661c163cf890873b2d6979db1a6917bebc
+# Parent  9625cb198a5a6b19aa148d2a4918370343c83aee
+Bug 1423495 - Part6: Use threadsafe refcounting for nsServerTiming r=baku,nwgh
+
+* Also keeps the timing array as nsTArray<nsCOMPtr<nsIServerTiming>> instead of the scriptable nsIArray (which doesn't like being released on another thread)
+
+MozReview-Commit-ID: 37uPZJ38saQ
+
+diff --git a/dom/performance/PerformanceResourceTiming.cpp b/dom/performance/PerformanceResourceTiming.cpp
+--- a/dom/performance/PerformanceResourceTiming.cpp
++++ b/dom/performance/PerformanceResourceTiming.cpp
+@@ -87,29 +87,20 @@ PerformanceResourceTiming::GetServerTimi
+                             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;
+-  }
+-
++  nsTArray<nsCOMPtr<nsIServerTiming>> serverTimingArray = mTimingData->GetServerTiming();
++  uint32_t length = serverTimingArray.Length();
+   for (uint32_t index = 0; index < length; ++index) {
+-    nsCOMPtr<nsIServerTiming> serverTiming =
+-      do_QueryElementAt(serverTimingArray, index);
++    nsCOMPtr<nsIServerTiming> serverTiming = serverTimingArray.ElementAt(index);
+     MOZ_ASSERT(serverTiming);
+ 
+     aRetval.AppendElement(
+       new PerformanceServerTiming(GetParentObject(), serverTiming));
+   }
+ }
+ 
+ // Actually from Bug 1441336. Fix it later.
+diff --git a/dom/performance/PerformanceTiming.cpp b/dom/performance/PerformanceTiming.cpp
+--- a/dom/performance/PerformanceTiming.cpp
++++ b/dom/performance/PerformanceTiming.cpp
+@@ -154,17 +154,17 @@ 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));
++    aChannel->GetNativeServerTiming(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()) {
+@@ -627,23 +627,22 @@ 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
++nsTArray<nsCOMPtr<nsIServerTiming>>
++PerformanceTimingData::GetServerTiming()
+ {
+   if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized() ||
+       !TimingAllowed() ||
+       nsContentUtils::ShouldResistFingerprinting()) {
+-    return nullptr;
++    return nsTArray<nsCOMPtr<nsIServerTiming>>();
+   }
+ 
+-  nsCOMPtr<nsIArray> serverTiming = mServerTiming;
+-  return serverTiming.forget();
++  return nsTArray<nsCOMPtr<nsIServerTiming>>(mServerTiming);
+ }
+ 
+ } // dom namespace
+ } // mozilla namespace
+diff --git a/dom/performance/PerformanceTiming.h b/dom/performance/PerformanceTiming.h
+--- a/dom/performance/PerformanceTiming.h
++++ b/dom/performance/PerformanceTiming.h
+@@ -8,16 +8,17 @@
+ #define mozilla_dom_PerformanceTiming_h
+ 
+ #include "mozilla/Attributes.h"
+ #include "nsContentUtils.h"
+ #include "nsDOMNavigationTiming.h"
+ #include "nsRFPService.h"
+ #include "nsWrapperCache.h"
+ #include "Performance.h"
++#include "nsITimedChannel.h"
+ 
+ class nsIHttpChannel;
+ class nsITimedChannel;
+ 
+ namespace mozilla {
+ namespace dom {
+ 
+ class PerformanceTiming;
+@@ -157,26 +158,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;
++  nsTArray<nsCOMPtr<nsIServerTiming>> GetServerTiming();
+ 
+ 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;
++  nsTArray<nsCOMPtr<nsIServerTiming>> mServerTiming;
+   nsString mNextHopProtocol;
+ 
+   TimeStamp mAsyncOpen;
+   TimeStamp mRedirectStart;
+   TimeStamp mRedirectEnd;
+   TimeStamp mDomainLookupStart;
+   TimeStamp mDomainLookupEnd;
+   TimeStamp mConnectStart;
+diff --git a/netwerk/base/nsITimedChannel.idl b/netwerk/base/nsITimedChannel.idl
+--- a/netwerk/base/nsITimedChannel.idl
++++ b/netwerk/base/nsITimedChannel.idl
+@@ -4,27 +4,31 @@
+ 
+ #include "nsISupports.idl"
+ interface nsIArray;
+ interface nsIPrincipal;
+ %{C++
+ namespace mozilla {
+ class TimeStamp;
+ }
++#include "nsTArrayForwardDeclare.h"
++#include "nsCOMPtr.h"
+ %}
+ 
+ native TimeStamp(mozilla::TimeStamp);
+ 
+ [scriptable, uuid(c2d9e95b-9cc9-4f47-9ef6-1de0cf7ebc75)]
+ interface nsIServerTiming : nsISupports {
+   [must_use] readonly attribute ACString name;
+   [must_use] readonly attribute double duration;
+   [must_use] readonly attribute ACString description;
+ };
+ 
++[ref] native nsServerTimingArrayRef(nsTArray<nsCOMPtr<nsIServerTiming>>);
++
+ // All properties return zero if the value is not available
+ [scriptable, uuid(ca63784d-959c-4c3a-9a59-234a2a520de0)]
+ interface nsITimedChannel : nsISupports {
+   // Set this attribute to true to enable collection of timing data.
+   // channelCreationTime will be available even with this attribute set to
+   // false.
+   attribute boolean timingEnabled;
+ 
+@@ -105,9 +109,10 @@ interface nsITimedChannel : nsISupports 
+   readonly attribute PRTime cacheReadEndTime;
+   readonly attribute PRTime redirectStartTime;
+   readonly attribute PRTime redirectEndTime;
+ 
+   // If this attribute is false, this resource MUST NOT be reported in resource timing.
+   [noscript] attribute boolean reportResourceTiming;
+ 
+   readonly attribute nsIArray serverTiming;
++  nsServerTimingArrayRef getNativeServerTiming();
+ };
+diff --git a/netwerk/protocol/http/HttpBaseChannel.cpp b/netwerk/protocol/http/HttpBaseChannel.cpp
+--- a/netwerk/protocol/http/HttpBaseChannel.cpp
++++ b/netwerk/protocol/http/HttpBaseChannel.cpp
+@@ -4496,52 +4496,64 @@ HttpBaseChannel::CallTypeSniffers(void *
+   if (!newType.IsEmpty()) {
+     chan->SetContentType(newType);
+   }
+ }
+ 
+ template <class T>
+ static void
+ ParseServerTimingHeader(const nsAutoPtr<T> &aHeader,
+-                        nsIMutableArray* aOutput)
++                        nsTArray<nsCOMPtr<nsIServerTiming>>& aOutput)
+ {
+   if (!aHeader) {
+     return;
+   }
+ 
+   nsAutoCString serverTimingHeader;
+   Unused << aHeader->GetHeader(nsHttp::Server_Timing, serverTimingHeader);
+   if (serverTimingHeader.IsEmpty()) {
+     return;
+   }
+ 
+   ServerTimingParser parser(serverTimingHeader);
+   parser.Parse();
+ 
+   nsTArray<nsCOMPtr<nsIServerTiming>> array = parser.TakeServerTimingHeaders();
+-  for (const auto &data : array) {
+-    aOutput->AppendElement(data);
+-  }
++  aOutput.AppendElements(array);
+ }
+ 
+ NS_IMETHODIMP
+ HttpBaseChannel::GetServerTiming(nsIArray **aServerTiming)
+ {
++  nsresult rv;
+   NS_ENSURE_ARG_POINTER(aServerTiming);
+ 
++  nsCOMPtr<nsIMutableArray> array = do_CreateInstance(NS_ARRAY_CONTRACTID, &rv);
++  NS_ENSURE_SUCCESS(rv, rv);
++
++  nsTArray<nsCOMPtr<nsIServerTiming>> data;
++  rv = GetNativeServerTiming(data);
++  NS_ENSURE_SUCCESS(rv, rv);
++
++  for (const auto &entry : data) {
++    array->AppendElement(entry);
++  }
++
++  array.forget(aServerTiming);
++  return NS_OK;
++}
++
++NS_IMETHODIMP
++HttpBaseChannel::GetNativeServerTiming(nsTArray<nsCOMPtr<nsIServerTiming>>& aServerTiming)
++{
++  aServerTiming.Clear();
++
+   bool isHTTPS = false;
+   if (NS_SUCCEEDED(mURI->SchemeIs("https", &isHTTPS)) && isHTTPS) {
+-    nsTArray<nsCOMPtr<nsIServerTiming>> data;
+-    nsresult rv = NS_OK;
+-    nsCOMPtr<nsIMutableArray> array = do_CreateInstance(NS_ARRAY_CONTRACTID, &rv);
+-    NS_ENSURE_SUCCESS(rv, rv);
+-
+-    ParseServerTimingHeader(mResponseHead, array);
+-    ParseServerTimingHeader(mResponseTrailers, array);
+-
+-    array.forget(aServerTiming);
++    ParseServerTimingHeader(mResponseHead, aServerTiming);
++    ParseServerTimingHeader(mResponseTrailers, aServerTiming);
+   }
+ 
+   return NS_OK;
+ }
+ 
+ } // namespace net
+ } // namespace mozilla
+diff --git a/netwerk/protocol/http/NullHttpChannel.cpp b/netwerk/protocol/http/NullHttpChannel.cpp
+--- a/netwerk/protocol/http/NullHttpChannel.cpp
++++ b/netwerk/protocol/http/NullHttpChannel.cpp
+@@ -896,16 +896,22 @@ NullHttpChannel::GetReportResourceTiming
+ }
+ 
+ NS_IMETHODIMP
+ NullHttpChannel::GetServerTiming(nsIArray **aServerTiming)
+ {
+   return NS_ERROR_NOT_IMPLEMENTED;
+ }
+ 
++NS_IMETHODIMP
++NullHttpChannel::GetNativeServerTiming(nsTArray<nsCOMPtr<nsIServerTiming>>& aServerTiming)
++{
++  return NS_ERROR_NOT_IMPLEMENTED;
++}
++
+ #define IMPL_TIMING_ATTR(name)                                 \
+ NS_IMETHODIMP                                                  \
+ NullHttpChannel::Get##name##Time(PRTime* _retval) {            \
+     TimeStamp stamp;                                           \
+     Get##name(&stamp);                                         \
+     if (stamp.IsNull()) {                                      \
+         *_retval = 0;                                          \
+         return NS_OK;                                          \
+diff --git a/netwerk/protocol/http/nsServerTiming.h b/netwerk/protocol/http/nsServerTiming.h
+--- a/netwerk/protocol/http/nsServerTiming.h
++++ b/netwerk/protocol/http/nsServerTiming.h
+@@ -9,17 +9,17 @@
+ 
+ #include "nsITimedChannel.h"
+ #include "nsString.h"
+ #include "nsTArray.h"
+ 
+ class nsServerTiming final : public nsIServerTiming
+ {
+ public:
+-  NS_DECL_ISUPPORTS
++  NS_DECL_THREADSAFE_ISUPPORTS
+   NS_DECL_NSISERVERTIMING
+ 
+   nsServerTiming() = default;
+ 
+   void SetName(const nsACString &aName)
+   {
+     mName = aName;
+   }

+ 153 - 0
mozilla-release/patches/1425605-60a1.patch

@@ -0,0 +1,153 @@
+# HG changeset patch
+# User Greg Tatum <gtatum@mozilla.com>
+# Date 1520548613 21600
+# Node ID c26cb9769245d3b8023f887cda759e8fb9c70efc
+# Parent  8742010ad18ff6f3e3a17fe05c82b7b001128bd8
+Bug 1425605 - Add the start/end mark names to performance.measure profiler markers; r=baku,mstange
+
+MozReview-Commit-ID: I8DzSlSi124
+
+diff --git a/dom/performance/Performance.cpp b/dom/performance/Performance.cpp
+--- a/dom/performance/Performance.cpp
++++ b/dom/performance/Performance.cpp
+@@ -323,19 +323,32 @@ Performance::Measure(const nsAString& aN
+   InsertUserEntry(performanceMeasure);
+ 
+ #ifdef MOZ_GECKO_PROFILER
+   if (profiler_is_active()) {
+     TimeStamp startTimeStamp = CreationTimeStamp() +
+                                TimeDuration::FromMilliseconds(startTime);
+     TimeStamp endTimeStamp = CreationTimeStamp() +
+                              TimeDuration::FromMilliseconds(endTime);
++
++    // Convert to Maybe values so that Optional types do not need to be used in
++    // the profiler.
++    Maybe<nsString> startMark;
++    if (aStartMark.WasPassed()) {
++      startMark.emplace(aStartMark.Value());
++    }
++    Maybe<nsString> endMark;
++    if (aEndMark.WasPassed()) {
++      endMark.emplace(aEndMark.Value());
++    }
++
+     profiler_add_marker(
+       "UserTiming",
+-      MakeUnique<UserTimingMarkerPayload>(aName, startTimeStamp, endTimeStamp));
++      MakeUnique<UserTimingMarkerPayload>(aName, startMark, endMark,
++                                          startTimeStamp, endTimeStamp));
+   }
+ #endif
+ }
+ 
+ void
+ Performance::ClearMeasures(const Optional<nsAString>& aName)
+ {
+   ClearUserEntries(aName, NS_LITERAL_STRING("measure"));
+diff --git a/tools/profiler/core/ProfilerMarkerPayload.cpp b/tools/profiler/core/ProfilerMarkerPayload.cpp
+--- a/tools/profiler/core/ProfilerMarkerPayload.cpp
++++ b/tools/profiler/core/ProfilerMarkerPayload.cpp
+@@ -4,16 +4,17 @@
+  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+ 
+ #include "GeckoProfiler.h"
+ #include "ProfilerBacktrace.h"
+ #include "ProfilerMarkerPayload.h"
+ #include "gfxASurface.h"
+ #include "Layers.h"
+ #include "mozilla/Sprintf.h"
++#include "mozilla/Maybe.h"
+ 
+ using namespace mozilla;
+ 
+ void
+ ProfilerMarkerPayload::StreamCommonProps(const char* aMarkerType,
+                                          SpliceableJSONWriter& aWriter,
+                                          const TimeStamp& aProcessStartTime,
+                                          UniqueStacks& aUniqueStacks)
+@@ -70,16 +71,27 @@ IOMarkerPayload::StreamPayload(Spliceabl
+ void
+ UserTimingMarkerPayload::StreamPayload(SpliceableJSONWriter& aWriter,
+                                        const TimeStamp& aProcessStartTime,
+                                        UniqueStacks& aUniqueStacks)
+ {
+   StreamCommonProps("UserTiming", aWriter, aProcessStartTime, aUniqueStacks);
+   aWriter.StringProperty("name", NS_ConvertUTF16toUTF8(mName).get());
+   aWriter.StringProperty("entryType", mEntryType);
++
++  if (mStartMark.isSome()) {
++    aWriter.StringProperty("startMark", NS_ConvertUTF16toUTF8(mStartMark.value()).get());
++  } else {
++    aWriter.NullProperty("startMark");
++  }
++  if (mEndMark.isSome()) {
++    aWriter.StringProperty("endMark", NS_ConvertUTF16toUTF8(mEndMark.value()).get());
++  } else {
++    aWriter.NullProperty("endMark");
++  }
+ }
+ 
+ void
+ DOMEventMarkerPayload::StreamPayload(SpliceableJSONWriter& aWriter,
+                                      const TimeStamp& aProcessStartTime,
+                                      UniqueStacks& aUniqueStacks)
+ {
+   StreamCommonProps("DOMEvent", aWriter, aProcessStartTime, aUniqueStacks);
+diff --git a/tools/profiler/public/ProfilerMarkerPayload.h b/tools/profiler/public/ProfilerMarkerPayload.h
+--- a/tools/profiler/public/ProfilerMarkerPayload.h
++++ b/tools/profiler/public/ProfilerMarkerPayload.h
+@@ -3,16 +3,17 @@
+ /* 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 ProfilerMarkerPayload_h
+ #define ProfilerMarkerPayload_h
+ 
+ #include "mozilla/Attributes.h"
++#include "mozilla/Maybe.h"
+ #include "mozilla/RefPtr.h"
+ #include "mozilla/TimeStamp.h"
+ #include "mozilla/UniquePtrExtensions.h"
+ 
+ #include "nsString.h"
+ #include "GeckoProfiler.h"
+ 
+ #include "js/Utility.h"
+@@ -145,29 +146,35 @@ public:
+   UserTimingMarkerPayload(const nsAString& aName,
+                           const mozilla::TimeStamp& aStartTime)
+     : ProfilerMarkerPayload(aStartTime, aStartTime)
+     , mEntryType("mark")
+     , mName(aName)
+   {}
+ 
+   UserTimingMarkerPayload(const nsAString& aName,
++                          const mozilla::Maybe<nsString>& aStartMark,
++                          const mozilla::Maybe<nsString>& aEndMark,
+                           const mozilla::TimeStamp& aStartTime,
+                           const mozilla::TimeStamp& aEndTime)
+     : ProfilerMarkerPayload(aStartTime, aEndTime)
+     , mEntryType("measure")
+     , mName(aName)
++    , mStartMark(aStartMark)
++    , mEndMark(aEndMark)
+   {}
+ 
+   DECL_STREAM_PAYLOAD
+ 
+ private:
+   // Either "mark" or "measure".
+   const char* mEntryType;
+   nsString mName;
++  mozilla::Maybe<nsString> mStartMark;
++  mozilla::Maybe<nsString> mEndMark;
+ };
+ 
+ // Contains the translation applied to a 2d layer so we can track the layer
+ // position at each frame.
+ class LayerTranslationMarkerPayload : public ProfilerMarkerPayload
+ {
+ public:
+   LayerTranslationMarkerPayload(mozilla::layers::Layer* aLayer,
+

+ 267 - 0
mozilla-release/patches/1429973-0-60a1.patch

@@ -0,0 +1,267 @@
+# HG changeset patch
+# User Nicholas Hurley <hurley@mozilla.com>
+# Date 1518718358 28800
+#      Thu Feb 15 10:12:38 2018 -0800
+# Node ID 8438cc4db7709b106a68a392bef840a504eeea7d
+# Parent  8c0beb6eb43a3396ce92cfeb5f9f174372b9de1a
+Bug 1429973 part 0 - Update node-http2 to v3.3.8 for required bugfix. r=bagder
+
+MozReview-Commit-ID: 60AQesLEA3K
+
+diff --git a/testing/xpcshell/node-http2/HISTORY.md b/testing/xpcshell/node-http2/HISTORY.md
+--- a/testing/xpcshell/node-http2/HISTORY.md
++++ b/testing/xpcshell/node-http2/HISTORY.md
+@@ -1,11 +1,17 @@
+ Version history
+ ===============
+ 
++### 3.3.8 (2018-02-15) ###
++* Fix an issue with HTTP trailers and END_STREAM.
++
++### 3.3.7 (2017-09-21) ###
++* Mark as incompatible with node >= 9.0.0 (to encourage using the built-in http2 module available by default in node >= 9.0.0).
++
+ ### 3.3.6 (2016-09-16) ###
+ * We were not appropriately sending HPACK context updates when receiving SETTINGS_HEADER_TABLE_SIZE. This release fixes that bug.
+ 
+ ### 3.3.5 (2016-09-06) ###
+ * Fix issues with large DATA frames (https://github.com/molnarg/node-http2/issues/207)
+ 
+ ### 3.3.4 (2016-04-22) ###
+ * More PR bugfixes (https://github.com/molnarg/node-http2/issues?q=milestone%3Av3.3.4)
+diff --git a/testing/xpcshell/node-http2/README.md b/testing/xpcshell/node-http2/README.md
+--- a/testing/xpcshell/node-http2/README.md
++++ b/testing/xpcshell/node-http2/README.md
+@@ -1,16 +1,18 @@
+ node-http2
+ ==========
+ 
+ An HTTP/2 ([RFC 7540](http://tools.ietf.org/html/rfc7540))
+ client and server implementation for node.js.
+ 
+ ![Travis CI status](https://travis-ci.org/molnarg/node-http2.svg?branch=master)
+ 
++**NOTE WELL** This package is officially deprecated. As of node 9.0.0, there is an 'http2' package built-in. You should use that one instead.
++
+ Installation
+ ------------
+ 
+ ```
+ npm install http2
+ ```
+ 
+ API
+diff --git a/testing/xpcshell/node-http2/lib/http.js b/testing/xpcshell/node-http2/lib/http.js
+--- a/testing/xpcshell/node-http2/lib/http.js
++++ b/testing/xpcshell/node-http2/lib/http.js
+@@ -340,32 +340,32 @@ OutgoingMessage.prototype._write = funct
+ };
+ 
+ OutgoingMessage.prototype._finish = function _finish() {
+   if (this.stream) {
+     if (this._trailers) {
+       if (this.request) {
+         this.request.addTrailers(this._trailers);
+       } else {
+-        this.stream.headers(this._trailers);
++        this.stream.trailers(this._trailers);
+       }
+     }
+     this.finished = true;
+     this.stream.end();
+   } else {
+     this.once('socket', this._finish.bind(this));
+   }
+ };
+ 
+ OutgoingMessage.prototype.setHeader = function setHeader(name, value) {
+   if (this.headersSent) {
+     return this.emit('error', new Error('Can\'t set headers after they are sent.'));
+   } else {
+     name = name.toLowerCase();
+-    if (deprecatedHeaders.includes(name)) {
++    if (deprecatedHeaders.indexOf(name) !== -1) {
+       return this.emit('error', new Error('Cannot set deprecated header: ' + name));
+     }
+     this._headers[name] = value;
+   }
+ };
+ 
+ OutgoingMessage.prototype.removeHeader = function removeHeader(name) {
+   if (this.headersSent) {
+diff --git a/testing/xpcshell/node-http2/lib/protocol/flow.js b/testing/xpcshell/node-http2/lib/protocol/flow.js
+--- a/testing/xpcshell/node-http2/lib/protocol/flow.js
++++ b/testing/xpcshell/node-http2/lib/protocol/flow.js
+@@ -82,23 +82,23 @@ Flow.prototype._receive = function _rece
+ Flow.prototype._write = function _write(frame, encoding, callback) {
+   var sentToUs = (this._flowControlId === undefined) || (frame.stream === this._flowControlId);
+ 
+   if (sentToUs && (frame.flags.END_STREAM || (frame.type === 'RST_STREAM'))) {
+     this._ended = true;
+   }
+ 
+   if ((frame.type === 'DATA') && (frame.data.length > 0)) {
+-    this._receive(frame, () => {
++    this._receive(frame, function() {
+       this._received += frame.data.length;
+       if (!this._restoreWindowTimer) {
+         this._restoreWindowTimer = setImmediate(this._restoreWindow.bind(this));
+       }
+       callback();
+-    });
++    }.bind(this));
+   }
+ 
+   else {
+     this._receive(frame, callback);
+   }
+ 
+   if (sentToUs && (frame.type === 'WINDOW_UPDATE')) {
+     this._updateWindow(frame);
+diff --git a/testing/xpcshell/node-http2/lib/protocol/stream.js b/testing/xpcshell/node-http2/lib/protocol/stream.js
+--- a/testing/xpcshell/node-http2/lib/protocol/stream.js
++++ b/testing/xpcshell/node-http2/lib/protocol/stream.js
+@@ -57,16 +57,17 @@ function Stream(log, connection) {
+ 
+   // * sending and receiving frames to/from the upstream connection
+   this._initializeDataFlow();
+ 
+   // * maintaining the state of the stream (idle, open, closed, etc.) and error detection
+   this._initializeState();
+ 
+   this.connection = connection;
++  this.sentEndStream = false;
+ }
+ 
+ Stream.prototype = Object.create(Duplex.prototype, { constructor: { value: Stream } });
+ 
+ // Managing the stream
+ // -------------------
+ 
+ // the default stream priority is 2^30
+@@ -101,16 +102,26 @@ Stream.prototype.headers = function head
+   this._pushUpstream({
+     type: 'HEADERS',
+     flags: {},
+     stream: this.id,
+     headers: headers
+   });
+ };
+ 
++Stream.prototype.trailers = function trailers(trailers) {
++  this.sentEndStream = true;
++  this._pushUpstream({
++    type: 'HEADERS',
++    flags: {'END_STREAM': true},
++    stream: this.id,
++    headers: trailers
++  });
++};
++
+ Stream.prototype._onHeaders = function _onHeaders(frame) {
+   if (frame.priority !== undefined) {
+     this.priority(frame.priority, true);
+   }
+   this.emit('headers', frame.headers);
+ };
+ 
+ Stream.prototype.priority = function priority(priority, peer) {
+@@ -337,16 +348,23 @@ Stream.prototype._send = function _send(
+ var emptyBuffer = new Buffer(0);
+ Stream.prototype._finishing = function _finishing() {
+   var endFrame = {
+     type: 'DATA',
+     flags: { END_STREAM: true },
+     stream: this.id,
+     data: emptyBuffer
+   };
++
++  if (this.sentEndStream) {
++    this._log.debug('Already sent END_STREAM, not sending again.');
++    return;
++  }
++
++  this.sentEndStream = true;
+   var lastFrame = this.upstream.getLastQueuedFrame();
+   if (lastFrame && ((lastFrame.type === 'DATA') || (lastFrame.type === 'HEADERS'))) {
+     this._log.debug({ frame: lastFrame }, 'Marking last frame with END_STREAM flag.');
+     lastFrame.flags.END_STREAM = true;
+     this._transition(true, endFrame);
+   } else {
+     this._pushUpstream(endFrame);
+   }
+diff --git a/testing/xpcshell/node-http2/package.json b/testing/xpcshell/node-http2/package.json
+--- a/testing/xpcshell/node-http2/package.json
++++ b/testing/xpcshell/node-http2/package.json
+@@ -1,15 +1,15 @@
+ {
+   "name": "http2",
+-  "version": "3.3.6",
++  "version": "3.3.8",
+   "description": "An HTTP/2 client and server implementation",
+   "main": "lib/index.js",
+-  "engines" : {
+-    "node" : ">=0.12.0"
++  "engines": {
++    "node": ">=0.12.0 <9.0.0"
+   },
+   "devDependencies": {
+     "istanbul": "*",
+     "chai": "*",
+     "mocha": "*",
+     "docco": "*",
+     "bunyan": "*"
+   },
+diff --git a/testing/xpcshell/node-http2/test/flow.js b/testing/xpcshell/node-http2/test/flow.js
+--- a/testing/xpcshell/node-http2/test/flow.js
++++ b/testing/xpcshell/node-http2/test/flow.js
+@@ -224,25 +224,25 @@ describe('flow.js', function() {
+           if (frame.type === 'DATA') {
+             expect(frame.data.length).to.be.lte(MAX_PAYLOAD_SIZE);
+             output.push(frame.data);
+           }
+           if (frame.flags.END_STREAM) {
+             this.emit('end_stream');
+           }
+           if (frame.type === 'BLOCKED') {
+-            setTimeout(() => {
++            setTimeout(function() {
+               this._push({
+                 type: 'WINDOW_UPDATE',
+                 flags: {},
+                 stream: this._flowControlId,
+                 window_size: this._received
+               });
+               this._received = 0;
+-            }, 20);
++            }.bind(this), 20);
+           }
+           callback();
+         };
+ 
+         // Checking results
+         flow2.on('end_stream', function() {
+           input = util.concat(input);
+           output = util.concat(output);
+diff --git a/testing/xpcshell/node-http2/test/stream.js b/testing/xpcshell/node-http2/test/stream.js
+--- a/testing/xpcshell/node-http2/test/stream.js
++++ b/testing/xpcshell/node-http2/test/stream.js
+@@ -18,17 +18,17 @@ function execute_sequence(stream, sequen
+     sequence = stream;
+     stream = createStream();
+   }
+ 
+   var outgoing_frames = [];
+ 
+   var emit = stream.emit, events = [];
+   stream.emit = function(name) {
+-    if (recorded_events.includes(name)) {
++    if (recorded_events.indexOf(name) !== -1) {
+       events.push({ name: name, data: Array.prototype.slice.call(arguments, 1) });
+     }
+     return emit.apply(this, arguments);
+   };
+ 
+   var commands = [], checks = [];
+   sequence.forEach(function(step) {
+     if ('method' in step || 'incoming' in step || 'outgoing' in step || 'wait' in step || 'set_state' in step) {

+ 275 - 0
mozilla-release/patches/1429973-1-60a1.patch

@@ -0,0 +1,275 @@
+# HG changeset patch
+# User Nicholas Hurley <hurley@mozilla.com>
+# Date 1517526863 28800
+#      Thu Feb 01 15:14:23 2018 -0800
+# Node ID 446096b9960dd7bcd41e2cd8130e3c1156a939a9
+# Parent  ff4979a579ba6dd23a66c2a58b676b016664116c
+Bug 1429973 part 1 - plumb through trailers in h2 to support server-timing. r=bagder
+
+MozReview-Commit-ID: JV1Ikb9cYCV
+
+diff --git a/netwerk/protocol/http/Http2Session.cpp b/netwerk/protocol/http/Http2Session.cpp
+--- a/netwerk/protocol/http/Http2Session.cpp
++++ b/netwerk/protocol/http/Http2Session.cpp
+@@ -1438,23 +1438,26 @@ Http2Session::RecvHeaders(Http2Session *
+ // should be reset with a PROTOCOL_ERROR, NS_OK when the response headers were
+ // fine, and any other error is fatal to the session.
+ nsresult
+ Http2Session::ResponseHeadersComplete()
+ {
+   LOG3(("Http2Session::ResponseHeadersComplete %p for 0x%X fin=%d",
+         this, mInputFrameDataStream->StreamID(), mInputFrameFinal));
+ 
+-  // only interpret headers once, afterwards ignore as trailers
++  // Anything prior to AllHeadersReceived() => true is actual headers. After
++  // that, we need to handle them as trailers instead (which are special-cased
++  // so we don't have to use the nasty chunked parser for all h2, just in case).
+   if (mInputFrameDataStream->AllHeadersReceived()) {
+-    LOG3(("Http2Session::ResponseHeadersComplete extra headers"));
++    LOG3(("Http2Session::ResponseHeadersComplete processing trailers"));
+     MOZ_ASSERT(mInputFrameFlags & kFlag_END_STREAM);
+-    nsresult rv = UncompressAndDiscard(false);
++    nsresult rv = mInputFrameDataStream->ConvertResponseTrailers(&mDecompressor,
++        mDecompressBuffer);
+     if (NS_FAILED(rv)) {
+-      LOG3(("Http2Session::ResponseHeadersComplete extra uncompress failed\n"));
++      LOG3(("Http2Session::ResponseHeadersComplete trailer conversion failed\n"));
+       return rv;
+     }
+     mFlatHTTPResponseHeadersOut = 0;
+     mFlatHTTPResponseHeaders.Truncate();
+     if (mInputFrameFinal) {
+       // need to process the fin
+       ChangeDownstreamState(PROCESSING_COMPLETE_HEADERS);
+     } else {
+diff --git a/netwerk/protocol/http/Http2Stream.cpp b/netwerk/protocol/http/Http2Stream.cpp
+--- a/netwerk/protocol/http/Http2Stream.cpp
++++ b/netwerk/protocol/http/Http2Stream.cpp
+@@ -1010,16 +1010,18 @@ Http2Stream::GenerateDataFrameHeader(uin
+ // into HTTP/1 format
+ nsresult
+ Http2Stream::ConvertResponseHeaders(Http2Decompressor *decompressor,
+                                     nsACString &aHeadersIn,
+                                     nsACString &aHeadersOut,
+                                     int32_t &httpResponseCode)
+ {
+   aHeadersOut.Truncate();
++  // Add in some space to hopefully not have to reallocate while decompressing
++  // the headers. 512 bytes seems like a good enough number.
+   aHeadersOut.SetCapacity(aHeadersIn.Length() + 512);
+ 
+   nsresult rv =
+     decompressor->DecodeHeaderBlock(reinterpret_cast<const uint8_t *>(aHeadersIn.BeginReading()),
+                                     aHeadersIn.Length(),
+                                     aHeadersOut, false);
+   if (NS_FAILED(rv)) {
+     LOG3(("Http2Stream::ConvertResponseHeaders %p decode Error\n", this));
+@@ -1086,16 +1088,18 @@ Http2Stream::ConvertResponseHeaders(Http
+ // ConvertPushHeaders is used to convert the pushed request headers
+ // into HTTP/1 format and report
+ nsresult
+ Http2Stream::ConvertPushHeaders(Http2Decompressor *decompressor,
+                                 nsACString &aHeadersIn,
+                                 nsACString &aHeadersOut)
+ {
+   aHeadersOut.Truncate();
++  // Add in some space to hopefully not have to reallocate while decompressing
++  // the headers. 512 bytes seems like a good enough number.
+   aHeadersOut.SetCapacity(aHeadersIn.Length() + 512);
+   nsresult rv =
+     decompressor->DecodeHeaderBlock(reinterpret_cast<const uint8_t *>(aHeadersIn.BeginReading()),
+                                     aHeadersIn.Length(),
+                                     aHeadersOut, true);
+   if (NS_FAILED(rv)) {
+     LOG3(("Http2Stream::ConvertPushHeaders %p Error\n", this));
+     return rv;
+@@ -1122,16 +1126,45 @@ Http2Stream::ConvertPushHeaders(Http2Dec
+ 
+   aHeadersIn.Truncate();
+   LOG (("id 0x%X decoded push headers %s %s %s are:\n%s", mStreamID,
+         mHeaderScheme.get(), mHeaderHost.get(), mHeaderPath.get(),
+         aHeadersOut.BeginReading()));
+   return NS_OK;
+ }
+ 
++nsresult
++Http2Stream::ConvertResponseTrailers(Http2Decompressor *decompressor,
++                                     nsACString &aTrailersIn)
++{
++  LOG3(("Http2Stream::ConvertResponseTrailers %p", this));
++  nsAutoCString flatTrailers;
++  // Add in some space to hopefully not have to reallocate while decompressing
++  // the headers. 512 bytes seems like a good enough number.
++  flatTrailers.SetCapacity(aTrailersIn.Length() + 512);
++
++  nsresult rv =
++    decompressor->DecodeHeaderBlock(reinterpret_cast<const uint8_t *>(aTrailersIn.BeginReading()),
++                                    aTrailersIn.Length(),
++                                    flatTrailers, false);
++  if (NS_FAILED(rv)) {
++    LOG3(("Http2Stream::ConvertResponseTrailers %p decode Error", this));
++    return rv;
++  }
++
++  nsHttpTransaction *trans = mTransaction->QueryHttpTransaction();
++  if (trans) {
++    trans->SetHttpTrailers(flatTrailers);
++  } else {
++    LOG3(("Http2Stream::ConvertResponseTrailers %p no trans", this));
++  }
++
++  return NS_OK;
++}
++
+ void
+ Http2Stream::Close(nsresult reason)
+ {
+   // In case we are connected to a push, make sure the push knows we are closed,
+   // so it doesn't try to give us any more DATA that comes on it after our close.
+   ClearPushSource();
+ 
+   mTransaction->Close(reason);
+diff --git a/netwerk/protocol/http/Http2Stream.h b/netwerk/protocol/http/Http2Stream.h
+--- a/netwerk/protocol/http/Http2Stream.h
++++ b/netwerk/protocol/http/Http2Stream.h
+@@ -120,16 +120,18 @@ public:
+   void UpdateTransportReadEvents(uint32_t count);
+ 
+   // NS_ERROR_ABORT terminates stream, other failure terminates session
+   MOZ_MUST_USE nsresult ConvertResponseHeaders(Http2Decompressor *,
+                                                nsACString &,
+                                                nsACString &, int32_t &);
+   MOZ_MUST_USE nsresult ConvertPushHeaders(Http2Decompressor *, nsACString &,
+                                            nsACString &);
++  MOZ_MUST_USE nsresult ConvertResponseTrailers(Http2Decompressor *,
++                                                nsACString &);
+ 
+   bool AllowFlowControlledWrite();
+   void UpdateServerReceiveWindow(int32_t delta);
+   int64_t ServerReceiveWindow() { return mServerReceiveWindow; }
+ 
+   void DecrementClientReceiveWindow(uint32_t delta) {
+     mClientReceiveWindow -= delta;
+     mLocalUnacked += delta;
+diff --git a/netwerk/protocol/http/nsHttpTransaction.cpp b/netwerk/protocol/http/nsHttpTransaction.cpp
+--- a/netwerk/protocol/http/nsHttpTransaction.cpp
++++ b/netwerk/protocol/http/nsHttpTransaction.cpp
+@@ -1773,19 +1773,19 @@ nsHttpTransaction::HandleContent(char *b
+ 
+     LOG(("nsHttpTransaction::HandleContent [this=%p count=%u read=%u mContentRead=%" PRId64 " mContentLength=%" PRId64 "]\n",
+         this, count, *contentRead, mContentRead, mContentLength));
+ 
+     // check for end-of-file
+     if ((mContentRead == mContentLength) ||
+         (mChunkedDecoder && mChunkedDecoder->ReachedEOF())) {
+         MutexAutoLock lock(*nsHttp::GetLock());
+-        mForTakeResponseTrailers = mChunkedDecoder
+-            ? mChunkedDecoder->TakeTrailers()
+-            : nullptr;
++        if (mChunkedDecoder) {
++            mForTakeResponseTrailers = mChunkedDecoder->TakeTrailers();
++        }
+ 
+         // the transaction is done with a complete response.
+         mTransactionDone = true;
+         mResponseIsComplete = true;
+         ReleaseBlockingTransaction();
+ 
+         if (TimingEnabled()) {
+             SetResponseEnd(TimeStamp::Now());
+@@ -2429,10 +2429,47 @@ void
+ nsHttpTransaction::Refused0RTT()
+ {
+     LOG(("nsHttpTransaction::Refused0RTT %p\n", this));
+     if (mEarlyDataDisposition == EARLY_ACCEPTED) {
+         mEarlyDataDisposition = EARLY_SENT; // undo accepted state
+     }
+ }
+ 
++void
++nsHttpTransaction::SetHttpTrailers(nsCString &aTrailers)
++{
++    LOG(("nsHttpTransaction::SetHttpTrailers %p", this));
++    LOG(("[\n    %s\n]", aTrailers.BeginReading()));
++    if (!mForTakeResponseTrailers) {
++        mForTakeResponseTrailers = new nsHttpHeaderArray();
++    }
++
++    int32_t cur = 0;
++    int32_t len = aTrailers.Length();
++    while (cur < len) {
++        int32_t newline = aTrailers.FindCharInSet("\n", cur);
++        if (newline == -1) {
++            newline = len;
++        }
++
++        int32_t end = aTrailers[newline - 1] == '\r' ? newline - 1 : newline;
++        nsDependentCSubstring line(aTrailers, cur, end);
++        nsHttpAtom hdr;
++        nsAutoCString hdrNameOriginal;
++        nsAutoCString val;
++        if (NS_SUCCEEDED(mForTakeResponseTrailers->ParseHeaderLine(line, &hdr, &hdrNameOriginal, &val))) {
++            if (hdr == nsHttp::Server_Timing) {
++                Unused << mForTakeResponseTrailers->SetHeaderFromNet(hdr, hdrNameOriginal, val, true);
++            }
++        }
++
++        cur = newline + 1;
++    }
++
++    if (mForTakeResponseTrailers->Count() == 0) {
++        // Didn't find a Server-Timing header, so get rid of this.
++        mForTakeResponseTrailers = nullptr;
++    }
++}
++
+ } // namespace net
+ } // namespace mozilla
+diff --git a/netwerk/protocol/http/nsHttpTransaction.cpp.1605659.later b/netwerk/protocol/http/nsHttpTransaction.cpp.1605659.later
+deleted file mode 100644
+--- a/netwerk/protocol/http/nsHttpTransaction.cpp.1605659.later
++++ /dev/null
+@@ -1,21 +0,0 @@
+---- nsHttpTransaction.cpp
+-+++ nsHttpTransaction.cpp
+-@@ -2456,17 +2456,17 @@ void nsHttpTransaction::SetHttpTrailers(
+-     int32_t newline = aTrailers.FindCharInSet("\n", cur);
+-     if (newline == -1) {
+-       newline = len;
+-     }
+- 
+-     int32_t end =
+-         (newline && aTrailers[newline - 1] == '\r') ? newline - 1 : newline;
+-     nsDependentCSubstring line(aTrailers, cur, end);
+--    nsHttpAtom hdr = {nullptr};
+-+    nsHttpAtom hdr;
+-     nsAutoCString hdrNameOriginal;
+-     nsAutoCString val;
+-     if (NS_SUCCEEDED(httpTrailers->ParseHeaderLine(line, &hdr, &hdrNameOriginal,
+-                                                    &val))) {
+-       if (hdr == nsHttp::Server_Timing) {
+-         Unused << httpTrailers->SetHeaderFromNet(hdr, hdrNameOriginal, val,
+-                                                  true);
+-       }
+diff --git a/netwerk/protocol/http/nsHttpTransaction.h b/netwerk/protocol/http/nsHttpTransaction.h
+--- a/netwerk/protocol/http/nsHttpTransaction.h
++++ b/netwerk/protocol/http/nsHttpTransaction.h
+@@ -186,16 +186,18 @@ public:
+     MOZ_MUST_USE nsresult RestartOnFastOpenError() override;
+ 
+     uint64_t TopLevelOuterContentWindowId() override
+     {
+         return mTopLevelOuterContentWindowId;
+     }
+ 
+     void SetFastOpenStatus(uint8_t aStatus) override;
++
++    void SetHttpTrailers(nsCString &aTrailers);
+ private:
+     friend class DeleteHttpTransaction;
+     virtual ~nsHttpTransaction();
+ 
+     MOZ_MUST_USE nsresult Restart();
+     char    *LocateHttpStart(char *buf, uint32_t len,
+                              bool aAllowPartialMatch);
+     MOZ_MUST_USE nsresult ParseLine(nsACString &line);

+ 180 - 0
mozilla-release/patches/1429973-2-60a1.patch

@@ -0,0 +1,180 @@
+# HG changeset patch
+# User Nicholas Hurley <hurley@mozilla.com>
+# Date 1518718297 28800
+#      Thu Feb 15 10:11:37 2018 -0800
+# Node ID 4bc56ae6d0fe2fac78b8d89e7bb7cdce26c61a67
+# Parent  4848373ed2ad3283e0ad67e6847c672e8fd2e565
+Bug 1429973 part 2 - Move server-timing tests into http/2. r=bagder
+
+MozReview-Commit-ID: JuQUUAOnW4g
+
+diff --git a/netwerk/test/unit/test_header_Server_Timing.js b/netwerk/test/unit/test_header_Server_Timing.js
+--- a/netwerk/test/unit/test_header_Server_Timing.js
++++ b/netwerk/test/unit/test_header_Server_Timing.js
+@@ -1,89 +1,74 @@
+ /* 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/. */
+ 
+ //
+ //  HTTP Server-Timing header test
+ //
+ 
+-Cu.import("resource://testing-common/httpd.js");
+-Cu.import("resource://gre/modules/NetUtil.jsm");
+-
+-XPCOMUtils.defineLazyGetter(this, "URL", function() {
+-  return "http://localhost:" + httpServer.identity.primaryPort + "/content";
+-});
+-
+-let httpServer = null;
++ChromeUtils.import("resource://gre/modules/NetUtil.jsm");
+ 
+ function make_and_open_channel(url, callback) {
+   let chan = NetUtil.newChannel({uri: url, loadUsingSystemPrincipal: true});
+   chan.asyncOpen2(new ChannelListener(callback, null, CL_ALLOW_UNKNOWN_CL));
+ }
+ 
+-var respnseServerTiming = [{metric:"metric", duration:"123.4", description:"description"},
+-                           {metric:"metric2", duration:"456.78", description:"description1"}];
++var responseServerTiming = [{metric:"metric", duration:"123.4", description:"description"},
++                            {metric:"metric2", duration:"456.78", description:"description1"}];
+ var trailerServerTiming = [{metric:"metric3", duration:"789.11", description:"description2"},
+                            {metric:"metric4", duration:"1112.13", description:"description3"}];
+ 
+-function createServerTimingHeader(headerData) {
+-  var header = "";
+-  for (var i = 0; i < headerData.length; i++) {
+-    header += "Server-Timing:" + headerData[i].metric + ";" +
+-              "dur=" + headerData[i].duration + ";" +
+-              "desc=" + headerData[i].description + "\r\n";
+-  }
+-  return header;
++function readFile(file) {
++  let fstream = Cc["@mozilla.org/network/file-input-stream;1"]
++                  .createInstance(Ci.nsIFileInputStream);
++  fstream.init(file, -1, 0, 0);
++  let data = NetUtil.readInputStreamToString(fstream, fstream.available());
++  fstream.close();
++  return data;
+ }
+ 
+-function contentHandler(metadata, response)
+-{
+-  var body = "c\r\ndata reached\r\n3\r\nhej\r\n0\r\n";
+-
+-  response.seizePower();
+-  response.write("HTTP/1.1 200 OK\r\n");
+-  response.write("Content-Type: text/plain\r\n");
+-  response.write(createServerTimingHeader(respnseServerTiming));
+-
+-  response.write("Transfer-Encoding: chunked\r\n");
+-  response.write("\r\n");
+-  response.write(body);
+-  response.write(createServerTimingHeader(trailerServerTiming));
+-  response.write("\r\n");
+-  response.finish();
++function addCertFromFile(certdb, filename, trustString) {
++  let certFile = do_get_file(filename, false);
++  let der = readFile(certFile);
++  certdb.addCert(der, trustString);
+ }
+ 
+ function run_test()
+ {
+-  Services.prefs.setBoolPref("network.http.allow-plaintext-server-timing", true);
++  do_test_pending();
++
++  // Set up to allow the cert presented by the server
++  do_get_profile();
++  let certdb = Cc["@mozilla.org/security/x509certdb;1"]
++                  .getService(Ci.nsIX509CertDB);
++  addCertFromFile(certdb, "CA.cert.der", "CTu,u,u");
++
++  Services.prefs.setCharPref("network.dns.localDomains", "foo.example.com");
+   registerCleanupFunction(() => {
+-    Services.prefs.clearUserPref("network.http.allow-plaintext-server-timing");
++    Services.prefs.clearUserPref("network.dns.localDomains");
+   });
+ 
+-  httpServer = new HttpServer();
+-  httpServer.registerPathHandler("/content", contentHandler);
+-  httpServer.start(-1);
+-
+-  do_test_pending();
+-  make_and_open_channel(URL, readServerContent);
++  var env = Cc["@mozilla.org/process/environment;1"].getService(Ci.nsIEnvironment);
++  var serverPort = env.get("MOZHTTP2_PORT");
++  make_and_open_channel("https://foo.example.com:" + serverPort + "/server-timing", readServerContent);
+ }
+ 
+ function checkServerTimingContent(headers) {
+-  var expectedResult = respnseServerTiming.concat(trailerServerTiming);
++  var expectedResult = responseServerTiming.concat(trailerServerTiming);
+   Assert.equal(headers.length, expectedResult.length);
+ 
+   for (var i = 0; i < expectedResult.length; i++) {
+     let header = headers.queryElementAt(i, Ci.nsIServerTiming);
+     Assert.equal(header.name, expectedResult[i].metric);
+     Assert.equal(header.description, expectedResult[i].description);
+     Assert.equal(header.duration, parseFloat(expectedResult[i].duration));
+   }
+ }
+ 
+ function readServerContent(request, buffer)
+ {
+   let channel = request.QueryInterface(Ci.nsITimedChannel);
+   let headers = channel.serverTiming.QueryInterface(Ci.nsIArray);
+   checkServerTimingContent(headers);
+-
+-  httpServer.stop(do_test_finished);
++  do_test_finished();
+ }
+diff --git a/netwerk/test/unit/xpcshell.ini b/netwerk/test/unit/xpcshell.ini
+--- a/netwerk/test/unit/xpcshell.ini
++++ b/netwerk/test/unit/xpcshell.ini
+@@ -404,9 +404,12 @@ skip-if = os == "android"
+ [test_bug1312782_http1.js]
+ [test_bug1355539_http1.js]
+ [test_bug1378385_http1.js]
+ [test_tls_flags_separate_connections.js]
+ [test_tls_flags.js]
+ [test_uri_mutator.js]
+ [test_bug1411316_http1.js]
+ [test_header_Server_Timing.js]
++# Test requires http/2, and http/2 server doesn't run on android.
++skip-if = os == "android"
++run-sequentially = node server exceptions dont replay well
+ [test_substituting_protocol_handler.js]
+diff --git a/testing/xpcshell/moz-http2/moz-http2.js b/testing/xpcshell/moz-http2/moz-http2.js
+--- a/testing/xpcshell/moz-http2/moz-http2.js
++++ b/testing/xpcshell/moz-http2/moz-http2.js
+@@ -842,16 +842,28 @@ function handleRequest(req, res) {
+       'content-type': 'text/html',
+       'pushed' : 'yes',
+       'content-length' : pushedContent.length,
+       'X-Connection-Http2': 'yes'
+     });
+     push.end(pushedContent);
+   }
+ 
++  // For test_header_Server_Timing.js
++  else if (u.pathname === "/server-timing") {
++    res.setHeader('Content-Type', 'text/plain');
++    res.setHeader('Content-Length', '12');
++    res.setHeader('Trailer', 'Server-Timing');
++    res.setHeader('Server-Timing', 'metric; dur=123.4; desc=description, metric2; dur=456.78; desc=description1');
++    res.write('data reached');
++    res.addTrailers({'Server-Timing': 'metric3; dur=789.11; desc=description2, metric4; dur=1112.13; desc=description3'});
++    res.end();
++    return;
++  }
++
+   res.setHeader('Content-Type', 'text/html');
+   if (req.httpVersionMajor != 2) {
+     res.setHeader('Connection', 'close');
+   }
+   res.writeHead(200);
+   res.end(content);
+ }
+ 

+ 134 - 0
mozilla-release/patches/1429973-3-60a1.patch

@@ -0,0 +1,134 @@
+# HG changeset patch
+# User Nicholas Hurley <hurley@mozilla.com>
+# Date 1518719444 28800
+#      Thu Feb 15 10:30:44 2018 -0800
+# Node ID 69c3b8eeba6383653db47a78ff7a35a685099e42
+# Parent  ba62bb691755487a8072b9f8073ebb5ab2e03755
+Bug 1429973 part 3 - Remove hidden pref to allow plaintext server-timing. r=bagder
+
+MozReview-Commit-ID: 2MfcvRXq7We
+
+diff --git a/netwerk/protocol/http/HttpBaseChannel.cpp b/netwerk/protocol/http/HttpBaseChannel.cpp
+--- a/netwerk/protocol/http/HttpBaseChannel.cpp
++++ b/netwerk/protocol/http/HttpBaseChannel.cpp
+@@ -4503,18 +4503,17 @@ ParseServerTimingHeader(const nsAutoPtr<
+ }
+ 
+ NS_IMETHODIMP
+ HttpBaseChannel::GetServerTiming(nsIArray **aServerTiming)
+ {
+   NS_ENSURE_ARG_POINTER(aServerTiming);
+ 
+   bool isHTTPS = false;
+-  if (gHttpHandler->AllowPlaintextServerTiming() ||
+-      (NS_SUCCEEDED(mURI->SchemeIs("https", &isHTTPS)) && isHTTPS)) {
++  if (NS_SUCCEEDED(mURI->SchemeIs("https", &isHTTPS)) && isHTTPS) {
+     nsTArray<nsCOMPtr<nsIServerTiming>> data;
+     nsresult rv = NS_OK;
+     nsCOMPtr<nsIMutableArray> array = do_CreateInstance(NS_ARRAY_CONTRACTID, &rv);
+     NS_ENSURE_SUCCESS(rv, rv);
+ 
+     ParseServerTimingHeader(mResponseHead, array);
+     ParseServerTimingHeader(mResponseTrailers, array);
+ 
+diff --git a/netwerk/protocol/http/nsHttpHandler.cpp b/netwerk/protocol/http/nsHttpHandler.cpp
+--- a/netwerk/protocol/http/nsHttpHandler.cpp
++++ b/netwerk/protocol/http/nsHttpHandler.cpp
+@@ -280,17 +280,16 @@ nsHttpHandler::nsHttpHandler()
+     , mUseFastOpen(true)
+     , mFastOpenConsecutiveFailureLimit(5)
+     , mFastOpenConsecutiveFailureCounter(0)
+     , mFastOpenStallsLimit(3)
+     , mFastOpenStallsCounter(0)
+     , mFastOpenStallsIdleTime(10)
+     , mFastOpenStallsTimeout(20)
+     , mActiveTabPriority(true)
+-    , mAllowPlaintextServerTiming(false)
+     , mProcessId(0)
+     , mNextChannelId(1)
+ {
+     LOG(("Creating nsHttpHandler [this=%p].\n", this));
+ 
+     mUserAgentOverride.SetIsVoid(true);
+ 
+     MOZ_ASSERT(!gHttpHandler, "HTTP handler already created!");
+@@ -462,17 +461,16 @@ nsHttpHandler::Init()
+         prefBranch->AddObserver(HTTP_PREF("tcp_keepalive.long_lived_connections"), this, true);
+         prefBranch->AddObserver(SAFE_HINT_HEADER_VALUE, this, true);
+         prefBranch->AddObserver(SECURITY_PREFIX, this, true);
+         prefBranch->AddObserver(TCP_FAST_OPEN_ENABLE, this, true);
+         prefBranch->AddObserver(TCP_FAST_OPEN_FAILURE_LIMIT, this, true);
+         prefBranch->AddObserver(TCP_FAST_OPEN_STALLS_LIMIT, this, true);
+         prefBranch->AddObserver(TCP_FAST_OPEN_STALLS_IDLE, this, true);
+         prefBranch->AddObserver(TCP_FAST_OPEN_STALLS_TIMEOUT, this, true);
+-        prefBranch->AddObserver(HTTP_PREF("allow-plaintext-server-timing"), this, false);
+         PrefsChanged(prefBranch, nullptr);
+     }
+ 
+     nsHttpChannelAuthProvider::InitializePrefs();
+ 
+     mMisc.AssignLiteral("rv:91.0");
+ 
+     mCompatFirefox.AssignLiteral("Firefox/91.0");
+@@ -1750,20 +1748,16 @@ nsHttpHandler::PrefsChanged(nsIPrefBranc
+             if (ratio > 0 && ratio < 1) {
+                 mFocusedWindowTransactionRatio = ratio;
+             } else {
+                 NS_WARNING("Wrong value for focused_window_transaction_ratio");
+             }
+         }
+     }
+ 
+-    if (PREF_CHANGED(HTTP_PREF("allow-plaintext-server-timing"))) {
+-        Unused << prefs->GetBoolPref(HTTP_PREF("allow-plaintext-server-timing"), &mAllowPlaintextServerTiming);
+-    }
+-
+     //
+     // INTL options
+     //
+ 
+     if (PREF_CHANGED(INTL_ACCEPT_LANGUAGES)) {
+         // We don't want to set the new accept languages here since
+         // this pref is a complex type and it may be racy with flushing
+         // string resources.
+diff --git a/netwerk/protocol/http/nsHttpHandler.h b/netwerk/protocol/http/nsHttpHandler.h
+--- a/netwerk/protocol/http/nsHttpHandler.h
++++ b/netwerk/protocol/http/nsHttpHandler.h
+@@ -139,18 +139,16 @@ public:
+     uint32_t       TailBlockingDelayQuantum(bool aAfterDOMContentLoaded) {
+       return aAfterDOMContentLoaded ? mTailDelayQuantumAfterDCL : mTailDelayQuantum;
+     }
+     uint32_t       TailBlockingDelayMax() { return mTailDelayMax; }
+     uint32_t       TailBlockingTotalMax() { return mTailTotalMax; }
+ 
+     uint32_t       ThrottlingReadLimit() { return mThrottleVersion == 1 ? 0 : mThrottleReadLimit; }
+ 
+-    bool           AllowPlaintextServerTiming() { return mAllowPlaintextServerTiming; }
+-
+     // TCP Keepalive configuration values.
+ 
+     // Returns true if TCP keepalive should be enabled for short-lived conns.
+     bool TCPKeepaliveEnabledForShortLivedConns() {
+       return mTCPKeepaliveShortLivedEnabled;
+     }
+     // Return time (secs) that a connection is consider short lived (for TCP
+     // keepalive purposes). After this time, the connection is long-lived.
+@@ -640,18 +638,16 @@ private:
+     uint32_t mFastOpenStallsLimit;
+     uint32_t mFastOpenStallsCounter;
+     uint32_t mFastOpenStallsIdleTime;
+     uint32_t mFastOpenStallsTimeout;
+ 
+     // If true, the transactions from active tab will be dispatched first.
+     bool mActiveTabPriority;
+ 
+-    bool mAllowPlaintextServerTiming;
+-
+ private:
+     // For Rate Pacing Certain Network Events. Only assign this pointer on
+     // socket thread.
+     void MakeNewRequestTokenBucket();
+     RefPtr<EventTokenBucket> mRequestTokenBucket;
+ 
+ public:
+     // Socket thread only

+ 74 - 0
mozilla-release/patches/1436692-60a1.patch

@@ -0,0 +1,74 @@
+# HG changeset patch
+# User Andrea Marchesini <amarchesini@mozilla.com>
+# Date 1518108205 -3600
+# Node ID 0fdcc0c8f50f2613722928710057c7fdc6101314
+# Parent  10c35d0b440233ebb8f387d3976e075ff222bc6e
+Bug 1436692 - Implement PerformanceObserver::takeRecords(), r=valentin
+
+diff --git a/dom/performance/PerformanceObserver.cpp b/dom/performance/PerformanceObserver.cpp
+--- a/dom/performance/PerformanceObserver.cpp
++++ b/dom/performance/PerformanceObserver.cpp
+@@ -215,8 +215,15 @@ void
+ PerformanceObserver::Disconnect()
+ {
+   if (mConnected) {
+     MOZ_ASSERT(mPerformance);
+     mPerformance->RemoveObserver(this);
+     mConnected = false;
+   }
+ }
++
++void
++PerformanceObserver::TakeRecords(nsTArray<RefPtr<PerformanceEntry>>& aRetval)
++{
++  MOZ_ASSERT(aRetval.IsEmpty());
++  aRetval.SwapElements(mQueuedEntries);
++}
+diff --git a/dom/performance/PerformanceObserver.h b/dom/performance/PerformanceObserver.h
+--- a/dom/performance/PerformanceObserver.h
++++ b/dom/performance/PerformanceObserver.h
+@@ -51,16 +51,18 @@ public:
+                                JS::Handle<JSObject*> aGivenProto) override;
+ 
+   nsISupports* GetParentObject() const { return mOwner; }
+ 
+   void Observe(const PerformanceObserverInit& aOptions);
+ 
+   void Disconnect();
+ 
++  void TakeRecords(nsTArray<RefPtr<PerformanceEntry>>& aRetval);
++
+   void Notify();
+   void QueueEntry(PerformanceEntry* aEntry);
+ 
+ private:
+   ~PerformanceObserver();
+ 
+   nsCOMPtr<nsISupports> mOwner;
+   RefPtr<PerformanceObserverCallback> mCallback;
+diff --git a/dom/webidl/PerformanceObserver.webidl b/dom/webidl/PerformanceObserver.webidl
+--- a/dom/webidl/PerformanceObserver.webidl
++++ b/dom/webidl/PerformanceObserver.webidl
+@@ -7,17 +7,19 @@
+  * https://w3c.github.io/performance-timeline/#the-performanceobserver-interface
+  */
+ 
+ dictionary PerformanceObserverInit {
+   required sequence<DOMString> entryTypes;
+   boolean buffered = false;
+ };
+ 
+-callback PerformanceObserverCallback = void (PerformanceObserverEntryList entries, PerformanceObserver observer);
++callback PerformanceObserverCallback = void (PerformanceObserverEntryList entries,
++                                             PerformanceObserver observer);
+ 
+ [Func="Performance::IsObserverEnabled",
+  Constructor(PerformanceObserverCallback callback),
+  Exposed=(Window,Worker)]
+ interface PerformanceObserver {
+-  void observe(PerformanceObserverInit options);
+-  void disconnect();
++    void                 observe(PerformanceObserverInit options);
++    void                 disconnect();
++    PerformanceEntryList takeRecords();
+ };

+ 287 - 0
mozilla-release/patches/1436744-60a1.patch

@@ -0,0 +1,287 @@
+# HG changeset patch
+# User Andrea Marchesini <amarchesini@mozilla.com>
+# Date 1518465742 -3600
+# Node ID d33f2acef1ed12be6bce66e8a615fa17b1d9be9b
+# Parent  64dc1980c3fa40cba6c5519e5815500c72f42f47
+Bug 1436744 - Get rid of WorkerCheckAPIExposureOnMainThreadRunnable, r=catalinb
+
+diff --git a/dom/base/DOMPrefsInternal.h b/dom/base/DOMPrefsInternal.h
+--- a/dom/base/DOMPrefsInternal.h
++++ b/dom/base/DOMPrefsInternal.h
+@@ -34,23 +34,25 @@ DOM_PREF(PushEnabled, "dom.push.enabled"
+ DOM_PREF(StreamsEnabled, "dom.streams.enabled")
+ DOM_PREF(RequestContextEnabled, "dom.requestcontext.enabled")
+ DOM_PREF(OffscreenCanvasEnabled, "gfx.offscreencanvas.enabled")
+ DOM_PREF(WebkitBlinkDirectoryPickerEnabled, "dom.webkitBlink.dirPicker.enabled")
+ DOM_PREF(NetworkInformationEnabled, "dom.netinfo.enabled")
+ DOM_PREF(FetchObserverEnabled, "dom.fetchObserver.enabled")
+ DOM_PREF(ResistFingerprintingEnabled, "privacy.resistFingerprinting")
+ DOM_PREF(DevToolsEnabled, "devtools.enabled")
++DOM_PREF(PerformanceObserverEnabled, "dom.enable_performance_observer")
+ 
+ DOM_WEBIDL_PREF(ImageBitmapExtensionsEnabled)
+ DOM_WEBIDL_PREF(DOMCachesEnabled)
+ DOM_WEBIDL_PREF(NotificationEnabledInServiceWorkers)
+ DOM_WEBIDL_PREF(NotificationRIEnabled)
+ DOM_WEBIDL_PREF(ServiceWorkersEnabled)
+ DOM_WEBIDL_PREF(StorageManagerEnabled)
+ DOM_WEBIDL_PREF(PromiseRejectionEventsEnabled)
+ DOM_WEBIDL_PREF(PushEnabled)
+ DOM_WEBIDL_PREF(StreamsEnabled)
+ DOM_WEBIDL_PREF(RequestContextEnabled)
+ DOM_WEBIDL_PREF(OffscreenCanvasEnabled)
+ DOM_WEBIDL_PREF(WebkitBlinkDirectoryPickerEnabled)
+ DOM_WEBIDL_PREF(NetworkInformationEnabled)
+ DOM_WEBIDL_PREF(FetchObserverEnabled)
++DOM_WEBIDL_PREF(PerformanceObserverEnabled)
+diff --git a/dom/performance/Performance.cpp b/dom/performance/Performance.cpp
+--- a/dom/performance/Performance.cpp
++++ b/dom/performance/Performance.cpp
+@@ -31,48 +31,16 @@
+ #include "ProfilerMarkerPayload.h"
+ #endif
+ 
+ #define PERFLOG(msg, ...) printf_stderr(msg, ##__VA_ARGS__)
+ 
+ namespace mozilla {
+ namespace dom {
+ 
+-namespace {
+-
+-class PrefEnabledRunnable final
+-  : public WorkerCheckAPIExposureOnMainThreadRunnable
+-{
+-public:
+-  PrefEnabledRunnable(WorkerPrivate* aWorkerPrivate,
+-                      const nsCString& aPrefName)
+-    : WorkerCheckAPIExposureOnMainThreadRunnable(aWorkerPrivate)
+-    , mEnabled(false)
+-    , mPrefName(aPrefName)
+-  { }
+-
+-  bool MainThreadRun() override
+-  {
+-    MOZ_ASSERT(NS_IsMainThread());
+-    mEnabled = Preferences::GetBool(mPrefName.get(), false);
+-    return true;
+-  }
+-
+-  bool IsEnabled() const
+-  {
+-    return mEnabled;
+-  }
+-
+-private:
+-  bool mEnabled;
+-  nsCString mPrefName;
+-};
+-
+-} // anonymous namespace
+-
+ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Performance)
+ NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
+ 
+ NS_IMPL_CYCLE_COLLECTION_INHERITED(Performance,
+                                    DOMEventTargetHelper,
+                                    mUserEntries,
+                                    mResourceEntries);
+ 
+@@ -527,34 +495,16 @@ Performance::QueueEntry(PerformanceEntry
+                                            PerformanceObserver,
+                                            QueueEntry, (aEntry));
+ 
+   if (!mPendingNotificationObserversTask) {
+     RunNotificationObserversTask();
+   }
+ }
+ 
+-/* static */ bool
+-Performance::IsObserverEnabled(JSContext* aCx, JSObject* aGlobal)
+-{
+-  if (NS_IsMainThread()) {
+-    return Preferences::GetBool("dom.enable_performance_observer", false);
+-  }
+-
+-  WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
+-  MOZ_ASSERT(workerPrivate);
+-  workerPrivate->AssertIsOnWorkerThread();
+-
+-  RefPtr<PrefEnabledRunnable> runnable =
+-    new PrefEnabledRunnable(workerPrivate,
+-                            NS_LITERAL_CSTRING("dom.enable_performance_observer"));
+-
+-  return runnable->Dispatch() && runnable->IsEnabled();
+-}
+-
+ void
+ Performance::MemoryPressure()
+ {
+   mUserEntries.Clear();
+ }
+ 
+ size_t
+ Performance::SizeOfUserEntries(mozilla::MallocSizeOf aMallocSizeOf) const
+diff --git a/dom/performance/Performance.h b/dom/performance/Performance.h
+--- a/dom/performance/Performance.h
++++ b/dom/performance/Performance.h
+@@ -4,16 +4,17 @@
+  * 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_Performance_h
+ #define mozilla_dom_Performance_h
+ 
+ #include "mozilla/Attributes.h"
+ #include "mozilla/DOMEventTargetHelper.h"
++#include "mozilla/dom/DOMPrefs.h"
+ #include "nsCOMPtr.h"
+ #include "nsDOMNavigationTiming.h"
+ 
+ class nsITimedChannel;
+ 
+ namespace mozilla {
+ 
+ class ErrorResult;
+diff --git a/dom/performance/PerformanceObserverEntryList.h b/dom/performance/PerformanceObserverEntryList.h
+--- a/dom/performance/PerformanceObserverEntryList.h
++++ b/dom/performance/PerformanceObserverEntryList.h
+@@ -6,16 +6,17 @@
+ 
+ #ifndef mozilla_dom_PerformanceObserverEntryList_h__
+ #define mozilla_dom_PerformanceObserverEntryList_h__
+ 
+ #include "nsCOMPtr.h"
+ #include "nsISupports.h"
+ #include "nsTArray.h"
+ #include "nsWrapperCache.h"
++#include "mozilla/dom/DOMPrefs.h"
+ #include "mozilla/dom/PerformanceEntryBinding.h"
+ 
+ namespace mozilla {
+ namespace dom {
+ 
+ struct PerformanceEntryFilterOptions;
+ class PerformanceEntry;
+ template<typename T> class Optional;
+diff --git a/dom/webidl/PerformanceObserver.webidl b/dom/webidl/PerformanceObserver.webidl
+--- a/dom/webidl/PerformanceObserver.webidl
++++ b/dom/webidl/PerformanceObserver.webidl
+@@ -10,16 +10,16 @@
+ dictionary PerformanceObserverInit {
+   required sequence<DOMString> entryTypes;
+   boolean buffered = false;
+ };
+ 
+ callback PerformanceObserverCallback = void (PerformanceObserverEntryList entries,
+                                              PerformanceObserver observer);
+ 
+-[Func="Performance::IsObserverEnabled",
++[Func="mozilla::dom::DOMPrefs::PerformanceObserverEnabled",
+  Constructor(PerformanceObserverCallback callback),
+  Exposed=(Window,Worker)]
+ interface PerformanceObserver {
+     void                 observe(PerformanceObserverInit options);
+     void                 disconnect();
+     PerformanceEntryList takeRecords();
+ };
+diff --git a/dom/webidl/PerformanceObserverEntryList.webidl b/dom/webidl/PerformanceObserverEntryList.webidl
+--- a/dom/webidl/PerformanceObserverEntryList.webidl
++++ b/dom/webidl/PerformanceObserverEntryList.webidl
+@@ -9,16 +9,17 @@
+ 
+ // XXX should be moved into Performance.webidl.
+ dictionary PerformanceEntryFilterOptions {
+   DOMString name;
+   DOMString entryType;
+   DOMString initiatorType;
+ };
+ 
+-[Func="Performance::IsObserverEnabled", Exposed=(Window,Worker)]
++[Func="mozilla::dom::DOMPrefs::PerformanceObserverEnabled",
++ Exposed=(Window,Worker)]
+ interface PerformanceObserverEntryList {
+   PerformanceEntryList getEntries(optional PerformanceEntryFilterOptions filter);
+   PerformanceEntryList getEntriesByType(DOMString entryType);
+   PerformanceEntryList getEntriesByName(DOMString name,
+                                         optional DOMString entryType);
+ };
+ 
+diff --git a/dom/workers/WorkerRunnable.cpp b/dom/workers/WorkerRunnable.cpp
+--- a/dom/workers/WorkerRunnable.cpp
++++ b/dom/workers/WorkerRunnable.cpp
+@@ -630,34 +630,16 @@ WorkerMainThreadRunnable::Run()
+                                        mSyncLoopTarget.forget(),
+                                        runResult);
+ 
+   MOZ_ALWAYS_TRUE(response->Dispatch());
+ 
+   return NS_OK;
+ }
+ 
+-WorkerCheckAPIExposureOnMainThreadRunnable::WorkerCheckAPIExposureOnMainThreadRunnable(WorkerPrivate* aWorkerPrivate):
+-  WorkerMainThreadRunnable(aWorkerPrivate,
+-                           NS_LITERAL_CSTRING("WorkerCheckAPIExposureOnMainThread"))
+-{}
+-
+-WorkerCheckAPIExposureOnMainThreadRunnable::~WorkerCheckAPIExposureOnMainThreadRunnable()
+-{}
+-
+-bool
+-WorkerCheckAPIExposureOnMainThreadRunnable::Dispatch()
+-{
+-  ErrorResult rv;
+-  WorkerMainThreadRunnable::Dispatch(Terminating, rv);
+-  bool ok = !rv.Failed();
+-  rv.SuppressException();
+-  return ok;
+-}
+-
+ bool
+ WorkerSameThreadRunnable::PreDispatch(WorkerPrivate* aWorkerPrivate)
+ {
+   // We don't call WorkerRunnable::PreDispatch, because we're using
+   // WorkerThreadModifyBusyCount for mBehavior, and WorkerRunnable will assert
+   // that PreDispatch is on the parent thread in that case.
+   aWorkerPrivate->AssertIsOnWorkerThread();
+   return true;
+diff --git a/dom/workers/WorkerRunnable.h b/dom/workers/WorkerRunnable.h
+--- a/dom/workers/WorkerRunnable.h
++++ b/dom/workers/WorkerRunnable.h
+@@ -452,37 +452,16 @@ private:
+   bool HoldWorker();
+   void ReleaseWorker();
+ 
+ protected:
+   WorkerPrivate* mWorkerPrivate;
+   UniquePtr<WorkerHolder> mWorkerHolder;
+ };
+ 
+-// Class for checking API exposure.  This totally violates the "MUST" in the
+-// comments on WorkerMainThreadRunnable::Dispatch, because API exposure checks
+-// can't throw.  Maybe we should change it so they _could_ throw.  But for now
+-// we are bad people and should be ashamed of ourselves.  Let's hope none of
+-// them happen while a worker is shutting down.
+-//
+-// Do NOT copy what this class is doing elsewhere.  Just don't.
+-class WorkerCheckAPIExposureOnMainThreadRunnable
+-  : public WorkerMainThreadRunnable
+-{
+-public:
+-  explicit
+-  WorkerCheckAPIExposureOnMainThreadRunnable(WorkerPrivate* aWorkerPrivate);
+-  virtual
+-  ~WorkerCheckAPIExposureOnMainThreadRunnable();
+-
+-  // Returns whether the dispatch succeeded.  If this returns false, the API
+-  // should not be exposed.
+-  bool Dispatch();
+-};
+-
+ // This runnable is used to stop a sync loop and it's meant to be used on the
+ // main-thread only. As sync loops keep the busy count incremented as long as
+ // they run this runnable does not modify the busy count
+ // in any way.
+ class MainThreadStopSyncLoopRunnable : public WorkerSyncRunnable
+ {
+   bool mResult;
+ 

+ 30 - 0
mozilla-release/patches/1457401-61a1.patch

@@ -0,0 +1,30 @@
+# HG changeset patch
+# User Dragana Damjanovic <dd.mozilla@gmail.com>
+# Date 1524796740 -10800
+# Node ID f846639066aa8f7e5aff7fa363a450885fc887b4
+# Parent  db2555234bfcc8c415f4307583031ebc62545e13
+Bug 1457401 - Check if loadInfo is present. r=valentin
+
+diff --git a/netwerk/protocol/http/HttpBaseChannel.cpp b/netwerk/protocol/http/HttpBaseChannel.cpp
+--- a/netwerk/protocol/http/HttpBaseChannel.cpp
++++ b/netwerk/protocol/http/HttpBaseChannel.cpp
+@@ -4285,17 +4285,17 @@ HttpBaseChannel::GetPerformanceStorage()
+ 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 (mLoadInfo && 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;
+

+ 41 - 0
mozilla-release/patches/1465585-3a-std-62a1.patch

@@ -0,0 +1,41 @@
+# HG changeset patch
+# User Emilio Cobos Alvarez <emilio@crisal.io>
+# Date 1527707735 -7200
+# Node ID b54db66223586b4e04f5cb926fccdacf8a176b91
+# Parent  9bd4ce43361fbda79e78e6218adda6e89eb77a07
+Bug 1465585: Switch from mozilla::Move to std::move. r=froydnj
+
+This was done automatically replacing:
+
+  s/mozilla::Move/std::move/
+  s/ Move(/ std::move(/
+  s/(Move(/(std::move(/
+
+Removing the 'using mozilla::Move;' lines.
+
+And then with a few manual fixups, see the bug for the split series..
+
+MozReview-Commit-ID: Jxze3adipUh
+
+diff --git a/dom/performance/PerformanceMainThread.cpp b/dom/performance/PerformanceMainThread.cpp
+--- a/dom/performance/PerformanceMainThread.cpp
++++ b/dom/performance/PerformanceMainThread.cpp
+@@ -304,17 +304,17 @@ PerformanceMainThread::CreateDocumentEnt
+   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);
++  mDocEntry = new PerformanceNavigationTiming(std::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();

+ 32 - 0
mozilla-release/patches/1566482-70a1.patch

@@ -0,0 +1,32 @@
+# HG changeset patch
+# User Christian Holler <choller@mozilla.com>
+# Date 1564559597 0
+# Node ID 6c522d98565a3b9829be1e79c0a9fc5cdd777cd9
+# Parent  58bd74826796f2607b865c8731d2eca69e1cb55b
+Bug 1566482 - Properly calculate end in SetHttpTrailers. r=dragana
+
+Differential Revision: https://phabricator.services.mozilla.com/D38272
+
+diff --git a/netwerk/protocol/http/nsHttpTransaction.cpp b/netwerk/protocol/http/nsHttpTransaction.cpp
+--- a/netwerk/protocol/http/nsHttpTransaction.cpp
++++ b/netwerk/protocol/http/nsHttpTransaction.cpp
+@@ -2446,17 +2446,18 @@ nsHttpTransaction::SetHttpTrailers(nsCSt
+     int32_t cur = 0;
+     int32_t len = aTrailers.Length();
+     while (cur < len) {
+         int32_t newline = aTrailers.FindCharInSet("\n", cur);
+         if (newline == -1) {
+             newline = len;
+         }
+ 
+-        int32_t end = aTrailers[newline - 1] == '\r' ? newline - 1 : newline;
++        int32_t end =
++            (newline && aTrailers[newline - 1] == '\r') ? newline - 1 : newline;
+         nsDependentCSubstring line(aTrailers, cur, end);
+         nsHttpAtom hdr;
+         nsAutoCString hdrNameOriginal;
+         nsAutoCString val;
+         if (NS_SUCCEEDED(mForTakeResponseTrailers->ParseHeaderLine(line, &hdr, &hdrNameOriginal, &val))) {
+             if (hdr == nsHttp::Server_Timing) {
+                 Unused << mForTakeResponseTrailers->SetHeaderFromNet(hdr, hdrNameOriginal, val, true);
+             }

+ 15 - 0
mozilla-release/patches/series

@@ -7101,3 +7101,18 @@ TOP-1905160-NSS3903-11513.patch
 1902935-seamonkey-credits-25320.patch
 1585358-71a1.patch
 TOP-1906540-mozdevice-removal-mozilla-25320.patch
+1436692-60a1.patch
+1436744-60a1.patch
+1429973-0-60a1.patch
+1429973-1-60a1.patch
+1429973-2-60a1.patch
+1429973-3-60a1.patch
+1425605-60a1.patch
+1423495-1-61a1.patch
+1423495-2-61a1.patch
+1423495-3-61a1.patch
+1423495-4no5-61a1.patch
+1423495-6-61a1.patch
+1457401-61a1.patch
+1465585-3a-std-62a1.patch
+1566482-70a1.patch