diff --git a/.travis.yml b/.travis.yml index 805d3d5..5783ad7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,3 @@ -sudo: false - language: node_js node_js: @@ -8,6 +6,8 @@ node_js: - "6" - "7" - "8" + - "10" + - "12" install: - PATH="`npm bin`:`npm bin -g`:$PATH" diff --git a/proxy.js b/proxy.js index 38d7363..3cf7ca5 100644 --- a/proxy.js +++ b/proxy.js @@ -339,9 +339,7 @@ function onconnect (req, socket, head) { res.removeListener('finish', onfinish); res.writeHead(200, 'Connection established'); - - // HACK: force a flush of the HTTP header - res._send(''); + res.flushHeaders(); // relinquish control of the `socket` from the ServerResponse instance res.detachSocket(socket); @@ -351,6 +349,7 @@ function onconnect (req, socket, head) { res = null; socket.pipe(target); + target.once('unpipe', resume); target.pipe(socket); } @@ -416,6 +415,17 @@ function onconnect (req, socket, head) { }); } +/** + * Resumes a socket. + * + * @param {(net.Socket|tls.Socket)} socket The socket to resume + * @api private + */ + +function resume (socket) { + socket.resume(); +} + /** * Checks `Proxy-Authorization` request headers. Same logic applied to CONNECT * requests as well as regular HTTP requests. diff --git a/test/test.js b/test/test.js index ff919e3..b105276 100644 --- a/test/test.js +++ b/test/test.js @@ -108,6 +108,48 @@ describe('proxy', function () { }); }); + it('should resume the client socket when it is unpiped', function (done) { + server.once('request', function (req, res) { + res.end(); + }); + + var gotData = false; + var host = '127.0.0.1:' + serverPort; + var socket = net.connect({ port: proxyPort }); + + socket.on('connect', function () { + socket.write( + 'CONNECT ' + host + ' HTTP/1.1\r\n' + + 'Host: ' + host + '\r\n' + + '\r\n' + ); + }); + + socket.on('close', function () { + assert(gotData); + done(); + }); + + socket.setEncoding('utf8'); + socket.once('data', function (data) { + assert(0 == data.indexOf('HTTP/1.1 200 Connection established\r\n')); + + socket.write( + 'POST / HTTP/1.1\r\n' + + 'Host: ' + host + '\r\n' + + 'Connection: close\r\n' + + 'Transfer-Encoding: chunked\r\n' + + '\r\n' + ); + + socket.once('data', function (data) { + assert(0 == data.indexOf('HTTP/1.1 200 OK\r\n')); + gotData = true; + socket.write('10\r\n{ "foo": "bar",\r\n'); + }); + }); + }); + describe('authentication', function () { function clearAuth () {