-
-
Notifications
You must be signed in to change notification settings - Fork 33.6k
Open
Labels
help wantedIssues that need assistance from volunteers or PRs that need help to proceed.Issues that need assistance from volunteers or PRs that need help to proceed.httpIssues or PRs related to the http subsystem.Issues or PRs related to the http subsystem.
Description
- 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, and the rest is an HTTP proxy which serves CONNECT requests and pipes them to an HTTPS server defined in the same script:
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 --proxytunnelwork 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
setImmediateorsetTimeoutaround the reply (with, I guess, any timeout value).process.nextTickdoesn'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.
gajus, iofjuupasli, dustin-H, ibc, fijimunkii and 15 more
Metadata
Metadata
Assignees
Labels
help wantedIssues that need assistance from volunteers or PRs that need help to proceed.Issues that need assistance from volunteers or PRs that need help to proceed.httpIssues or PRs related to the http subsystem.Issues or PRs related to the http subsystem.