diff options
Diffstat (limited to 'dom/performance/PerformanceResourceTiming.cpp')
-rw-r--r-- | dom/performance/PerformanceResourceTiming.cpp | 134 |
1 files changed, 134 insertions, 0 deletions
diff --git a/dom/performance/PerformanceResourceTiming.cpp b/dom/performance/PerformanceResourceTiming.cpp new file mode 100644 index 0000000000..40a0b77382 --- /dev/null +++ b/dom/performance/PerformanceResourceTiming.cpp @@ -0,0 +1,134 @@ +/* -*- 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 "nsNetUtil.h" +#include "nsArrayUtils.h" + +using namespace mozilla::dom; + +NS_IMPL_CYCLE_COLLECTION_INHERITED(PerformanceResourceTiming, PerformanceEntry, + mPerformance) + +NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(PerformanceResourceTiming, + PerformanceEntry) +NS_IMPL_CYCLE_COLLECTION_TRACE_END + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(PerformanceResourceTiming) +NS_INTERFACE_MAP_END_INHERITING(PerformanceEntry) + +NS_IMPL_ADDREF_INHERITED(PerformanceResourceTiming, PerformanceEntry) +NS_IMPL_RELEASE_INHERITED(PerformanceResourceTiming, PerformanceEntry) + +PerformanceResourceTiming::PerformanceResourceTiming( + UniquePtr<PerformanceTimingData>&& aPerformanceTiming, + Performance* aPerformance, const nsAString& aName) + : PerformanceEntry(aPerformance->GetParentObject(), aName, u"resource"_ns), + mTimingData(std::move(aPerformanceTiming)), + mPerformance(aPerformance) { + MOZ_RELEASE_ASSERT(mTimingData); + MOZ_ASSERT(aPerformance, "Parent performance object should be provided"); + if (NS_IsMainThread()) { + // Used to check if an addon content script has access to this timing. + // We don't need it in workers, and ignore mOriginalURI if null. + NS_NewURI(getter_AddRefs(mOriginalURI), aName); + } +} + +PerformanceResourceTiming::~PerformanceResourceTiming() = default; + +DOMHighResTimeStamp PerformanceResourceTiming::FetchStart() const { + if (mTimingData->TimingAllowed()) { + return mTimingData->FetchStartHighRes(mPerformance); + } + return StartTime(); +} + +DOMHighResTimeStamp PerformanceResourceTiming::StartTime() const { + // Force the start time to be the earliest of: + // - RedirectStart + // - WorkerStart + // - AsyncOpen + // Ignore zero values. The RedirectStart and WorkerStart values + // can come from earlier redirected channels prior to the AsyncOpen + // time being recorded. + if (mCachedStartTime.isNothing()) { + DOMHighResTimeStamp redirect = + mTimingData->RedirectStartHighRes(mPerformance); + redirect = redirect ? redirect : DBL_MAX; + + DOMHighResTimeStamp worker = mTimingData->WorkerStartHighRes(mPerformance); + worker = worker ? worker : DBL_MAX; + + DOMHighResTimeStamp asyncOpen = mTimingData->AsyncOpenHighRes(mPerformance); + + mCachedStartTime.emplace(std::min(asyncOpen, std::min(redirect, worker))); + } + return mCachedStartTime.value(); +} + +JSObject* PerformanceResourceTiming::WrapObject( + JSContext* aCx, JS::Handle<JSObject*> aGivenProto) { + return PerformanceResourceTiming_Binding::Wrap(aCx, this, aGivenProto); +} + +size_t PerformanceResourceTiming::SizeOfIncludingThis( + mozilla::MallocSizeOf aMallocSizeOf) const { + return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf); +} + +size_t PerformanceResourceTiming::SizeOfExcludingThis( + mozilla::MallocSizeOf aMallocSizeOf) const { + return PerformanceEntry::SizeOfExcludingThis(aMallocSizeOf) + + mInitiatorType.SizeOfExcludingThisIfUnshared(aMallocSizeOf) + + mTimingData->NextHopProtocol().SizeOfExcludingThisIfUnshared( + aMallocSizeOf); +} + +void PerformanceResourceTiming::GetServerTiming( + nsTArray<RefPtr<PerformanceServerTiming>>& aRetval, + Maybe<nsIPrincipal*>& aSubjectPrincipal) { + aRetval.Clear(); + if (!TimingAllowedForCaller(aSubjectPrincipal)) { + return; + } + + nsTArray<nsCOMPtr<nsIServerTiming>> serverTimingArray = + mTimingData->GetServerTiming(); + uint32_t length = serverTimingArray.Length(); + for (uint32_t index = 0; index < length; ++index) { + nsCOMPtr<nsIServerTiming> serverTiming = serverTimingArray.ElementAt(index); + MOZ_ASSERT(serverTiming); + + aRetval.AppendElement( + new PerformanceServerTiming(GetParentObject(), serverTiming)); + } +} + +bool PerformanceResourceTiming::TimingAllowedForCaller( + Maybe<nsIPrincipal*>& aCaller) const { + if (mTimingData->TimingAllowed()) { + return true; + } + + // Check if the addon has permission to access the cross-origin resource. + return mOriginalURI && aCaller.isSome() && + BasePrincipal::Cast(aCaller.value())->AddonAllowsLoad(mOriginalURI); +} + +bool PerformanceResourceTiming::ReportRedirectForCaller( + Maybe<nsIPrincipal*>& aCaller, bool aEnsureSameOriginAndIgnoreTAO) const { + if (mTimingData->ShouldReportCrossOriginRedirect( + aEnsureSameOriginAndIgnoreTAO)) { + return true; + } + + // Only report cross-origin redirect if the addon has <all_urls> permission. + return aCaller.isSome() && + BasePrincipal::Cast(aCaller.value()) + ->AddonHasPermission(nsGkAtoms::all_urlsPermission); +} |