11cb0ef41Sopenharmony_ci'use strict'; 21cb0ef41Sopenharmony_ci// Flags: --expose-internals 31cb0ef41Sopenharmony_ciconst common = require('../common'); 41cb0ef41Sopenharmony_ciconst assert = require('assert'); 51cb0ef41Sopenharmony_ciconst { async_id_symbol } = require('internal/async_hooks').symbols; 61cb0ef41Sopenharmony_ciconst async_hooks = require('async_hooks'); 71cb0ef41Sopenharmony_ciconst http = require('http'); 81cb0ef41Sopenharmony_ci 91cb0ef41Sopenharmony_ci// Regression test for https://github.com/nodejs/node/issues/19859 101cb0ef41Sopenharmony_ci// Checks that an http.Agent emits a destroy for the old asyncId before calling 111cb0ef41Sopenharmony_ci// asyncReset()s when reusing a socket handle. The setup is nearly identical to 121cb0ef41Sopenharmony_ci// parallel/test-async-hooks-http-agent (which focuses on the assertion that 131cb0ef41Sopenharmony_ci// a fresh asyncId is assigned to the net.Socket instance). 141cb0ef41Sopenharmony_ci 151cb0ef41Sopenharmony_ciconst destroyedIds = new Set(); 161cb0ef41Sopenharmony_ciasync_hooks.createHook({ 171cb0ef41Sopenharmony_ci destroy: common.mustCallAtLeast((asyncId) => { 181cb0ef41Sopenharmony_ci destroyedIds.add(asyncId); 191cb0ef41Sopenharmony_ci }, 1) 201cb0ef41Sopenharmony_ci}).enable(); 211cb0ef41Sopenharmony_ci 221cb0ef41Sopenharmony_ci// Make sure a single socket is transparently reused for 2 requests. 231cb0ef41Sopenharmony_ciconst agent = new http.Agent({ 241cb0ef41Sopenharmony_ci keepAlive: true, 251cb0ef41Sopenharmony_ci keepAliveMsecs: Infinity, 261cb0ef41Sopenharmony_ci maxSockets: 1 271cb0ef41Sopenharmony_ci}); 281cb0ef41Sopenharmony_ci 291cb0ef41Sopenharmony_ciconst server = http.createServer(common.mustCall((req, res) => { 301cb0ef41Sopenharmony_ci req.once('data', common.mustCallAtLeast(() => { 311cb0ef41Sopenharmony_ci res.writeHead(200, { 'Content-Type': 'text/plain' }); 321cb0ef41Sopenharmony_ci res.write('foo'); 331cb0ef41Sopenharmony_ci })); 341cb0ef41Sopenharmony_ci req.on('end', common.mustCall(() => { 351cb0ef41Sopenharmony_ci res.end('bar'); 361cb0ef41Sopenharmony_ci })); 371cb0ef41Sopenharmony_ci}, 2)).listen(0, common.mustCall(() => { 381cb0ef41Sopenharmony_ci const port = server.address().port; 391cb0ef41Sopenharmony_ci const payload = 'hello world'; 401cb0ef41Sopenharmony_ci 411cb0ef41Sopenharmony_ci // First request. This is useless except for adding a socket to the 421cb0ef41Sopenharmony_ci // agent’s pool for reuse. 431cb0ef41Sopenharmony_ci const r1 = http.request({ 441cb0ef41Sopenharmony_ci agent, port, method: 'POST' 451cb0ef41Sopenharmony_ci }, common.mustCall((res) => { 461cb0ef41Sopenharmony_ci // Remember which socket we used. 471cb0ef41Sopenharmony_ci const socket = res.socket; 481cb0ef41Sopenharmony_ci const asyncIdAtFirstRequest = socket[async_id_symbol]; 491cb0ef41Sopenharmony_ci assert.ok(asyncIdAtFirstRequest > 0, `${asyncIdAtFirstRequest} > 0`); 501cb0ef41Sopenharmony_ci // Check that request and response share their socket. 511cb0ef41Sopenharmony_ci assert.strictEqual(r1.socket, socket); 521cb0ef41Sopenharmony_ci 531cb0ef41Sopenharmony_ci res.on('data', common.mustCallAtLeast()); 541cb0ef41Sopenharmony_ci res.on('end', common.mustCall(() => { 551cb0ef41Sopenharmony_ci // setImmediate() to give the agent time to register the freed socket. 561cb0ef41Sopenharmony_ci setImmediate(common.mustCall(() => { 571cb0ef41Sopenharmony_ci // The socket is free for reuse now. 581cb0ef41Sopenharmony_ci assert.strictEqual(socket[async_id_symbol], -1); 591cb0ef41Sopenharmony_ci 601cb0ef41Sopenharmony_ci // second request: 611cb0ef41Sopenharmony_ci const r2 = http.request({ 621cb0ef41Sopenharmony_ci agent, port, method: 'POST' 631cb0ef41Sopenharmony_ci }, common.mustCall((res) => { 641cb0ef41Sopenharmony_ci assert.ok(destroyedIds.has(asyncIdAtFirstRequest)); 651cb0ef41Sopenharmony_ci 661cb0ef41Sopenharmony_ci // Empty payload, to hit the “right” code path. 671cb0ef41Sopenharmony_ci r2.end(''); 681cb0ef41Sopenharmony_ci 691cb0ef41Sopenharmony_ci res.on('data', common.mustCallAtLeast()); 701cb0ef41Sopenharmony_ci res.on('end', common.mustCall(() => { 711cb0ef41Sopenharmony_ci // Clean up to let the event loop stop. 721cb0ef41Sopenharmony_ci server.close(); 731cb0ef41Sopenharmony_ci agent.destroy(); 741cb0ef41Sopenharmony_ci })); 751cb0ef41Sopenharmony_ci })); 761cb0ef41Sopenharmony_ci 771cb0ef41Sopenharmony_ci // Schedule a payload to be written immediately, but do not end the 781cb0ef41Sopenharmony_ci // request just yet. 791cb0ef41Sopenharmony_ci r2.write(payload); 801cb0ef41Sopenharmony_ci })); 811cb0ef41Sopenharmony_ci })); 821cb0ef41Sopenharmony_ci })); 831cb0ef41Sopenharmony_ci r1.end(payload); 841cb0ef41Sopenharmony_ci})); 85