diff --git a/lib/handler/unwrap-handler.js b/lib/handler/unwrap-handler.js index 865593a327b..e23b9666cf7 100644 --- a/lib/handler/unwrap-handler.js +++ b/lib/handler/unwrap-handler.js @@ -67,6 +67,10 @@ module.exports = class UnwrapHandler { this.#handler.onRequestStart?.(this.#controller, context) } + onResponseStarted () { + return this.#handler.onResponseStarted?.() + } + onUpgrade (statusCode, rawHeaders, socket) { this.#handler.onRequestUpgrade?.(this.#controller, statusCode, parseHeaders(rawHeaders), socket) } diff --git a/lib/handler/wrap-handler.js b/lib/handler/wrap-handler.js index 47caa5fa68b..6d2f56d2a36 100644 --- a/lib/handler/wrap-handler.js +++ b/lib/handler/wrap-handler.js @@ -20,6 +20,10 @@ module.exports = class WrapHandler { return this.#handler.onConnect?.(abort, context) } + onResponseStarted () { + return this.#handler.onResponseStarted?.() + } + onHeaders (statusCode, rawHeaders, resume, statusMessage) { return this.#handler.onHeaders?.(statusCode, rawHeaders, resume, statusMessage) } diff --git a/test/fetch/resource-timing.js b/test/fetch/resource-timing.js index c060dba30cc..e6c8d0e830d 100644 --- a/test/fetch/resource-timing.js +++ b/test/fetch/resource-timing.js @@ -2,7 +2,7 @@ const { test } = require('node:test') const { createServer } = require('node:http') -const { fetch } = require('../..') +const { fetch, Agent } = require('../..') const { closeServerAsPromise } = require('../utils/node-http') const { @@ -138,3 +138,31 @@ test('redirect timing entries should be included when redirecting', (t, done) => t.after(closeServerAsPromise(server)) }) + +test('responseStart should be greater than 0 with composed interceptor', (t, done) => { + t.plan(4) + const obs = new PerformanceObserver(list => { + const [entry] = list.getEntries() + + t.assert.ok(entry.requestStart > 0, `requestStart should be > 0, got ${entry.requestStart}`) + t.assert.ok(entry.responseStart > 0, `responseStart should be > 0, got ${entry.responseStart}`) + t.assert.ok(entry.responseStart >= entry.requestStart, 'responseStart should be >= requestStart') + + obs.disconnect() + performance.clearResourceTimings() + done() + }) + + obs.observe({ entryTypes: ['resource'] }) + + const dispatcher = new Agent().compose((dispatch) => (opts, handler) => dispatch(opts, handler)) + + const server = createServer({ joinDuplicateHeaders: true }, (req, res) => { + res.end('ok') + }).listen(0, async () => { + const body = await fetch(`http://localhost:${server.address().port}`, { dispatcher }) + t.assert.strictEqual('ok', await body.text()) + }) + + t.after(closeServerAsPromise(server)) +}) diff --git a/test/node-test/client-dispatch.js b/test/node-test/client-dispatch.js index 06862150efb..2ad355f6571 100644 --- a/test/node-test/client-dispatch.js +++ b/test/node-test/client-dispatch.js @@ -870,6 +870,45 @@ test('dispatches in expected order', async (t) => { await p.completed }) +test('onResponseStarted is called with interceptor', async (t) => { + const server = http.createServer({ joinDuplicateHeaders: true }, (req, res) => { + res.end('ended') + }) + t.after(closeServerAsPromise(server)) + + const p = tspl(t, { plan: 2 }) + + server.listen(0, () => { + const pool = new Pool(`http://localhost:${server.address().port}`) + const client = pool.compose((dispatch) => (opts, handler) => dispatch(opts, handler)) + + t.after(() => { return pool.close() }) + + let responseStartedCalled = false + + client.dispatch({ + path: '/', + method: 'GET' + }, { + onConnect () {}, + onResponseStarted () { + responseStartedCalled = true + }, + onHeaders () {}, + onData () {}, + onComplete () { + p.strictEqual(responseStartedCalled, true) + p.ok(true) + }, + onError (err) { + p.ifError(err) + } + }) + }) + + await p.completed +}) + test('dispatches in expected order for http2', async (t) => { const server = createSecureServer(pem) server.on('stream', (stream) => {