tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

PerformanceTiming.h (19530B)


      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_PerformanceTiming_h
      8 #define mozilla_dom_PerformanceTiming_h
      9 
     10 #include "CacheablePerformanceTimingData.h"
     11 #include "Performance.h"
     12 #include "ipc/IPCMessageUtils.h"
     13 #include "ipc/IPCMessageUtilsSpecializations.h"
     14 #include "mozilla/BasePrincipal.h"
     15 #include "mozilla/StaticPrefs_dom.h"
     16 #include "mozilla/dom/PerformanceTimingTypes.h"
     17 #include "mozilla/net/nsServerTiming.h"
     18 #include "nsContentUtils.h"
     19 #include "nsDOMNavigationTiming.h"
     20 #include "nsITimedChannel.h"
     21 #include "nsRFPService.h"
     22 #include "nsWrapperCache.h"
     23 
     24 class nsIHttpChannel;
     25 
     26 namespace mozilla::dom {
     27 
     28 class PerformanceTiming;
     29 enum class RenderBlockingStatusType : uint8_t;
     30 
     31 class PerformanceTimingData final : public CacheablePerformanceTimingData {
     32  friend class PerformanceTiming;
     33  friend struct IPC::ParamTraits<mozilla::dom::PerformanceTimingData>;
     34 
     35  // https://w3c.github.io/resource-timing/#dom-performanceresourcetiming-transfersize
     36  // The transferSize getter steps are to perform the following steps:
     37  //   1. If this's cache mode is "local", then return 0.
     38  static constexpr uint64_t kLocalCacheTransferSize = 0;
     39 
     40 public:
     41  PerformanceTimingData() = default;  // For deserialization
     42  // This can return null.
     43  static PerformanceTimingData* Create(nsITimedChannel* aChannel,
     44                                       nsIHttpChannel* aHttpChannel,
     45                                       DOMHighResTimeStamp aZeroTime,
     46                                       nsAString& aInitiatorType,
     47                                       nsAString& aEntryName);
     48 
     49  PerformanceTimingData(nsITimedChannel* aChannel, nsIHttpChannel* aHttpChannel,
     50                        DOMHighResTimeStamp aZeroTime);
     51 
     52  static PerformanceTimingData* Create(
     53      const CacheablePerformanceTimingData& aCachedData,
     54      DOMHighResTimeStamp aZeroTime, TimeStamp aStartTime, TimeStamp aEndTime,
     55      RenderBlockingStatusType aRenderBlockingStatus);
     56 
     57 private:
     58  PerformanceTimingData(const CacheablePerformanceTimingData& aCachedData,
     59                        DOMHighResTimeStamp aZeroTime, TimeStamp aStartTime,
     60                        TimeStamp aEndTime,
     61                        RenderBlockingStatusType aRenderBlockingStatus);
     62 
     63 public:
     64  explicit PerformanceTimingData(const IPCPerformanceTimingData& aIPCData);
     65 
     66  IPCPerformanceTimingData ToIPC();
     67 
     68  void SetPropertiesFromHttpChannel(nsIHttpChannel* aHttpChannel,
     69                                    nsITimedChannel* aChannel);
     70 
     71 private:
     72  void SetTransferSizeFromHttpChannel(nsIHttpChannel* aHttpChannel);
     73 
     74 public:
     75  uint64_t TransferSize() const { return mTransferSize; }
     76 
     77  /**
     78   * @param   aStamp
     79   *          The TimeStamp recorded for a specific event. This TimeStamp can
     80   *          be null.
     81   * @return  the duration of an event with a given TimeStamp, relative to the
     82   *          navigationStart TimeStamp (the moment the user landed on the
     83   *          page), if the given TimeStamp is valid. Otherwise, it will return
     84   *          the FetchStart timing value.
     85   */
     86  inline DOMHighResTimeStamp TimeStampToReducedDOMHighResOrFetchStart(
     87      Performance* aPerformance, TimeStamp aStamp) {
     88    MOZ_ASSERT(aPerformance);
     89 
     90    if (aStamp.IsNull()) {
     91      return FetchStartHighRes(aPerformance);
     92    }
     93 
     94    DOMHighResTimeStamp rawTimestamp =
     95        TimeStampToDOMHighRes(aPerformance, aStamp);
     96 
     97    return nsRFPService::ReduceTimePrecisionAsMSecs(
     98        rawTimestamp, aPerformance->GetRandomTimelineSeed(),
     99        aPerformance->GetRTPCallerType());
    100  }
    101 
    102  /**
    103   * The nsITimedChannel records an absolute timestamp for each event.
    104   * The nsDOMNavigationTiming will record the moment when the user landed on
    105   * the page. This is a window.performance unique timestamp, so it can be used
    106   * for all the events (navigation timing and resource timing events).
    107   *
    108   * The algorithm operates in 2 steps:
    109   * 1. The first step is to subtract the two timestamps: the argument (the
    110   * event's timestamp) and the navigation start timestamp. This will result in
    111   * a relative timestamp of the event (relative to the navigation start -
    112   * window.performance.timing.navigationStart).
    113   * 2. The second step is to add any required offset (the mZeroTime). For now,
    114   * this offset value is either 0 (for the resource timing), or equal to
    115   * "performance.navigationStart" (for navigation timing).
    116   * For the resource timing, mZeroTime is set to 0, causing the result to be a
    117   * relative time.
    118   * For the navigation timing, mZeroTime is set to
    119   * "performance.navigationStart" causing the result be an absolute time.
    120   *
    121   * @param   aStamp
    122   *          The TimeStamp recorded for a specific event. This TimeStamp can't
    123   *          be null.
    124   * @return  number of milliseconds value as one of:
    125   * - relative to the navigation start time, time the user has landed on the
    126   *   page
    127   * - an absolute wall clock time since the unix epoch
    128   */
    129  inline DOMHighResTimeStamp TimeStampToDOMHighRes(Performance* aPerformance,
    130                                                   TimeStamp aStamp) const {
    131    MOZ_ASSERT(aPerformance);
    132    MOZ_ASSERT(!aStamp.IsNull());
    133 
    134    TimeDuration duration = aStamp - aPerformance->CreationTimeStamp();
    135    return duration.ToMilliseconds() + mZeroTime;
    136  }
    137 
    138  // The last channel's AsyncOpen time.  This may occur before the FetchStart
    139  // in some cases.
    140  DOMHighResTimeStamp AsyncOpenHighRes(Performance* aPerformance);
    141 
    142  // High resolution (used by resource timing)
    143  DOMHighResTimeStamp WorkerStartHighRes(Performance* aPerformance);
    144  DOMHighResTimeStamp FetchStartHighRes(Performance* aPerformance);
    145  DOMHighResTimeStamp RedirectStartHighRes(Performance* aPerformance);
    146  DOMHighResTimeStamp RedirectEndHighRes(Performance* aPerformance);
    147  DOMHighResTimeStamp DomainLookupStartHighRes(Performance* aPerformance);
    148  DOMHighResTimeStamp DomainLookupEndHighRes(Performance* aPerformance);
    149  DOMHighResTimeStamp ConnectStartHighRes(Performance* aPerformance);
    150  DOMHighResTimeStamp SecureConnectionStartHighRes(Performance* aPerformance);
    151  DOMHighResTimeStamp ConnectEndHighRes(Performance* aPerformance);
    152  DOMHighResTimeStamp RequestStartHighRes(Performance* aPerformance);
    153  DOMHighResTimeStamp ResponseStartHighRes(Performance* aPerformance);
    154  DOMHighResTimeStamp ResponseEndHighRes(Performance* aPerformance);
    155 
    156  DOMHighResTimeStamp ZeroTime() const { return mZeroTime; }
    157 
    158  // If this is false the values of redirectStart/End will be 0 This is false if
    159  // no redirects occured, or if any of the responses failed the
    160  // timing-allow-origin check in HttpBaseChannel::TimingAllowCheck
    161  //
    162  // If aEnsureSameOriginAndIgnoreTAO is false, it checks if all redirects pass
    163  // TAO. When it is true, it checks if all redirects are same-origin and
    164  // ignores the result of TAO.
    165  bool ShouldReportCrossOriginRedirect(
    166      bool aEnsureSameOriginAndIgnoreTAO) const;
    167 
    168  RenderBlockingStatusType RenderBlockingStatus() const {
    169    return mRenderBlockingStatus;
    170  }
    171 
    172 private:
    173  TimeStamp mAsyncOpen;
    174  TimeStamp mRedirectStart;
    175  TimeStamp mRedirectEnd;
    176  TimeStamp mDomainLookupStart;
    177  TimeStamp mDomainLookupEnd;
    178  TimeStamp mConnectStart;
    179  TimeStamp mSecureConnectionStart;
    180  TimeStamp mConnectEnd;
    181  TimeStamp mRequestStart;
    182  TimeStamp mResponseStart;
    183  TimeStamp mCacheReadStart;
    184  TimeStamp mResponseEnd;
    185  TimeStamp mCacheReadEnd;
    186 
    187  // ServiceWorker interception timing information
    188  TimeStamp mWorkerStart;
    189  TimeStamp mWorkerRequestStart;
    190  TimeStamp mWorkerResponseEnd;
    191 
    192  // This is an offset that will be added to each timing ([ms] resolution).
    193  // There are only 2 possible values: (1) logicaly equal to navigationStart
    194  // TimeStamp (results are absolute timstamps - wallclock); (2) "0" (results
    195  // are relative to the navigation start).
    196  DOMHighResTimeStamp mZeroTime = 0;
    197 
    198  DOMHighResTimeStamp mFetchStart = 0;
    199 
    200  uint64_t mTransferSize = 0;
    201 
    202  RenderBlockingStatusType mRenderBlockingStatus;
    203 };
    204 
    205 // Script "performance.timing" object
    206 class PerformanceTiming final : public nsWrapperCache {
    207 public:
    208  /**
    209   * @param   aPerformance
    210   *          The performance object (the JS parent).
    211   *          This will allow access to "window.performance.timing" attribute
    212   * for the navigation timing (can't be null).
    213   * @param   aChannel
    214   *          An nsITimedChannel used to gather all the networking timings by
    215   * both the navigation timing and the resource timing (can't be null).
    216   * @param   aHttpChannel
    217   *          An nsIHttpChannel (the resource's http channel).
    218   *          This will be used by the resource timing cross-domain check
    219   *          algorithm.
    220   *          Argument is null for the navigation timing (navigation timing uses
    221   *          another algorithm for the cross-domain redirects).
    222   * @param   aZeroTime
    223   *          The offset that will be added to the timestamp of each event. This
    224   *          argument should be equal to performance.navigationStart for
    225   *          navigation timing and "0" for the resource timing.
    226   */
    227  PerformanceTiming(Performance* aPerformance, nsITimedChannel* aChannel,
    228                    nsIHttpChannel* aHttpChannel,
    229                    DOMHighResTimeStamp aZeroTime);
    230  NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(PerformanceTiming)
    231  NS_DECL_CYCLE_COLLECTION_NATIVE_WRAPPERCACHE_CLASS(PerformanceTiming)
    232 
    233  nsDOMNavigationTiming* GetDOMTiming() const {
    234    return mPerformance->GetDOMTiming();
    235  }
    236 
    237  Performance* GetParentObject() const { return mPerformance; }
    238 
    239  virtual JSObject* WrapObject(JSContext* cx,
    240                               JS::Handle<JSObject*> aGivenProto) override;
    241 
    242  // PerformanceNavigation WebIDL methods
    243  DOMTimeMilliSec NavigationStart() const {
    244    if (!StaticPrefs::dom_enable_performance()) {
    245      return 0;
    246    }
    247    return nsRFPService::ReduceTimePrecisionAsMSecs(
    248        GetDOMTiming()->GetNavigationStart(),
    249        mPerformance->GetRandomTimelineSeed(),
    250        mPerformance->GetRTPCallerType());
    251  }
    252 
    253  DOMTimeMilliSec UnloadEventStart() {
    254    if (!StaticPrefs::dom_enable_performance()) {
    255      return 0;
    256    }
    257    return nsRFPService::ReduceTimePrecisionAsMSecs(
    258        GetDOMTiming()->GetUnloadEventStart(),
    259        mPerformance->GetRandomTimelineSeed(),
    260        mPerformance->GetRTPCallerType());
    261  }
    262 
    263  DOMTimeMilliSec UnloadEventEnd() {
    264    if (!StaticPrefs::dom_enable_performance()) {
    265      return 0;
    266    }
    267    return nsRFPService::ReduceTimePrecisionAsMSecs(
    268        GetDOMTiming()->GetUnloadEventEnd(),
    269        mPerformance->GetRandomTimelineSeed(),
    270        mPerformance->GetRTPCallerType());
    271  }
    272 
    273  // Low resolution (used by navigation timing)
    274  DOMTimeMilliSec FetchStart();
    275  DOMTimeMilliSec RedirectStart();
    276  DOMTimeMilliSec RedirectEnd();
    277  DOMTimeMilliSec DomainLookupStart();
    278  DOMTimeMilliSec DomainLookupEnd();
    279  DOMTimeMilliSec ConnectStart();
    280  DOMTimeMilliSec SecureConnectionStart();
    281  DOMTimeMilliSec ConnectEnd();
    282  DOMTimeMilliSec RequestStart();
    283  DOMTimeMilliSec ResponseStart();
    284  DOMTimeMilliSec ResponseEnd();
    285 
    286  DOMTimeMilliSec DomLoading() {
    287    if (!StaticPrefs::dom_enable_performance()) {
    288      return 0;
    289    }
    290    return nsRFPService::ReduceTimePrecisionAsMSecs(
    291        GetDOMTiming()->GetDomLoading(), mPerformance->GetRandomTimelineSeed(),
    292        mPerformance->GetRTPCallerType());
    293  }
    294 
    295  DOMTimeMilliSec DomInteractive() const {
    296    if (!StaticPrefs::dom_enable_performance()) {
    297      return 0;
    298    }
    299    return nsRFPService::ReduceTimePrecisionAsMSecs(
    300        GetDOMTiming()->GetDomInteractive(),
    301        mPerformance->GetRandomTimelineSeed(),
    302        mPerformance->GetRTPCallerType());
    303  }
    304 
    305  DOMTimeMilliSec DomContentLoadedEventStart() const {
    306    if (!StaticPrefs::dom_enable_performance()) {
    307      return 0;
    308    }
    309    return nsRFPService::ReduceTimePrecisionAsMSecs(
    310        GetDOMTiming()->GetDomContentLoadedEventStart(),
    311        mPerformance->GetRandomTimelineSeed(),
    312        mPerformance->GetRTPCallerType());
    313  }
    314 
    315  DOMTimeMilliSec DomContentLoadedEventEnd() const {
    316    if (!StaticPrefs::dom_enable_performance()) {
    317      return 0;
    318    }
    319    return nsRFPService::ReduceTimePrecisionAsMSecs(
    320        GetDOMTiming()->GetDomContentLoadedEventEnd(),
    321        mPerformance->GetRandomTimelineSeed(),
    322        mPerformance->GetRTPCallerType());
    323  }
    324 
    325  DOMTimeMilliSec DomComplete() const {
    326    if (!StaticPrefs::dom_enable_performance()) {
    327      return 0;
    328    }
    329    return nsRFPService::ReduceTimePrecisionAsMSecs(
    330        GetDOMTiming()->GetDomComplete(), mPerformance->GetRandomTimelineSeed(),
    331        mPerformance->GetRTPCallerType());
    332  }
    333 
    334  DOMTimeMilliSec LoadEventStart() const {
    335    if (!StaticPrefs::dom_enable_performance()) {
    336      return 0;
    337    }
    338    return nsRFPService::ReduceTimePrecisionAsMSecs(
    339        GetDOMTiming()->GetLoadEventStart(),
    340        mPerformance->GetRandomTimelineSeed(),
    341        mPerformance->GetRTPCallerType());
    342  }
    343 
    344  DOMTimeMilliSec LoadEventEnd() const {
    345    if (!StaticPrefs::dom_enable_performance()) {
    346      return 0;
    347    }
    348    return nsRFPService::ReduceTimePrecisionAsMSecs(
    349        GetDOMTiming()->GetLoadEventEnd(),
    350        mPerformance->GetRandomTimelineSeed(),
    351        mPerformance->GetRTPCallerType());
    352  }
    353 
    354  DOMTimeMilliSec TimeToNonBlankPaint() const {
    355    if (!StaticPrefs::dom_enable_performance()) {
    356      return 0;
    357    }
    358    return nsRFPService::ReduceTimePrecisionAsMSecs(
    359        GetDOMTiming()->GetTimeToNonBlankPaint(),
    360        mPerformance->GetRandomTimelineSeed(),
    361        mPerformance->GetRTPCallerType());
    362  }
    363 
    364  DOMTimeMilliSec TimeToContentfulPaint() const {
    365    if (!StaticPrefs::dom_enable_performance()) {
    366      return 0;
    367    }
    368    return nsRFPService::ReduceTimePrecisionAsMSecs(
    369        GetDOMTiming()->GetTimeToContentfulComposite(),
    370        mPerformance->GetRandomTimelineSeed(),
    371        mPerformance->GetRTPCallerType());
    372  }
    373 
    374  DOMTimeMilliSec TimeToFirstInteractive() const {
    375    if (!StaticPrefs::dom_enable_performance()) {
    376      return 0;
    377    }
    378    return nsRFPService::ReduceTimePrecisionAsMSecs(
    379        GetDOMTiming()->GetTimeToTTFI(), mPerformance->GetRandomTimelineSeed(),
    380        mPerformance->GetRTPCallerType());
    381  }
    382 
    383  PerformanceTimingData* Data() const { return mTimingData.get(); }
    384 
    385 private:
    386  ~PerformanceTiming();
    387 
    388  bool IsTopLevelContentDocument() const;
    389 
    390  RefPtr<Performance> mPerformance;
    391 
    392  UniquePtr<PerformanceTimingData> mTimingData;
    393 };
    394 
    395 }  // namespace mozilla::dom
    396 
    397 namespace IPC {
    398 
    399 template <>
    400 struct ParamTraits<mozilla::dom::PerformanceTimingData> {
    401  using paramType = mozilla::dom::PerformanceTimingData;
    402  static void Write(IPC::MessageWriter* aWriter, const paramType& aParam) {
    403    WriteParam(aWriter, aParam.mServerTiming);
    404    WriteParam(aWriter, aParam.mNextHopProtocol);
    405    WriteParam(aWriter, aParam.mAsyncOpen);
    406    WriteParam(aWriter, aParam.mRedirectStart);
    407    WriteParam(aWriter, aParam.mRedirectEnd);
    408    WriteParam(aWriter, aParam.mDomainLookupStart);
    409    WriteParam(aWriter, aParam.mDomainLookupEnd);
    410    WriteParam(aWriter, aParam.mConnectStart);
    411    WriteParam(aWriter, aParam.mSecureConnectionStart);
    412    WriteParam(aWriter, aParam.mConnectEnd);
    413    WriteParam(aWriter, aParam.mRequestStart);
    414    WriteParam(aWriter, aParam.mResponseStart);
    415    WriteParam(aWriter, aParam.mCacheReadStart);
    416    WriteParam(aWriter, aParam.mResponseEnd);
    417    WriteParam(aWriter, aParam.mCacheReadEnd);
    418    WriteParam(aWriter, aParam.mWorkerStart);
    419    WriteParam(aWriter, aParam.mWorkerRequestStart);
    420    WriteParam(aWriter, aParam.mWorkerResponseEnd);
    421    WriteParam(aWriter, aParam.mZeroTime);
    422    WriteParam(aWriter, aParam.mFetchStart);
    423    WriteParam(aWriter, aParam.mEncodedBodySize);
    424    WriteParam(aWriter, aParam.mTransferSize);
    425    WriteParam(aWriter, aParam.mDecodedBodySize);
    426    WriteParam(aWriter, aParam.mResponseStatus);
    427    WriteParam(aWriter, aParam.mRedirectCount);
    428    WriteParam(aWriter, aParam.mContentType);
    429    WriteParam(aWriter, aParam.mAllRedirectsSameOrigin);
    430    WriteParam(aWriter, aParam.mAllRedirectsPassTAO);
    431    WriteParam(aWriter, aParam.mSecureConnection);
    432    WriteParam(aWriter, aParam.mBodyInfoAccessAllowed);
    433    WriteParam(aWriter, aParam.mTimingAllowed);
    434    WriteParam(aWriter, aParam.mInitialized);
    435  }
    436 
    437  static bool Read(IPC::MessageReader* aReader, paramType* aResult) {
    438    return ReadParam(aReader, &aResult->mServerTiming) &&
    439           ReadParam(aReader, &aResult->mNextHopProtocol) &&
    440           ReadParam(aReader, &aResult->mAsyncOpen) &&
    441           ReadParam(aReader, &aResult->mRedirectStart) &&
    442           ReadParam(aReader, &aResult->mRedirectEnd) &&
    443           ReadParam(aReader, &aResult->mDomainLookupStart) &&
    444           ReadParam(aReader, &aResult->mDomainLookupEnd) &&
    445           ReadParam(aReader, &aResult->mConnectStart) &&
    446           ReadParam(aReader, &aResult->mSecureConnectionStart) &&
    447           ReadParam(aReader, &aResult->mConnectEnd) &&
    448           ReadParam(aReader, &aResult->mRequestStart) &&
    449           ReadParam(aReader, &aResult->mResponseStart) &&
    450           ReadParam(aReader, &aResult->mCacheReadStart) &&
    451           ReadParam(aReader, &aResult->mResponseEnd) &&
    452           ReadParam(aReader, &aResult->mCacheReadEnd) &&
    453           ReadParam(aReader, &aResult->mWorkerStart) &&
    454           ReadParam(aReader, &aResult->mWorkerRequestStart) &&
    455           ReadParam(aReader, &aResult->mWorkerResponseEnd) &&
    456           ReadParam(aReader, &aResult->mZeroTime) &&
    457           ReadParam(aReader, &aResult->mFetchStart) &&
    458           ReadParam(aReader, &aResult->mEncodedBodySize) &&
    459           ReadParam(aReader, &aResult->mTransferSize) &&
    460           ReadParam(aReader, &aResult->mDecodedBodySize) &&
    461           ReadParam(aReader, &aResult->mResponseStatus) &&
    462           ReadParam(aReader, &aResult->mRedirectCount) &&
    463           ReadParam(aReader, &aResult->mContentType) &&
    464           ReadParam(aReader, &aResult->mAllRedirectsSameOrigin) &&
    465           ReadParam(aReader, &aResult->mAllRedirectsPassTAO) &&
    466           ReadParam(aReader, &aResult->mSecureConnection) &&
    467           ReadParam(aReader, &aResult->mBodyInfoAccessAllowed) &&
    468           ReadParam(aReader, &aResult->mTimingAllowed) &&
    469           ReadParam(aReader, &aResult->mInitialized);
    470  }
    471 };
    472 
    473 template <>
    474 struct ParamTraits<nsIServerTiming*> {
    475  static void Write(IPC::MessageWriter* aWriter, nsIServerTiming* aParam) {
    476    nsAutoCString name;
    477    (void)aParam->GetName(name);
    478    double duration = 0;
    479    (void)aParam->GetDuration(&duration);
    480    nsAutoCString description;
    481    (void)aParam->GetDescription(description);
    482    WriteParam(aWriter, name);
    483    WriteParam(aWriter, duration);
    484    WriteParam(aWriter, description);
    485  }
    486 
    487  static bool Read(IPC::MessageReader* aReader,
    488                   RefPtr<nsIServerTiming>* aResult) {
    489    nsAutoCString name;
    490    double duration;
    491    nsAutoCString description;
    492    if (!ReadParam(aReader, &name) || !ReadParam(aReader, &duration) ||
    493        !ReadParam(aReader, &description)) {
    494      return false;
    495    }
    496 
    497    RefPtr<nsServerTiming> timing = new nsServerTiming();
    498    timing->SetName(name);
    499    timing->SetDuration(duration);
    500    timing->SetDescription(description);
    501    *aResult = timing.forget();
    502    return true;
    503  }
    504 };
    505 
    506 }  // namespace IPC
    507 
    508 #endif  // mozilla_dom_PerformanceTiming_h