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