Repository: node
Issue: Almost guaranteed ECONNRESET on piped sockets if connecting to Node's HTTPS server which answers with "connection: 'close'" after setImmediate or setTimeout, on OSX
Labels: help wanted,http

* **Version**: v10.11.0
* **Platform**: Darwin localhost.local 15.6.0 Darwin Kernel Version 15.6.0: Thu Jun 21 20:07:40 PDT 2018; root:xnu-3248.73.11~1/RELEASE_X86_64 x86_64 (aka OSX 10.11.6, also happens on High Sierra)
* **Subsystem**: ???

In the following code, `pem` is [a module from NPM](https://www.npmjs.com/package/pem), and the rest is an HTTP proxy which serves CONNECT requests and pipes them to an HTTPS server defined in the same script:

```javascript
const http = require('http');
const https = require('https');
const pem = require('pem');
const net = require('net');

const createHttpsServer = (callback) => {
  pem.createCertificate({
    days: 365,
    selfSigned: true
  }, (error, {serviceKey, certificate, csr}) => {
    const server = https.createServer({
      ca: csr,
      cert: certificate,
      key: serviceKey
    }, (req, res) => {
      setImmediate(() => {
        res.writeHead(200, {
          connection: 'close'
        });
        res.end('OK');
      });
    });

    server.listen((error) => {
      if (error) {
        console.error(error);
      } else {
        callback(null, server.address().port);
      }
    });
  });
};

const createProxy = (httpsServerPort) => {
  const proxy = http.createServer();
  proxy.on('connect', (request, requestSocket, head) => {
    const serverSocket = net.connect({
      port: httpsServerPort
    }, 'localhost', () => {
      requestSocket.write(
        'HTTP/1.1 200 Connection established\r\n\r\n'
      );

      serverSocket.write(head);
      serverSocket.pipe(requestSocket);
      requestSocket.pipe(serverSocket);
    });
  });

  proxy.listen(9000);
};

createHttpsServer((error, httpsServerPort) => {
  if (error) {
    console.error(error);
  } else {
    createProxy(httpsServerPort);
  }
});
```

If you run `curl --proxy http://localhost:9000 https://qweasd/ -k`, you'll see Curl receive the reply, and meanwhile the script will almost certainly fail with:

```
events.js:167
      throw er; // Unhandled 'error' event
      ^

Error: read ECONNRESET
    at TCP.onStreamRead (internal/stream_base_commons.js:111:27)
Emitted 'error' event at:
    at Socket.onerror (_stream_readable.js:690:12)
    at Socket.emit (events.js:182:13)
    at emitErrorNT (internal/streams/destroy.js:82:8)
    at emitErrorAndCloseNT (internal/streams/destroy.js:50:3)
    at process._tickCallback (internal/process/next_tick.js:63:19)
```

This issue is dependent on several parameters:
- You're running OSX. El Capitan and High Sierra both exhibit this, an Ubuntu VM doesn't.
- The server is HTTPS: an HTTP server and `curl --proxytunnel` work alright.
- The server is running in the same script as the proxy.
- The server answers with a `connection: 'close'` header.
- The strangest one: the server request handler has `setImmediate` or `setTimeout` around the reply (with, I guess, any timeout value). `process.nextTick` doesn't do it. And if the handler instead serves the reply immediately, the server continues to answer perfectly alright until you hit a seemingly different ECONNRESET.

If you adorn the sockets with `error` event handlers, you'll see that the errors actually don't happen on *each* request, and when they do, it's primarily on the outgoing socket from the proxy to the HTTPS server; and often, but not necessarily, a second ECONNRESET occurs on the incoming socket to the proxy.