Skip to content

Unable to properly cleanup underlying socket with close/terminate #1869

Closed
@cTn-dev

Description

@cTn-dev

Description

Hi Luigi, i am a bit lost if this a valid edge case to report. but i do find it "odd" that reading the payload from the response (while doing such successfully) can result in the underlying socket being left open).

Calling the request.socket.destroy(); after response end event fires bypasses the problem.
Is this behavior expected from your point of view?

Reproducible in:

  • version: 7.4.4
  • Node.js version(s): v14.16.1
  • OS version(s): Fedora 33, 5.11.12-200.fc33.x86_64

Steps to reproduce:

Demo server (returning invalid data on purpose):

let http = require('http');
let server = http.createServer(function (req, res) {
  res.writeHead(502, {'Content-Type': 'text/html'});
  res.write('uhoh\r\n');
  res.end();
});
server.keepAliveTimeout = 0;
server.listen(4987);

Client demonstrating the issue:

const WebSocket = require('ws');

for (let id = 0; id < 100; id++) {
  let ws = new WebSocket('ws:127.0.0.1:4987');

  ws.on('open', () => {});
  ws.on('close', (code, reason) => {
    console.log('close', id, code, reason);
  });
  ws.on('error', (error) => {
    console.log('error', id, error.toString());
  });
  ws.on('unexpected-response', (request, response) => {
    let chunks = [];
    let payload = null;

    response.on('data', (chunk) => chunks.push(chunk));
    response.on('end', () => {
      payload = Buffer.concat(chunks).toString();

      // uncommenting this when ready
      // request.socket.destroy();

      ws.terminate();
    });
  });
}

Expected result:

With the demo client code above, the bottom line is that the node process shuts down on its own.

Actual result:

The demo client code did not shut down because the underlying TCP sockets are left in ESTABLISHED state.
Regardless of calling ws.close() or ws.terminate().

The "trigger" for the above scenario appears to be binding the additional event handlers used to read the response payload (which does succeeds).

You can confirm that the connections are left open by doing netstat -an | grep ':4987' | grep ESTABLISHED | wc -l

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions