diff --git a/src/node/index.js b/src/node/index.js index c21231ad..b5f45458 100644 --- a/src/node/index.js +++ b/src/node/index.js @@ -709,6 +709,16 @@ Request.prototype.request = function () { // get the protocol protocol = `${protocol.split('+')[0]}:`; + if (!url.hostname) { + // the socket path wasn't percent-encoded, so the URL parser folded it + // into the pathname and left us with nothing to connect to. Bail out + // here instead of silently falling back to a plain host request. + this._unixSocketError = new Error( + 'Invalid unix socket URL. A unix socket path must be percent-encoded (replace "/" with "%2F"), e.g. http+unix://%2Ftmp%2Fmy.sock/path' + ); + return; + } + // get the socket path options.socketPath = url.hostname.replace(/%2F/g, '/'); url.host = ''; @@ -985,6 +995,8 @@ Request.prototype._end = function () { new Error('The request has been aborted even before .end() was called') ); + if (this._unixSocketError) return this.callback(this._unixSocketError); + let data = this._data; const { req } = this; const { method } = this; diff --git a/test/node/unix-sockets.js b/test/node/unix-sockets.js index a443079a..8eb4bd15 100644 --- a/test/node/unix-sockets.js +++ b/test/node/unix-sockets.js @@ -72,6 +72,25 @@ describe('[unix-sockets] http', () => { }); }); +describe('[unix-sockets] invalid path', () => { + if (process.platform === 'win32') { + return; + } + + it('rejects with a clear error instead of hitting the wrong host', (done) => { + // the socket path here has literal slashes instead of being + // percent-encoded, so the URL parser can't tell it apart from a path + request + .get(`http+unix://${httpSockPath}/request/path`) + .end((error, res) => { + assert(error); + assert(/percent-encoded/.test(error.message)); + assert.strictEqual(res, undefined); + done(); + }); + }); +}); + describe('[unix-sockets] https', () => { if (process.platform === 'win32') { return;