1'use strict'; 2// https://developer.mozilla.org/en-US/docs/Web/API/PerformanceResourceTiming 3 4const { InternalPerformanceEntry } = require('internal/perf/performance_entry'); 5const { SymbolToStringTag } = primordials; 6const assert = require('internal/assert'); 7const { enqueue, bufferResourceTiming } = require('internal/perf/observe'); 8const { Symbol, ObjectSetPrototypeOf } = primordials; 9 10const kCacheMode = Symbol('kCacheMode'); 11const kRequestedUrl = Symbol('kRequestedUrl'); 12const kTimingInfo = Symbol('kTimingInfo'); 13const kInitiatorType = Symbol('kInitiatorType'); 14 15const { 16 codes: { 17 ERR_ILLEGAL_CONSTRUCTOR, 18 }, 19} = require('internal/errors'); 20 21class InternalPerformanceResourceTiming extends InternalPerformanceEntry { 22 constructor(requestedUrl, initiatorType, timingInfo, cacheMode = '') { 23 super(requestedUrl, 'resource'); 24 this[kInitiatorType] = initiatorType; 25 this[kRequestedUrl] = requestedUrl; 26 // https://fetch.spec.whatwg.org/#fetch-timing-info 27 // This class is using timingInfo assuming it's already validated. 28 // The spec doesn't say to validate it in the class construction. 29 this[kTimingInfo] = timingInfo; 30 this[kCacheMode] = cacheMode; 31 } 32 33 get [SymbolToStringTag]() { 34 return 'PerformanceResourceTiming'; 35 } 36 37 get name() { 38 return this[kRequestedUrl]; 39 } 40 41 get startTime() { 42 return this[kTimingInfo].startTime; 43 } 44 45 get duration() { 46 return this[kTimingInfo].endTime - this[kTimingInfo].startTime; 47 } 48 49 get initiatorType() { 50 return this[kInitiatorType]; 51 } 52 53 get workerStart() { 54 return this[kTimingInfo].finalServiceWorkerStartTime; 55 } 56 57 get redirectStart() { 58 return this[kTimingInfo].redirectStartTime; 59 } 60 61 get redirectEnd() { 62 return this[kTimingInfo].redirectEndTime; 63 } 64 65 get fetchStart() { 66 return this[kTimingInfo].postRedirectStartTime; 67 } 68 69 get domainLookupStart() { 70 return this[kTimingInfo].finalConnectionTimingInfo?.domainLookupStartTime; 71 } 72 73 get domainLookupEnd() { 74 return this[kTimingInfo].finalConnectionTimingInfo?.domainLookupEndTime; 75 } 76 77 get connectStart() { 78 return this[kTimingInfo].finalConnectionTimingInfo?.connectionStartTime; 79 } 80 81 get connectEnd() { 82 return this[kTimingInfo].finalConnectionTimingInfo?.connectionEndTime; 83 } 84 85 get secureConnectionStart() { 86 return this[kTimingInfo] 87 .finalConnectionTimingInfo?.secureConnectionStartTime; 88 } 89 90 get nextHopProtocol() { 91 return this[kTimingInfo] 92 .finalConnectionTimingInfo?.ALPNNegotiatedProtocol; 93 } 94 95 get requestStart() { 96 return this[kTimingInfo].finalNetworkRequestStartTime; 97 } 98 99 get responseStart() { 100 return this[kTimingInfo].finalNetworkResponseStartTime; 101 } 102 103 get responseEnd() { 104 return this[kTimingInfo].endTime; 105 } 106 107 get encodedBodySize() { 108 return this[kTimingInfo].encodedBodySize; 109 } 110 111 get decodedBodySize() { 112 return this[kTimingInfo].decodedBodySize; 113 } 114 115 get transferSize() { 116 if (this[kCacheMode] === 'local') return 0; 117 if (this[kCacheMode] === 'validated') return 300; 118 119 return this[kTimingInfo].encodedBodySize + 300; 120 } 121 122 toJSON() { 123 return { 124 name: this.name, 125 entryType: this.entryType, 126 startTime: this.startTime, 127 duration: this.duration, 128 initiatorType: this[kInitiatorType], 129 nextHopProtocol: this.nextHopProtocol, 130 workerStart: this.workerStart, 131 redirectStart: this.redirectStart, 132 redirectEnd: this.redirectEnd, 133 fetchStart: this.fetchStart, 134 domainLookupStart: this.domainLookupStart, 135 domainLookupEnd: this.domainLookupEnd, 136 connectStart: this.connectStart, 137 connectEnd: this.connectEnd, 138 secureConnectionStart: this.secureConnectionStart, 139 requestStart: this.requestStart, 140 responseStart: this.responseStart, 141 responseEnd: this.responseEnd, 142 transferSize: this.transferSize, 143 encodedBodySize: this.encodedBodySize, 144 decodedBodySize: this.decodedBodySize, 145 }; 146 } 147} 148 149class PerformanceResourceTiming extends InternalPerformanceResourceTiming { 150 constructor() { 151 throw new ERR_ILLEGAL_CONSTRUCTOR(); 152 } 153} 154 155// https://w3c.github.io/resource-timing/#dfn-mark-resource-timing 156function markResourceTiming( 157 timingInfo, 158 requestedUrl, 159 initiatorType, 160 global, 161 cacheMode, 162) { 163 // https://w3c.github.io/resource-timing/#dfn-setup-the-resource-timing-entry 164 assert( 165 cacheMode === '' || cacheMode === 'local', 166 'cache must be an empty string or \'local\'', 167 ); 168 const resource = new InternalPerformanceResourceTiming( 169 requestedUrl, 170 initiatorType, 171 timingInfo, 172 cacheMode, 173 ); 174 175 ObjectSetPrototypeOf(resource, PerformanceResourceTiming.prototype); 176 enqueue(resource); 177 bufferResourceTiming(resource); 178 return resource; 179} 180 181module.exports = { 182 PerformanceResourceTiming, 183 markResourceTiming, 184}; 185