PerformanceResourceTiming.cpp (5667B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "PerformanceResourceTiming.h" 8 9 #include "mozilla/dom/PerformanceResourceTimingBinding.h" 10 #include "nsArrayUtils.h" 11 #include "nsGkAtoms.h" 12 #include "nsNetUtil.h" 13 14 using namespace mozilla::dom; 15 16 NS_IMPL_CYCLE_COLLECTION_INHERITED(PerformanceResourceTiming, PerformanceEntry, 17 mPerformance) 18 19 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(PerformanceResourceTiming, 20 PerformanceEntry) 21 NS_IMPL_CYCLE_COLLECTION_TRACE_END 22 23 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(PerformanceResourceTiming) 24 NS_INTERFACE_MAP_END_INHERITING(PerformanceEntry) 25 26 NS_IMPL_ADDREF_INHERITED(PerformanceResourceTiming, PerformanceEntry) 27 NS_IMPL_RELEASE_INHERITED(PerformanceResourceTiming, PerformanceEntry) 28 29 PerformanceResourceTiming::PerformanceResourceTiming( 30 UniquePtr<PerformanceTimingData>&& aPerformanceTiming, 31 Performance* aPerformance, const nsAString& aName) 32 : PerformanceEntry(aPerformance->GetParentObject(), aName, 33 nsGkAtoms::resource), 34 mTimingData(std::move(aPerformanceTiming)), 35 mPerformance(aPerformance) { 36 MOZ_RELEASE_ASSERT(mTimingData); 37 MOZ_ASSERT(aPerformance, "Parent performance object should be provided"); 38 if (NS_IsMainThread()) { 39 // Used to check if an addon content script has access to this timing. 40 // We don't need it in workers, and ignore mOriginalURI if null. 41 NS_NewURI(getter_AddRefs(mOriginalURI), aName); 42 } 43 } 44 45 PerformanceResourceTiming::~PerformanceResourceTiming() = default; 46 47 DOMHighResTimeStamp PerformanceResourceTiming::FetchStart() const { 48 if (mTimingData->TimingAllowed()) { 49 return mTimingData->FetchStartHighRes(mPerformance); 50 } 51 return StartTime(); 52 } 53 54 DOMHighResTimeStamp PerformanceResourceTiming::StartTime() const { 55 // Force the start time to be the earliest of: 56 // - RedirectStart 57 // - WorkerStart 58 // - AsyncOpen 59 // Ignore zero values. The RedirectStart and WorkerStart values 60 // can come from earlier redirected channels prior to the AsyncOpen 61 // time being recorded. 62 if (mCachedStartTime.isNothing()) { 63 DOMHighResTimeStamp redirect = 64 mTimingData->RedirectStartHighRes(mPerformance); 65 redirect = redirect ? redirect : DBL_MAX; 66 67 DOMHighResTimeStamp worker = mTimingData->WorkerStartHighRes(mPerformance); 68 worker = worker ? worker : DBL_MAX; 69 70 DOMHighResTimeStamp asyncOpen = mTimingData->AsyncOpenHighRes(mPerformance); 71 72 mCachedStartTime.emplace(std::min(asyncOpen, std::min(redirect, worker))); 73 } 74 return mCachedStartTime.value(); 75 } 76 77 JSObject* PerformanceResourceTiming::WrapObject( 78 JSContext* aCx, JS::Handle<JSObject*> aGivenProto) { 79 return PerformanceResourceTiming_Binding::Wrap(aCx, this, aGivenProto); 80 } 81 82 size_t PerformanceResourceTiming::SizeOfIncludingThis( 83 mozilla::MallocSizeOf aMallocSizeOf) const { 84 return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf); 85 } 86 87 size_t PerformanceResourceTiming::SizeOfExcludingThis( 88 mozilla::MallocSizeOf aMallocSizeOf) const { 89 return PerformanceEntry::SizeOfExcludingThis(aMallocSizeOf) + 90 mInitiatorType.SizeOfExcludingThisIfUnshared(aMallocSizeOf) + 91 mTimingData->ContentType().SizeOfExcludingThisIfUnshared( 92 aMallocSizeOf) + 93 mTimingData->NextHopProtocol().SizeOfExcludingThisIfUnshared( 94 aMallocSizeOf); 95 } 96 97 void PerformanceResourceTiming::GetServerTiming( 98 nsTArray<RefPtr<PerformanceServerTiming>>& aRetval, 99 nsIPrincipal& aSubjectPrincipal) { 100 aRetval.Clear(); 101 if (!TimingAllowedForCaller(aSubjectPrincipal)) { 102 return; 103 } 104 105 nsTArray<nsCOMPtr<nsIServerTiming>> serverTimingArray = 106 mTimingData->GetServerTiming(); 107 uint32_t length = serverTimingArray.Length(); 108 for (uint32_t index = 0; index < length; ++index) { 109 nsCOMPtr<nsIServerTiming> serverTiming = serverTimingArray.ElementAt(index); 110 MOZ_ASSERT(serverTiming); 111 112 aRetval.AppendElement( 113 new PerformanceServerTiming(GetParentObject(), serverTiming)); 114 } 115 } 116 117 nsITimedChannel::BodyInfoAccess 118 PerformanceResourceTiming::BodyInfoAccessAllowedForCaller( 119 nsIPrincipal& aCaller) const { 120 // If the addon has permission to access the cross-origin resource, 121 // allow it full access to the bodyInfo. 122 if (mOriginalURI && 123 BasePrincipal::Cast(&aCaller)->AddonAllowsLoad(mOriginalURI)) { 124 return nsITimedChannel::BodyInfoAccess::ALLOW_ALL; 125 } 126 127 return mTimingData->BodyInfoAccessAllowed(); 128 } 129 130 bool PerformanceResourceTiming::TimingAllowedForCaller( 131 nsIPrincipal& aCaller) const { 132 if (mTimingData->TimingAllowed()) { 133 return true; 134 } 135 136 // Check if the addon has permission to access the cross-origin resource. 137 return mOriginalURI && 138 BasePrincipal::Cast(&aCaller)->AddonAllowsLoad(mOriginalURI); 139 } 140 141 bool PerformanceResourceTiming::ReportRedirectForCaller( 142 nsIPrincipal& aCaller, bool aEnsureSameOriginAndIgnoreTAO) const { 143 if (mTimingData->ShouldReportCrossOriginRedirect( 144 aEnsureSameOriginAndIgnoreTAO)) { 145 return true; 146 } 147 148 // Only report cross-origin redirect if the addon has <all_urls> permission. 149 return BasePrincipal::Cast(&aCaller)->AddonHasPermission( 150 nsGkAtoms::all_urlsPermission); 151 } 152 153 RenderBlockingStatusType PerformanceResourceTiming::RenderBlockingStatus() 154 const { 155 return mTimingData->RenderBlockingStatus(); 156 }