PerformanceResourceTiming.h (8232B)
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 #ifndef mozilla_dom_PerformanceResourceTiming_h___ 8 #define mozilla_dom_PerformanceResourceTiming_h___ 9 10 #include "Performance.h" 11 #include "PerformanceEntry.h" 12 #include "PerformanceServerTiming.h" 13 #include "PerformanceTiming.h" 14 #include "mozilla/UniquePtr.h" 15 #include "nsCOMPtr.h" 16 17 namespace mozilla::dom { 18 enum class RenderBlockingStatusType : uint8_t; 19 20 #define IMPL_RESOURCE_TIMING_TAO_PROTECTED_TIMING_PROP(name) \ 21 DOMHighResTimeStamp name(nsIPrincipal& aSubjectPrincipal) const { \ 22 bool allowed = !mTimingData->RedirectCountReal() \ 23 ? TimingAllowedForCaller(aSubjectPrincipal) \ 24 : ReportRedirectForCaller(aSubjectPrincipal, false); \ 25 return allowed ? mTimingData->name##HighRes(mPerformance) : 0; \ 26 } 27 28 #define IMPL_RESOURCE_TIMING_TAO_PROTECTED_SIZE_PROP(name) \ 29 uint64_t name(nsIPrincipal& aSubjectPrincipal) const { \ 30 bool allowed = !mTimingData->RedirectCountReal() \ 31 ? TimingAllowedForCaller(aSubjectPrincipal) \ 32 : ReportRedirectForCaller(aSubjectPrincipal, false); \ 33 return allowed ? mTimingData->name() : 0; \ 34 } 35 36 #define IMPL_RESOURCE_TIMING_CORS_PROTECTED_SIZE_PROP(name) \ 37 uint64_t name(nsIPrincipal& aSubjectPrincipal) const { \ 38 if (BodyInfoAccessAllowedForCaller(aSubjectPrincipal)) { \ 39 return mTimingData->name(); \ 40 } \ 41 return 0; \ 42 } 43 44 // http://www.w3.org/TR/resource-timing/#performanceresourcetiming 45 class PerformanceResourceTiming : public PerformanceEntry { 46 public: 47 using TimeStamp = mozilla::TimeStamp; 48 49 NS_DECL_ISUPPORTS_INHERITED 50 NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED( 51 PerformanceResourceTiming, PerformanceEntry) 52 53 // aPerformanceTimingData and aPerformance must be non-null 54 PerformanceResourceTiming( 55 UniquePtr<PerformanceTimingData>&& aPerformanceTimingData, 56 Performance* aPerformance, const nsAString& aName); 57 58 virtual JSObject* WrapObject(JSContext* aCx, 59 JS::Handle<JSObject*> aGivenProto) override; 60 61 virtual DOMHighResTimeStamp StartTime() const override; 62 63 virtual DOMHighResTimeStamp Duration() const override { 64 return ResponseEnd() - StartTime(); 65 } 66 67 void GetInitiatorType(nsAString& aInitiatorType) const { 68 aInitiatorType = mInitiatorType; 69 } 70 71 void SetInitiatorType(const nsAString& aInitiatorType) { 72 mInitiatorType = aInitiatorType; 73 } 74 75 RenderBlockingStatusType RenderBlockingStatus() const; 76 77 void GetNextHopProtocol(nsAString& aNextHopProtocol) const { 78 if (mTimingData->TimingAllowed()) { 79 aNextHopProtocol = mTimingData->NextHopProtocol(); 80 } 81 } 82 83 DOMHighResTimeStamp WorkerStart() const { 84 return mTimingData->WorkerStartHighRes(mPerformance); 85 } 86 87 DOMHighResTimeStamp FetchStart() const; 88 89 DOMHighResTimeStamp RedirectStart(nsIPrincipal& aSubjectPrincipal, 90 bool aEnsureSameOriginAndIgnoreTAO) const { 91 // We have to check if all the redirect URIs whether had the same origin or 92 // different origins with TAO headers set (since there is no check in 93 // RedirectStartHighRes()) 94 return ReportRedirectForCaller(aSubjectPrincipal, 95 aEnsureSameOriginAndIgnoreTAO) 96 ? mTimingData->RedirectStartHighRes(mPerformance) 97 : 0; 98 } 99 100 virtual DOMHighResTimeStamp RedirectStart( 101 nsIPrincipal& aSubjectPrincipal) const { 102 return RedirectStart(aSubjectPrincipal, 103 false /* aEnsureSameOriginAndIgnoreTAO */); 104 } 105 106 DOMHighResTimeStamp RedirectEnd(nsIPrincipal& aSubjectPrincipal, 107 bool aEnsureSameOriginAndIgnoreTAO) const { 108 // We have to check if all the redirect URIs whether had the same origin or 109 // different origins with TAO headers set (since there is no check in 110 // RedirectEndHighRes()) 111 return ReportRedirectForCaller(aSubjectPrincipal, 112 aEnsureSameOriginAndIgnoreTAO) 113 ? mTimingData->RedirectEndHighRes(mPerformance) 114 : 0; 115 } 116 117 virtual DOMHighResTimeStamp RedirectEnd( 118 nsIPrincipal& aSubjectPrincipal) const { 119 return RedirectEnd(aSubjectPrincipal, 120 false /* aEnsureSameOriginAndIgnoreTAO */); 121 } 122 123 IMPL_RESOURCE_TIMING_TAO_PROTECTED_TIMING_PROP(DomainLookupStart) 124 125 IMPL_RESOURCE_TIMING_TAO_PROTECTED_TIMING_PROP(DomainLookupEnd) 126 127 IMPL_RESOURCE_TIMING_TAO_PROTECTED_TIMING_PROP(ConnectStart) 128 129 IMPL_RESOURCE_TIMING_TAO_PROTECTED_TIMING_PROP(ConnectEnd) 130 131 IMPL_RESOURCE_TIMING_TAO_PROTECTED_TIMING_PROP(RequestStart) 132 133 IMPL_RESOURCE_TIMING_TAO_PROTECTED_TIMING_PROP(ResponseStart) 134 135 DOMHighResTimeStamp ResponseEnd() const { 136 return mTimingData->ResponseEndHighRes(mPerformance); 137 } 138 139 IMPL_RESOURCE_TIMING_TAO_PROTECTED_TIMING_PROP(SecureConnectionStart) 140 141 virtual const PerformanceResourceTiming* ToResourceTiming() const override { 142 return this; 143 } 144 145 IMPL_RESOURCE_TIMING_CORS_PROTECTED_SIZE_PROP(EncodedBodySize); 146 IMPL_RESOURCE_TIMING_CORS_PROTECTED_SIZE_PROP(DecodedBodySize); 147 148 uint64_t TransferSize(nsIPrincipal& aSubjectPrincipal) const { 149 const bool allowed = 150 !mTimingData->RedirectCountReal() 151 ? TimingAllowedForCaller(aSubjectPrincipal) 152 : ReportRedirectForCaller(aSubjectPrincipal, false); 153 if (!allowed) { 154 return 0; 155 } 156 // Resource is cached. 157 if (!mTimingData->TransferSize()) { 158 return 0; 159 } 160 auto encodedBodySize = EncodedBodySize(aSubjectPrincipal); 161 // The constant number added to transferSize replaces exposing the 162 // total byte size of the HTTP headers, as that may expose the 163 // presence of certain cookies. 164 // https://github.com/w3c/resource-timing/issues/238 165 return encodedBodySize + 300; 166 } 167 168 uint16_t ResponseStatus(nsIPrincipal& aSubjectPrincipal) const { 169 if (BodyInfoAccessAllowedForCaller(aSubjectPrincipal)) { 170 return mTimingData->ResponseStatus(); 171 } 172 return 0; 173 } 174 175 void GetContentType(nsAString& aContentType, 176 nsIPrincipal& aSubjectPrincipal) const { 177 if (BodyInfoAccessAllowedForCaller(aSubjectPrincipal) == 178 nsITimedChannel::BodyInfoAccess::ALLOW_ALL) { 179 aContentType = mTimingData->ContentType(); 180 } 181 } 182 183 void GetServerTiming(nsTArray<RefPtr<PerformanceServerTiming>>& aRetval, 184 nsIPrincipal& aSubjectPrincipal); 185 186 size_t SizeOfIncludingThis( 187 mozilla::MallocSizeOf aMallocSizeOf) const override; 188 189 protected: 190 virtual ~PerformanceResourceTiming(); 191 192 size_t SizeOfExcludingThis( 193 mozilla::MallocSizeOf aMallocSizeOf) const override; 194 195 // Check if caller has access to the bodyInfo of the request, per Fetch spec. 196 nsITimedChannel::BodyInfoAccess BodyInfoAccessAllowedForCaller( 197 nsIPrincipal& aCaller) const; 198 199 // Check if caller has access to cross-origin timings, either by the rules 200 // from the spec, or based on addon permissions. 201 bool TimingAllowedForCaller(nsIPrincipal& aCaller) const; 202 203 // Check if cross-origin redirects should be reported to the caller. 204 bool ReportRedirectForCaller(nsIPrincipal& aCaller, 205 bool aEnsureSameOriginAndIgnoreTAO) const; 206 207 nsString mInitiatorType; 208 const UniquePtr<PerformanceTimingData> mTimingData; // always non-null 209 RefPtr<Performance> mPerformance; 210 211 // The same initial requested URI as the `name` attribute. 212 nsCOMPtr<nsIURI> mOriginalURI; 213 214 private: 215 mutable Maybe<DOMHighResTimeStamp> mCachedStartTime; 216 }; 217 218 } // namespace mozilla::dom 219 220 #endif /* mozilla_dom_PerformanceResourceTiming_h___ */