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 http = require('http');
71cb0ef41Sopenharmony_ci
81cb0ef41Sopenharmony_ci// Regression test for https://github.com/nodejs/node/issues/13325
91cb0ef41Sopenharmony_ci// Checks that an http.Agent properly asyncReset()s a reused socket handle, and
101cb0ef41Sopenharmony_ci// re-assigns the fresh async id to the reused `net.Socket` instance.
111cb0ef41Sopenharmony_ci
121cb0ef41Sopenharmony_ci// Make sure a single socket is transparently reused for 2 requests.
131cb0ef41Sopenharmony_ciconst agent = new http.Agent({
141cb0ef41Sopenharmony_ci  keepAlive: true,
151cb0ef41Sopenharmony_ci  keepAliveMsecs: Infinity,
161cb0ef41Sopenharmony_ci  maxSockets: 1
171cb0ef41Sopenharmony_ci});
181cb0ef41Sopenharmony_ci
191cb0ef41Sopenharmony_ciconst server = http.createServer(common.mustCall((req, res) => {
201cb0ef41Sopenharmony_ci  req.once('data', common.mustCallAtLeast(() => {
211cb0ef41Sopenharmony_ci    res.writeHead(200, { 'Content-Type': 'text/plain' });
221cb0ef41Sopenharmony_ci    res.write('foo');
231cb0ef41Sopenharmony_ci  }));
241cb0ef41Sopenharmony_ci  req.on('end', common.mustCall(() => {
251cb0ef41Sopenharmony_ci    res.end('bar');
261cb0ef41Sopenharmony_ci  }));
271cb0ef41Sopenharmony_ci}, 2)).listen(0, common.mustCall(() => {
281cb0ef41Sopenharmony_ci  const port = server.address().port;
291cb0ef41Sopenharmony_ci  const payload = 'hello world';
301cb0ef41Sopenharmony_ci
311cb0ef41Sopenharmony_ci  // First request. This is useless except for adding a socket to the
321cb0ef41Sopenharmony_ci  // agent’s pool for reuse.
331cb0ef41Sopenharmony_ci  const r1 = http.request({
341cb0ef41Sopenharmony_ci    agent, port, method: 'POST'
351cb0ef41Sopenharmony_ci  }, common.mustCall((res) => {
361cb0ef41Sopenharmony_ci    // Remember which socket we used.
371cb0ef41Sopenharmony_ci    const socket = res.socket;
381cb0ef41Sopenharmony_ci    const asyncIdAtFirstRequest = socket[async_id_symbol];
391cb0ef41Sopenharmony_ci    assert.ok(asyncIdAtFirstRequest > 0, `${asyncIdAtFirstRequest} > 0`);
401cb0ef41Sopenharmony_ci    // Check that request and response share their socket.
411cb0ef41Sopenharmony_ci    assert.strictEqual(r1.socket, socket);
421cb0ef41Sopenharmony_ci
431cb0ef41Sopenharmony_ci    res.on('data', common.mustCallAtLeast());
441cb0ef41Sopenharmony_ci    res.on('end', common.mustCall(() => {
451cb0ef41Sopenharmony_ci      // setImmediate() to give the agent time to register the freed socket.
461cb0ef41Sopenharmony_ci      setImmediate(common.mustCall(() => {
471cb0ef41Sopenharmony_ci        // The socket is free for reuse now.
481cb0ef41Sopenharmony_ci        assert.strictEqual(socket[async_id_symbol], -1);
491cb0ef41Sopenharmony_ci
501cb0ef41Sopenharmony_ci        // Second request. To re-create the exact conditions from the
511cb0ef41Sopenharmony_ci        // referenced issue, we use a POST request without chunked encoding
521cb0ef41Sopenharmony_ci        // (hence the Content-Length header) and call .end() after the
531cb0ef41Sopenharmony_ci        // response header has already been received.
541cb0ef41Sopenharmony_ci        const r2 = http.request({
551cb0ef41Sopenharmony_ci          agent, port, method: 'POST', headers: {
561cb0ef41Sopenharmony_ci            'Content-Length': payload.length
571cb0ef41Sopenharmony_ci          }
581cb0ef41Sopenharmony_ci        }, common.mustCall((res) => {
591cb0ef41Sopenharmony_ci          const asyncId = res.socket[async_id_symbol];
601cb0ef41Sopenharmony_ci          assert.ok(asyncId > 0, `${asyncId} > 0`);
611cb0ef41Sopenharmony_ci          assert.strictEqual(r2.socket, socket);
621cb0ef41Sopenharmony_ci          // Empty payload, to hit the “right” code path.
631cb0ef41Sopenharmony_ci          r2.end('');
641cb0ef41Sopenharmony_ci
651cb0ef41Sopenharmony_ci          res.on('data', common.mustCallAtLeast());
661cb0ef41Sopenharmony_ci          res.on('end', common.mustCall(() => {
671cb0ef41Sopenharmony_ci            // Clean up to let the event loop stop.
681cb0ef41Sopenharmony_ci            server.close();
691cb0ef41Sopenharmony_ci            agent.destroy();
701cb0ef41Sopenharmony_ci          }));
711cb0ef41Sopenharmony_ci        }));
721cb0ef41Sopenharmony_ci
731cb0ef41Sopenharmony_ci        // Schedule a payload to be written immediately, but do not end the
741cb0ef41Sopenharmony_ci        // request just yet.
751cb0ef41Sopenharmony_ci        r2.write(payload);
761cb0ef41Sopenharmony_ci      }));
771cb0ef41Sopenharmony_ci    }));
781cb0ef41Sopenharmony_ci  }));
791cb0ef41Sopenharmony_ci  r1.end(payload);
801cb0ef41Sopenharmony_ci}));
81