diff --git a/doc/api/perf_hooks.md b/doc/api/perf_hooks.md index 61e228113ef..7646e4d846a 100644 --- a/doc/api/perf_hooks.md +++ b/doc/api/perf_hooks.md @@ -246,12 +246,16 @@ and can be queried with `performance.getEntries`, observation is performed, the entries should be cleared from the global Performance Timeline manually with `performance.clearMarks`. -### `performance.markResourceTiming(timingInfo, requestedUrl, initiatorType, global, cacheMode)` +### `performance.markResourceTiming(timingInfo, requestedUrl, initiatorType, global, cacheMode, bodyInfo, responseStatus[, deliveryType])` * `timingInfo` {Object} [Fetch Timing Info][] @@ -259,6 +263,9 @@ added: * `initiatorType` {string} The initiator name, e.g: 'fetch' * `global` {Object} * `cacheMode` {string} The cache mode must be an empty string ('') or 'local' +* `bodyInfo` {Object} [Fetch Response Body Info][] +* `responseStatus` {number} The response's status code +* `deliveryType` {string} The delivery type. **Default:** `''`. _This property is an extension by Node.js. It is not available in Web browsers._ @@ -1911,6 +1918,7 @@ dns.promises.resolve('localhost'); ``` [Async Hooks]: async_hooks.md +[Fetch Response Body Info]: https://fetch.spec.whatwg.org/#response-body-info [Fetch Timing Info]: https://fetch.spec.whatwg.org/#fetch-timing-info [High Resolution Time]: https://www.w3.org/TR/hr-time-2 [Performance Timeline]: https://w3c.github.io/performance-timeline/ diff --git a/lib/internal/perf/resource_timing.js b/lib/internal/perf/resource_timing.js index e7c2f1fa448..a037d5c0945 100644 --- a/lib/internal/perf/resource_timing.js +++ b/lib/internal/perf/resource_timing.js @@ -21,6 +21,8 @@ const kCacheMode = Symbol('kCacheMode'); const kRequestedUrl = Symbol('kRequestedUrl'); const kTimingInfo = Symbol('kTimingInfo'); const kInitiatorType = Symbol('kInitiatorType'); +const kDeliveryType = Symbol('kDeliveryType'); +const kResponseStatus = Symbol('kResponseStatus'); class PerformanceResourceTiming extends PerformanceEntry { constructor(skipThrowSymbol = undefined, name = undefined, type = undefined) { @@ -136,6 +138,16 @@ class PerformanceResourceTiming extends PerformanceEntry { return this[kTimingInfo].encodedBodySize + 300; } + get deliveryType() { + validateInternalField(this, kTimingInfo, 'PerformanceResourceTiming'); + return this[kDeliveryType]; + } + + get responseStatus() { + validateInternalField(this, kTimingInfo, 'PerformanceResourceTiming'); + return this[kResponseStatus]; + } + toJSON() { validateInternalField(this, kInitiatorType, 'PerformanceResourceTiming'); return { @@ -160,6 +172,8 @@ class PerformanceResourceTiming extends PerformanceEntry { transferSize: this.transferSize, encodedBodySize: this.encodedBodySize, decodedBodySize: this.decodedBodySize, + deliveryType: this.deliveryType, + responseStatus: this.responseStatus, }; } } @@ -182,6 +196,8 @@ ObjectDefineProperties(PerformanceResourceTiming.prototype, { transferSize: kEnumerableProperty, encodedBodySize: kEnumerableProperty, decodedBodySize: kEnumerableProperty, + deliveryType: kEnumerableProperty, + responseStatus: kEnumerableProperty, toJSON: kEnumerableProperty, [SymbolToStringTag]: { __proto__: null, @@ -190,7 +206,15 @@ ObjectDefineProperties(PerformanceResourceTiming.prototype, { }, }); -function createPerformanceResourceTiming(requestedUrl, initiatorType, timingInfo, cacheMode = '') { +function createPerformanceResourceTiming( + requestedUrl, + initiatorType, + timingInfo, + cacheMode = '', + bodyInfo, + responseStatus, + deliveryType, +) { const resourceTiming = new PerformanceResourceTiming(kSkipThrow, requestedUrl, 'resource'); resourceTiming[kInitiatorType] = initiatorType; @@ -200,6 +224,8 @@ function createPerformanceResourceTiming(requestedUrl, initiatorType, timingInfo // The spec doesn't say to validate it in the class construction. resourceTiming[kTimingInfo] = timingInfo; resourceTiming[kCacheMode] = cacheMode; + resourceTiming[kDeliveryType] = deliveryType; + resourceTiming[kResponseStatus] = responseStatus; return resourceTiming; } @@ -211,6 +237,9 @@ function markResourceTiming( initiatorType, global, cacheMode, + bodyInfo, + responseStatus, + deliveryType = '', ) { // https://w3c.github.io/resource-timing/#dfn-setup-the-resource-timing-entry assert( @@ -222,6 +251,9 @@ function markResourceTiming( initiatorType, timingInfo, cacheMode, + bodyInfo, + responseStatus, + deliveryType, ); enqueue(resource); diff --git a/test/parallel/test-perf-hooks-resourcetiming.js b/test/parallel/test-perf-hooks-resourcetiming.js index f9574e90022..67893ca9741 100644 --- a/test/parallel/test-perf-hooks-resourcetiming.js +++ b/test/parallel/test-perf-hooks-resourcetiming.js @@ -86,6 +86,9 @@ function createTimingInfo({ initiatorType, customGlobal, cacheMode, + {}, + 200, + '', ); assert(resource instanceof PerformanceEntry); @@ -128,6 +131,9 @@ function createTimingInfo({ initiatorType, customGlobal, cacheMode, + {}, + 200, + '', ); assert(resource instanceof PerformanceEntry); @@ -155,6 +161,8 @@ function createTimingInfo({ assert.strictEqual(resource.encodedBodySize, 0); assert.strictEqual(resource.decodedBodySize, 0); assert.strictEqual(resource.transferSize, 0); + assert.strictEqual(resource.deliveryType, ''); + assert.strictEqual(resource.responseStatus, 200); assert.deepStrictEqual(resource.toJSON(), { name: requestedUrl, entryType: 'resource', @@ -177,6 +185,8 @@ function createTimingInfo({ transferSize: 0, encodedBodySize: 0, decodedBodySize: 0, + responseStatus: 200, + deliveryType: '', }); assert.strictEqual(util.inspect(performance.getEntries()), `[ PerformanceResourceTiming { @@ -200,7 +210,9 @@ function createTimingInfo({ responseEnd: 0, transferSize: 0, encodedBodySize: 0, - decodedBodySize: 0 + decodedBodySize: 0, + deliveryType: '', + responseStatus: 200 } ]`); assert.strictEqual(util.inspect(resource), `PerformanceResourceTiming { @@ -224,7 +236,9 @@ function createTimingInfo({ responseEnd: 0, transferSize: 0, encodedBodySize: 0, - decodedBodySize: 0 + decodedBodySize: 0, + deliveryType: '', + responseStatus: 200 }`); assert(resource instanceof PerformanceEntry); @@ -252,6 +266,9 @@ function createTimingInfo({ initiatorType, customGlobal, cacheMode, + {}, + 200, + '', ); assert(resource instanceof PerformanceEntry); @@ -307,6 +324,9 @@ function createTimingInfo({ initiatorType, customGlobal, cacheMode, + {}, + 200, + '' ); assert(resource instanceof PerformanceEntry); diff --git a/test/parallel/test-performance-resourcetimingbufferfull.js b/test/parallel/test-performance-resourcetimingbufferfull.js index 9c595610a67..d962bdf8cfd 100644 --- a/test/parallel/test-performance-resourcetimingbufferfull.js +++ b/test/parallel/test-performance-resourcetimingbufferfull.js @@ -34,10 +34,19 @@ const cacheMode = ''; async function main() { performance.setResourceTimingBufferSize(1); - performance.markResourceTiming(createTimingInfo(1), requestedUrl, initiatorType, globalThis, cacheMode); + const args = [ + requestedUrl, + initiatorType, + globalThis, + cacheMode, + {}, // body info + 200, + '', + ]; + performance.markResourceTiming(createTimingInfo(1), ...args); // Trigger a resourcetimingbufferfull event. - performance.markResourceTiming(createTimingInfo(2), requestedUrl, initiatorType, globalThis, cacheMode); - performance.markResourceTiming(createTimingInfo(3), requestedUrl, initiatorType, globalThis, cacheMode); + performance.markResourceTiming(createTimingInfo(2), ...args); + performance.markResourceTiming(createTimingInfo(3), ...args); assert.strictEqual(performance.getEntriesByType('resource').length, 1); // Clear resource timings on resourcetimingbufferfull event. @@ -65,10 +74,10 @@ async function main() { performance.clearResourceTimings(); performance.setResourceTimingBufferSize(1); - performance.markResourceTiming(createTimingInfo(4), requestedUrl, initiatorType, globalThis, cacheMode); + performance.markResourceTiming(createTimingInfo(4), ...args); // Trigger a resourcetimingbufferfull event. - performance.markResourceTiming(createTimingInfo(5), requestedUrl, initiatorType, globalThis, cacheMode); - performance.markResourceTiming(createTimingInfo(6), requestedUrl, initiatorType, globalThis, cacheMode); + performance.markResourceTiming(createTimingInfo(5), ...args); + performance.markResourceTiming(createTimingInfo(6), ...args); // Increase the buffer size on resourcetimingbufferfull event. await new Promise((resolve) => { @@ -96,10 +105,10 @@ async function main() { performance.clearResourceTimings(); performance.setResourceTimingBufferSize(2); - performance.markResourceTiming(createTimingInfo(7), requestedUrl, initiatorType, globalThis, cacheMode); - performance.markResourceTiming(createTimingInfo(8), requestedUrl, initiatorType, globalThis, cacheMode); + performance.markResourceTiming(createTimingInfo(7), ...args); + performance.markResourceTiming(createTimingInfo(8), ...args); // Trigger a resourcetimingbufferfull event. - performance.markResourceTiming(createTimingInfo(9), requestedUrl, initiatorType, globalThis, cacheMode); + performance.markResourceTiming(createTimingInfo(9), ...args); // Decrease the buffer size on resourcetimingbufferfull event. await new Promise((resolve) => { diff --git a/test/parallel/test-performance-resourcetimingbuffersize.js b/test/parallel/test-performance-resourcetimingbuffersize.js index 3b9e77799b3..c9c84dc9416 100644 --- a/test/parallel/test-performance-resourcetimingbuffersize.js +++ b/test/parallel/test-performance-resourcetimingbuffersize.js @@ -30,11 +30,18 @@ const initiatorType = ''; const cacheMode = ''; async function main() { + const args = [ + timingInfo, + requestedUrl, + initiatorType, + globalThis, + cacheMode, + ]; // Invalid buffer size values are converted to 0. const invalidValues = [ null, undefined, true, false, -1, 0.5, Infinity, NaN, '', 'foo', {}, [], () => {} ]; for (const value of invalidValues) { performance.setResourceTimingBufferSize(value); - performance.markResourceTiming(timingInfo, requestedUrl, initiatorType, globalThis, cacheMode); + performance.markResourceTiming(...args); assert.strictEqual(performance.getEntriesByType('resource').length, 0); performance.clearResourceTimings(); } @@ -42,9 +49,9 @@ async function main() { await waitBufferFullEvent(); performance.setResourceTimingBufferSize(1); - performance.markResourceTiming(timingInfo, requestedUrl, initiatorType, globalThis, cacheMode); + performance.markResourceTiming(...args); // Trigger a resourcetimingbufferfull event. - performance.markResourceTiming(timingInfo, requestedUrl, initiatorType, globalThis, cacheMode); + performance.markResourceTiming(...args); assert.strictEqual(performance.getEntriesByType('resource').length, 1); await waitBufferFullEvent(); @@ -56,14 +63,14 @@ async function main() { performance.clearResourceTimings(); assert.strictEqual(performance.getEntriesByType('resource').length, 0); // Trigger a resourcetimingbufferfull event. - performance.markResourceTiming(timingInfo, requestedUrl, initiatorType, globalThis, cacheMode); + performance.markResourceTiming(...args); // New entry is not added to the global buffer. assert.strictEqual(performance.getEntriesByType('resource').length, 0); await waitBufferFullEvent(); // Apply a new buffer size limit performance.setResourceTimingBufferSize(1); - performance.markResourceTiming(timingInfo, requestedUrl, initiatorType, globalThis, cacheMode); + performance.markResourceTiming(...args); assert.strictEqual(performance.getEntriesByType('resource').length, 1); } diff --git a/test/wpt/status/resource-timing.json b/test/wpt/status/resource-timing.json index db515426022..f40f8fe51da 100644 --- a/test/wpt/status/resource-timing.json +++ b/test/wpt/status/resource-timing.json @@ -23,14 +23,10 @@ "idlharness.any.js": { "fail": { "expected": [ - "PerformanceResourceTiming interface: attribute deliveryType", "PerformanceResourceTiming interface: attribute firstInterimResponseStart", - "PerformanceResourceTiming interface: attribute responseStatus", "PerformanceResourceTiming interface: attribute renderBlockingStatus", "PerformanceResourceTiming interface: attribute contentType", - "PerformanceResourceTiming interface: resource must inherit property \"deliveryType\" with the proper type", "PerformanceResourceTiming interface: resource must inherit property \"firstInterimResponseStart\" with the proper type", - "PerformanceResourceTiming interface: resource must inherit property \"responseStatus\" with the proper type", "PerformanceResourceTiming interface: resource must inherit property \"renderBlockingStatus\" with the proper type", "PerformanceResourceTiming interface: resource must inherit property \"contentType\" with the proper type", "PerformanceResourceTiming interface: default toJSON operation on resource" diff --git a/test/wpt/test-performance-timeline.js b/test/wpt/test-performance-timeline.js index dddce0dab8a..78a1f5b3e7c 100644 --- a/test/wpt/test-performance-timeline.js +++ b/test/wpt/test-performance-timeline.js @@ -27,7 +27,7 @@ runner.setInitScript(` finalNetworkResponseStartTime: 0, encodedBodySize: 0, decodedBodySize: 0, - }, 'https://nodejs.org', '', global, ''); + }, 'https://nodejs.org', '', global, '', {}, 200, ''); `); runner.runJsTests(); diff --git a/test/wpt/test-resource-timing.js b/test/wpt/test-resource-timing.js index 9f9aab55dc4..f30c7b2e44d 100644 --- a/test/wpt/test-resource-timing.js +++ b/test/wpt/test-resource-timing.js @@ -25,7 +25,7 @@ runner.setInitScript(` finalNetworkResponseStartTime: 0, encodedBodySize: 0, decodedBodySize: 0, - }, 'https://nodejs.org', '', global, ''); + }, 'https://nodejs.org', '', global, '', {}, 200, ''); `); runner.runJsTests();