Repository: node
Issue: stream: regression since v12.16.3 with TLS sockets backed by non-net.Socket streams
Labels: stream,regression

* **Version**: v12.16.3+, v14.0.0+, v15.0.0+, master
* **Platform**: n/a
* **Subsystem**: stream

### What steps will reproduce the bug?

The following code needs a private key and certificate for an HTTPS server.

```js
const { readFileSync } = require('fs');
const tls = require('tls');
const https = require('https');
const net = require('net');
const { Duplex } = require('stream');

class CustomAgent extends https.Agent {
  constructor() {
    super();
  }
  createConnection(options, cb) {
    const realSocket = net.createConnection(options);
    const stream = new Duplex({
      emitClose: false,
      read(n) {
        (function retry() {
          const data = realSocket.read();
          if (data === null)
            return realSocket.once('readable', retry);
          stream.push(data);
        })();
      },
      write(chunk, enc, callback) {
        realSocket.write(chunk, enc, callback);
      },
    });
    realSocket.on('end', () => stream.push(null));

    stream.on('end', () => {
      console.log('stream end');
    }).on('close', () => {
      console.log('stream close');
    });

    return tls.connect({ ...options, socket: stream });
  }
}

const httpsServer = https.createServer({
  key: readFileSync('https_key.pem'),
  cert: readFileSync('https_cert.pem'),
}, (req, res) => {
  httpsServer.close();
  res.end('hello world!');
});
httpsServer.listen(0, 'localhost', () => {
  const agent = new CustomAgent();
  https.get({
    host: 'localhost',
    port: httpsServer.address().port,
    agent,
    headers: { Connection: 'close' },
    ca: readFileSync('https_cert.pem'),
  }, (res) => {
    res.resume();
  });
});
```

### How often does it reproduce? Is there a required condition?

Every time.

### What is the expected behavior?

"stream end" should be displayed

### What do you see instead?

Nothing is displayed.

### Additional information

This was originally discovered while adding tests for custom HTTP and HTTPS agents for the `ssh2` module. I believe the key here is mainly using a custom stream for the socket passed to `tls.connect()`. However the regression only became evident once I started setting `emitClose: false` because my agent implementation was relying on the `'close'` event being emitted to know when to close the underlying ssh connection and emitting `'close'` is expected to be handled by `ssh2` (because the protocol has an explicit close message separate from "EOF").

Bisecting reveals ed21d32a7c37d030ce4668415832a89dc8ead34c as the bad commit. What's happening is that when `TLSSocket` sees that the `socket` option is some custom object/stream and not a `net.Socket` instance, it wraps the stream with a `JSStreamSocket`. `JSStreamSocket` happens to have a `readStop()` implementation that simply pauses the socket. Since ed21d32a7c37d030ce4668415832a89dc8ead34c added a check for this method's existence, it now gets called when the TLS portion ends, which means the underlying/original stream now stays paused and will never emit `'end'` like it used to.

Judging by the added code comments, it appears that this change was made to appease some error on Windows. I think the original error should be solved in a more compatible way.

/cc @ronag @addaleax @lpinca