From 8a37b799fb12a8de0f40d8fd377c15ae86f29dad Mon Sep 17 00:00:00 2001 From: TommyDew42 Date: Sat, 18 Jun 2022 21:47:58 +0800 Subject: [PATCH 01/20] add unix domain socket option --- source/core/options.ts | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/source/core/options.ts b/source/core/options.ts index 33073636d..f4fb25ffe 100644 --- a/source/core/options.ts +++ b/source/core/options.ts @@ -827,6 +827,7 @@ const defaultInternals: Options['_internals'] = { }, setHost: true, maxHeaderSize: undefined, + enableUnixSocket: false, }; const cloneInternals = (internals: typeof defaultInternals) => { @@ -1401,7 +1402,7 @@ export default class Options { this._internals.url = url; decodeURI(urlString); - if (url.protocol === 'unix:') { + if (this._internals.enableUnixSocket && url.protocol === 'unix:') { url.href = `http://unix${url.pathname}${url.search}`; } @@ -1427,7 +1428,7 @@ export default class Options { this._internals.searchParams = undefined; } - if (url.hostname === 'unix') { + if (this._internals.enableUnixSocket && url.hostname === 'unix') { const matches = /(?.+?):(?.+)/.exec(`${url.pathname}${url.search}`); if (matches?.groups) { @@ -2345,6 +2346,16 @@ export default class Options { this._internals.maxHeaderSize = value; } + get enableUnixSocket() { + return this._internals.enableUnixSocket; + } + + set enableUnixSocket(value: boolean) { + assert.boolean(value); + + this._internals.enableUnixSocket = value; + } + // eslint-disable-next-line @typescript-eslint/naming-convention toJSON() { return {...this._internals}; From ee75bab6dc9ea7e7f8eb2245b70c3e61cf112bec Mon Sep 17 00:00:00 2001 From: TommyDew42 Date: Sat, 18 Jun 2022 21:48:17 +0800 Subject: [PATCH 02/20] update tests for the unix doamin socket option --- test/redirects.ts | 23 ++++++++++++++++++++++- test/unix-socket.ts | 40 +++++++++++++++++++++++++++++++++------- 2 files changed, 55 insertions(+), 8 deletions(-) diff --git a/test/redirects.ts b/test/redirects.ts index 1b6d4324b..d255cd662 100644 --- a/test/redirects.ts +++ b/test/redirects.ts @@ -42,10 +42,31 @@ const unixHostname: Handler = (_request, response) => { response.end(); }; -test('cannot redirect to unix protocol', withServer, async (t, server, got) => { +test('cannot redirect to unix protocol when unix socket is enabled', withServer, async (t, server, got) => { server.get('/protocol', unixProtocol); server.get('/hostname', unixHostname); + const gotUnixSocketEnabled = got.extend({enableUnixSocket: true}); + + t.assert(gotUnixSocketEnabled.defaults.options.enableUnixSocket); + + await t.throwsAsync(gotUnixSocketEnabled('protocol'), { + message: 'Cannot redirect to UNIX socket', + instanceOf: RequestError, + }); + + await t.throwsAsync(gotUnixSocketEnabled('hostname'), { + message: 'Cannot redirect to UNIX socket', + instanceOf: RequestError, + }); +}); + +test('cannot redirect to unix protocol when unix socket is not enabled', withServer, async (t, server, got) => { + server.get('/protocol', unixProtocol); + server.get('/hostname', unixHostname); + + t.assert(!got.defaults.options.enableUnixSocket); + await t.throwsAsync(got('protocol'), { message: 'Cannot redirect to UNIX socket', instanceOf: RequestError, diff --git a/test/unix-socket.ts b/test/unix-socket.ts index 059785ea7..53e2f14b6 100644 --- a/test/unix-socket.ts +++ b/test/unix-socket.ts @@ -5,6 +5,8 @@ import {Handler} from 'express'; import got from '../source/index.js'; import {withSocketServer} from './helpers/with-server.js'; +const gotUnixSocketEnabled = got.extend({enableUnixSocket: true}); + const okHandler: Handler = (_request, response) => { response.end('ok'); }; @@ -21,26 +23,26 @@ if (process.platform !== 'win32') { server.on('/', okHandler); const url = format('http://unix:%s:%s', server.socketPath, '/'); - t.is((await got(url)).body, 'ok'); + t.is((await gotUnixSocketEnabled(url)).body, 'ok'); }); test('protocol-less works', withSocketServer, async (t, server) => { server.on('/', okHandler); const url = format('unix:%s:%s', server.socketPath, '/'); - t.is((await got(url)).body, 'ok'); + t.is((await gotUnixSocketEnabled(url)).body, 'ok'); }); test('address with : works', withSocketServer, async (t, server) => { server.on('/foo:bar', okHandler); const url = format('unix:%s:%s', server.socketPath, '/foo:bar'); - t.is((await got(url)).body, 'ok'); + t.is((await gotUnixSocketEnabled(url)).body, 'ok'); }); test('throws on invalid URL', async t => { try { - await got('unix:', {retry: {limit: 0}}); + await gotUnixSocketEnabled('unix:', {retry: {limit: 0}}); } catch (error: any) { t.regex(error.code, /ENOTFOUND|EAI_AGAIN/); } @@ -50,7 +52,7 @@ if (process.platform !== 'win32') { server.on('/', okHandler); const url = format('unix:%s:%s', server.socketPath, '/'); - const instance = got.extend({prefixUrl: url}); + const instance = gotUnixSocketEnabled.extend({prefixUrl: url}); t.is((await instance('')).body, 'ok'); }); @@ -58,7 +60,7 @@ if (process.platform !== 'win32') { server.on('/?a=1', okHandler); const url = format('http://unix:%s:%s', server.socketPath, '/?a=1'); - t.is((await got(url)).body, 'ok'); + t.is((await gotUnixSocketEnabled(url)).body, 'ok'); }); test('redirects work', withSocketServer, async (t, server) => { @@ -66,6 +68,30 @@ if (process.platform !== 'win32') { server.on('/foo', okHandler); const url = format('http://unix:%s:%s', server.socketPath, '/'); - t.is((await got(url)).body, 'ok'); + t.is((await gotUnixSocketEnabled(url)).body, 'ok'); + }); + + test('unix: fails when unix socket is not enabled', async t => { + try { + await got('unix:'); + } catch (error: any) { + t.assert(error.code === 'ERR_UNSUPPORTED_PROTOCOL'); + return; + } + + // Fail if no error is thrown + t.fail(); + }); + + test('http://unix:/ fails when unix socket is not enabled', async t => { + try { + await got('http://unix:'); + } catch (error: any) { + t.assert(error.code === 'ENOTFOUND'); + return; + } + + // Fail if no error is thrown + t.fail(); }); } From e683e5b151c5f8e51d432615a69813e263a8840d Mon Sep 17 00:00:00 2001 From: TommyDew42 Date: Sun, 19 Jun 2022 02:02:45 +0800 Subject: [PATCH 03/20] add a log to debug the failure in unix os --- test/unix-socket.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/test/unix-socket.ts b/test/unix-socket.ts index 53e2f14b6..46a803ae0 100644 --- a/test/unix-socket.ts +++ b/test/unix-socket.ts @@ -87,6 +87,7 @@ if (process.platform !== 'win32') { try { await got('http://unix:'); } catch (error: any) { + t.log(error); t.assert(error.code === 'ENOTFOUND'); return; } From cc130644622171d9078451f5c41f50476ebd4f51 Mon Sep 17 00:00:00 2001 From: TommyDew42 Date: Sun, 19 Jun 2022 02:22:43 +0800 Subject: [PATCH 04/20] add a different error code to assert for unix os --- test/unix-socket.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/unix-socket.ts b/test/unix-socket.ts index 46a803ae0..d4d8bfd2a 100644 --- a/test/unix-socket.ts +++ b/test/unix-socket.ts @@ -87,8 +87,7 @@ if (process.platform !== 'win32') { try { await got('http://unix:'); } catch (error: any) { - t.log(error); - t.assert(error.code === 'ENOTFOUND'); + t.regex(error.code, /ENOTFOUND|EAI_AGAIN/); return; } From 1624cc07b8e0c3d4444f25a5564f4997f1333e83 Mon Sep 17 00:00:00 2001 From: TommyDew42 Date: Sun, 19 Jun 2022 21:26:26 +0800 Subject: [PATCH 05/20] update documentation for new option enableUnixSocket --- documentation/2-options.md | 22 ++++++++++++++++++++++ documentation/migration-guides/axios.md | 2 +- documentation/migration-guides/request.md | 2 +- documentation/tips.md | 17 +---------------- readme.md | 2 +- 5 files changed, 26 insertions(+), 19 deletions(-) diff --git a/documentation/2-options.md b/documentation/2-options.md index f5e10669a..15b0c539d 100644 --- a/documentation/2-options.md +++ b/documentation/2-options.md @@ -918,6 +918,28 @@ By default, requests will not use [method rewriting](https://datatracker.ietf.or For example, when sending a `POST` request and receiving a `302`, it will resend the body to the new location using the same HTTP method (`POST` in this case). To rewrite the request as `GET`, set this option to `true`. +### `enableUnixSocket` +**Type: `boolean`**\ +**Default: `false`** + +Set to `true` to enable unix socket domain. + +When it is enabled, requests can also be sent via [UNIX Domain Sockets](https://serverfault.com/questions/124517/what-is-the-difference-between-unix-sockets-and-tcp-ip-sockets).\ +Use the following URL scheme: `PROTOCOL://unix:SOCKET:PATH` + +- `PROTOCOL` - `http` or `https` +- `SOCKET` - Absolute path to a unix domain socket, for example: `/var/run/docker.sock` +- `PATH` - Request path, for example: `/v2/keys` + +```js +import got from 'got'; + +await got('http://unix:/var/run/docker.sock:/containers/json'); + +// Or without protocol (HTTP by default) +await got('unix:/var/run/docker.sock:/containers/json'); +``` + ## Methods ### `options.merge(other: Options | OptionsInit)` diff --git a/documentation/migration-guides/axios.md b/documentation/migration-guides/axios.md index f4a457291..54d21d9b4 100644 --- a/documentation/migration-guides/axios.md +++ b/documentation/migration-guides/axios.md @@ -24,7 +24,7 @@ We deeply care about readability, so we renamed these options: - `httpAgent` → [`agent.http`](../2-options.md#agent) - `httpsAgent` → [`agent.https`](../2-options.md#agent) -- `socketPath` → [`url`](../tips.md#unix) +- `socketPath` → [`url`](../2-options.md#enableunixsocket) - `responseEncoding` → [`encoding`](../2-options.md#encoding) - `auth.username` → [`username`](../2-options.md#username) - `auth.password` → [`password`](../2-options.md#password) diff --git a/documentation/migration-guides/request.md b/documentation/migration-guides/request.md index b34329424..2686d8020 100644 --- a/documentation/migration-guides/request.md +++ b/documentation/migration-guides/request.md @@ -46,7 +46,7 @@ These Got options are the same as with Request: - [`localAddress`](../2-options.md#localaddress) - [`headers`](../2-options.md#headers) - [`createConnection`](../2-options.md#createconnection) -- [UNIX sockets](../tips.md#unixsockets): `http://unix:SOCKET:PATH` +- [UNIX sockets](../2-options.md#enableunixsocket): `http://unix:SOCKET:PATH` The `time` option does not exist, assume [it's always true](../6-timeout.md). diff --git a/documentation/tips.md b/documentation/tips.md index 014a28d94..969c251d9 100644 --- a/documentation/tips.md +++ b/documentation/tips.md @@ -89,24 +89,9 @@ for await (const commitData of pagination) { } ``` - ### UNIX Domain Sockets -Requests can also be sent via [UNIX Domain Sockets](https://serverfault.com/questions/124517/what-is-the-difference-between-unix-sockets-and-tcp-ip-sockets).\ -Use the following URL scheme: `PROTOCOL://unix:SOCKET:PATH` - -- `PROTOCOL` - `http` or `https` -- `SOCKET` - Absolute path to a unix domain socket, for example: `/var/run/docker.sock` -- `PATH` - Request path, for example: `/v2/keys` - -```js -import got from 'got'; - -await got('http://unix:/var/run/docker.sock:/containers/json'); - -// Or without protocol (HTTP by default) -await got('unix:/var/run/docker.sock:/containers/json'); -``` +See option [enableUnixSocket](./2-options.md#enableunixsocket) for more. ### Testing diff --git a/readme.md b/readme.md index f06ccf3a5..7f835bc92 100644 --- a/readme.md +++ b/readme.md @@ -202,7 +202,7 @@ For advanced JSON usage, check out the [`parseJson`](documentation/2-options.md# - [x] [RFC compliant caching](documentation/cache.md) - [x] [Proxy support](documentation/tips.md#proxying) -- [x] [Unix Domain Sockets](documentation/tips.md#unix) +- [x] [Unix Domain Sockets](documentation/2-options.md#enableunixsocket) #### Integration From c80f185747e52182f2a2486d224756ed32146d4c Mon Sep 17 00:00:00 2001 From: TommyDew42 Date: Tue, 21 Jun 2022 00:27:39 +0800 Subject: [PATCH 06/20] update test description --- test/redirects.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/redirects.ts b/test/redirects.ts index d255cd662..85db40014 100644 --- a/test/redirects.ts +++ b/test/redirects.ts @@ -42,7 +42,7 @@ const unixHostname: Handler = (_request, response) => { response.end(); }; -test('cannot redirect to unix protocol when unix socket is enabled', withServer, async (t, server, got) => { +test('cannot redirect to UNIX protocol when UNIX socket is enabled', withServer, async (t, server, got) => { server.get('/protocol', unixProtocol); server.get('/hostname', unixHostname); @@ -61,7 +61,7 @@ test('cannot redirect to unix protocol when unix socket is enabled', withServer, }); }); -test('cannot redirect to unix protocol when unix socket is not enabled', withServer, async (t, server, got) => { +test('cannot redirect to UNIX protocol when UNIX socket is not enabled', withServer, async (t, server, got) => { server.get('/protocol', unixProtocol); server.get('/hostname', unixHostname); From 30aae382131c459f9cdc1a892cafe002f88ab797 Mon Sep 17 00:00:00 2001 From: TommyDew42 Date: Tue, 21 Jun 2022 00:27:50 +0800 Subject: [PATCH 07/20] improve documentation --- documentation/2-options.md | 9 ++++++--- documentation/tips.md | 2 +- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/documentation/2-options.md b/documentation/2-options.md index 15b0c539d..b26fb9eb8 100644 --- a/documentation/2-options.md +++ b/documentation/2-options.md @@ -919,10 +919,11 @@ By default, requests will not use [method rewriting](https://datatracker.ietf.or For example, when sending a `POST` request and receiving a `302`, it will resend the body to the new location using the same HTTP method (`POST` in this case). To rewrite the request as `GET`, set this option to `true`. ### `enableUnixSocket` + **Type: `boolean`**\ **Default: `false`** -Set to `true` to enable unix socket domain. +Enable it with care if you accept untrusted user input for the URL. When it is enabled, requests can also be sent via [UNIX Domain Sockets](https://serverfault.com/questions/124517/what-is-the-difference-between-unix-sockets-and-tcp-ip-sockets).\ Use the following URL scheme: `PROTOCOL://unix:SOCKET:PATH` @@ -934,10 +935,12 @@ Use the following URL scheme: `PROTOCOL://unix:SOCKET:PATH` ```js import got from 'got'; -await got('http://unix:/var/run/docker.sock:/containers/json'); +const gotUnixSocketEnabled = got.extend({enableUnixSocket: true}); + +await gotUnixSocketEnabled('http://unix:/var/run/docker.sock:/containers/json'); // Or without protocol (HTTP by default) -await got('unix:/var/run/docker.sock:/containers/json'); +await gotUnixSocketEnabled('unix:/var/run/docker.sock:/containers/json'); ``` ## Methods diff --git a/documentation/tips.md b/documentation/tips.md index 969c251d9..0eb4abcb0 100644 --- a/documentation/tips.md +++ b/documentation/tips.md @@ -91,7 +91,7 @@ for await (const commitData of pagination) { ### UNIX Domain Sockets -See option [enableUnixSocket](./2-options.md#enableunixsocket) for more. +See the [`enableUnixSocket` option](./2-options.md#enableunixsocket). ### Testing From e5c94824c1fbb49d8cca87716873a0334d771b51 Mon Sep 17 00:00:00 2001 From: TommyDew42 Date: Tue, 21 Jun 2022 00:30:27 +0800 Subject: [PATCH 08/20] add back the a tag in unix socket --- documentation/tips.md | 1 + 1 file changed, 1 insertion(+) diff --git a/documentation/tips.md b/documentation/tips.md index 0eb4abcb0..c64e77129 100644 --- a/documentation/tips.md +++ b/documentation/tips.md @@ -89,6 +89,7 @@ for await (const commitData of pagination) { } ``` + ### UNIX Domain Sockets See the [`enableUnixSocket` option](./2-options.md#enableunixsocket). From 7ac2d9cf8fbf17d27677434842a3585f16a81e49 Mon Sep 17 00:00:00 2001 From: TommyDew42 Date: Tue, 5 Jul 2022 01:05:27 +0800 Subject: [PATCH 09/20] use plural form of unix socket --- documentation/2-options.md | 8 ++++---- documentation/migration-guides/axios.md | 2 +- documentation/migration-guides/request.md | 2 +- documentation/tips.md | 2 +- readme.md | 2 +- source/core/options.ts | 14 +++++++------- test/redirects.ts | 14 +++++++------- test/unix-socket.ts | 20 ++++++++++---------- 8 files changed, 32 insertions(+), 32 deletions(-) diff --git a/documentation/2-options.md b/documentation/2-options.md index b26fb9eb8..08a836d2f 100644 --- a/documentation/2-options.md +++ b/documentation/2-options.md @@ -918,7 +918,7 @@ By default, requests will not use [method rewriting](https://datatracker.ietf.or For example, when sending a `POST` request and receiving a `302`, it will resend the body to the new location using the same HTTP method (`POST` in this case). To rewrite the request as `GET`, set this option to `true`. -### `enableUnixSocket` +### `enableUnixSockets` **Type: `boolean`**\ **Default: `false`** @@ -935,12 +935,12 @@ Use the following URL scheme: `PROTOCOL://unix:SOCKET:PATH` ```js import got from 'got'; -const gotUnixSocketEnabled = got.extend({enableUnixSocket: true}); +const gotUnixSocketsEnabled = got.extend({enableUnixSockets: true}); -await gotUnixSocketEnabled('http://unix:/var/run/docker.sock:/containers/json'); +await gotUnixSocketsEnabled('http://unix:/var/run/docker.sock:/containers/json'); // Or without protocol (HTTP by default) -await gotUnixSocketEnabled('unix:/var/run/docker.sock:/containers/json'); +await gotUnixSocketsEnabled('unix:/var/run/docker.sock:/containers/json'); ``` ## Methods diff --git a/documentation/migration-guides/axios.md b/documentation/migration-guides/axios.md index 54d21d9b4..a17f606df 100644 --- a/documentation/migration-guides/axios.md +++ b/documentation/migration-guides/axios.md @@ -24,7 +24,7 @@ We deeply care about readability, so we renamed these options: - `httpAgent` → [`agent.http`](../2-options.md#agent) - `httpsAgent` → [`agent.https`](../2-options.md#agent) -- `socketPath` → [`url`](../2-options.md#enableunixsocket) +- `socketPath` → [`url`](../2-options.md#enableunixsockets) - `responseEncoding` → [`encoding`](../2-options.md#encoding) - `auth.username` → [`username`](../2-options.md#username) - `auth.password` → [`password`](../2-options.md#password) diff --git a/documentation/migration-guides/request.md b/documentation/migration-guides/request.md index 2686d8020..b6e80bea6 100644 --- a/documentation/migration-guides/request.md +++ b/documentation/migration-guides/request.md @@ -46,7 +46,7 @@ These Got options are the same as with Request: - [`localAddress`](../2-options.md#localaddress) - [`headers`](../2-options.md#headers) - [`createConnection`](../2-options.md#createconnection) -- [UNIX sockets](../2-options.md#enableunixsocket): `http://unix:SOCKET:PATH` +- [UNIX sockets](../2-options.md#enableunixsockets): `http://unix:SOCKET:PATH` The `time` option does not exist, assume [it's always true](../6-timeout.md). diff --git a/documentation/tips.md b/documentation/tips.md index c64e77129..1058e4188 100644 --- a/documentation/tips.md +++ b/documentation/tips.md @@ -92,7 +92,7 @@ for await (const commitData of pagination) { ### UNIX Domain Sockets -See the [`enableUnixSocket` option](./2-options.md#enableunixsocket). +See the [`enableUnixSockets` option](./2-options.md#enableunixsockets). ### Testing diff --git a/readme.md b/readme.md index 7f835bc92..0af7a6724 100644 --- a/readme.md +++ b/readme.md @@ -202,7 +202,7 @@ For advanced JSON usage, check out the [`parseJson`](documentation/2-options.md# - [x] [RFC compliant caching](documentation/cache.md) - [x] [Proxy support](documentation/tips.md#proxying) -- [x] [Unix Domain Sockets](documentation/2-options.md#enableunixsocket) +- [x] [Unix Domain Sockets](documentation/2-options.md#enableunixsockets) #### Integration diff --git a/source/core/options.ts b/source/core/options.ts index f4fb25ffe..16646f6f2 100644 --- a/source/core/options.ts +++ b/source/core/options.ts @@ -827,7 +827,7 @@ const defaultInternals: Options['_internals'] = { }, setHost: true, maxHeaderSize: undefined, - enableUnixSocket: false, + enableUnixSockets: false, }; const cloneInternals = (internals: typeof defaultInternals) => { @@ -1402,7 +1402,7 @@ export default class Options { this._internals.url = url; decodeURI(urlString); - if (this._internals.enableUnixSocket && url.protocol === 'unix:') { + if (this._internals.enableUnixSockets && url.protocol === 'unix:') { url.href = `http://unix${url.pathname}${url.search}`; } @@ -1428,7 +1428,7 @@ export default class Options { this._internals.searchParams = undefined; } - if (this._internals.enableUnixSocket && url.hostname === 'unix') { + if (this._internals.enableUnixSockets && url.hostname === 'unix') { const matches = /(?.+?):(?.+)/.exec(`${url.pathname}${url.search}`); if (matches?.groups) { @@ -2346,14 +2346,14 @@ export default class Options { this._internals.maxHeaderSize = value; } - get enableUnixSocket() { - return this._internals.enableUnixSocket; + get enableUnixSockets() { + return this._internals.enableUnixSockets; } - set enableUnixSocket(value: boolean) { + set enableUnixSockets(value: boolean) { assert.boolean(value); - this._internals.enableUnixSocket = value; + this._internals.enableUnixSockets = value; } // eslint-disable-next-line @typescript-eslint/naming-convention diff --git a/test/redirects.ts b/test/redirects.ts index 85db40014..e1384fb36 100644 --- a/test/redirects.ts +++ b/test/redirects.ts @@ -42,30 +42,30 @@ const unixHostname: Handler = (_request, response) => { response.end(); }; -test('cannot redirect to UNIX protocol when UNIX socket is enabled', withServer, async (t, server, got) => { +test('cannot redirect to UNIX protocol when UNIX sockets are enabled', withServer, async (t, server, got) => { server.get('/protocol', unixProtocol); server.get('/hostname', unixHostname); - const gotUnixSocketEnabled = got.extend({enableUnixSocket: true}); + const gotUnixSocketsEnabled = got.extend({enableUnixSockets: true}); - t.assert(gotUnixSocketEnabled.defaults.options.enableUnixSocket); + t.assert(gotUnixSocketsEnabled.defaults.options.enableUnixSockets); - await t.throwsAsync(gotUnixSocketEnabled('protocol'), { + await t.throwsAsync(gotUnixSocketsEnabled('protocol'), { message: 'Cannot redirect to UNIX socket', instanceOf: RequestError, }); - await t.throwsAsync(gotUnixSocketEnabled('hostname'), { + await t.throwsAsync(gotUnixSocketsEnabled('hostname'), { message: 'Cannot redirect to UNIX socket', instanceOf: RequestError, }); }); -test('cannot redirect to UNIX protocol when UNIX socket is not enabled', withServer, async (t, server, got) => { +test('cannot redirect to UNIX protocol when UNIX sockets are not enabled', withServer, async (t, server, got) => { server.get('/protocol', unixProtocol); server.get('/hostname', unixHostname); - t.assert(!got.defaults.options.enableUnixSocket); + t.assert(!got.defaults.options.enableUnixSockets); await t.throwsAsync(got('protocol'), { message: 'Cannot redirect to UNIX socket', diff --git a/test/unix-socket.ts b/test/unix-socket.ts index d4d8bfd2a..cbea61c97 100644 --- a/test/unix-socket.ts +++ b/test/unix-socket.ts @@ -5,7 +5,7 @@ import {Handler} from 'express'; import got from '../source/index.js'; import {withSocketServer} from './helpers/with-server.js'; -const gotUnixSocketEnabled = got.extend({enableUnixSocket: true}); +const gotUnixSocketsEnabled = got.extend({enableUnixSockets: true}); const okHandler: Handler = (_request, response) => { response.end('ok'); @@ -23,26 +23,26 @@ if (process.platform !== 'win32') { server.on('/', okHandler); const url = format('http://unix:%s:%s', server.socketPath, '/'); - t.is((await gotUnixSocketEnabled(url)).body, 'ok'); + t.is((await gotUnixSocketsEnabled(url)).body, 'ok'); }); test('protocol-less works', withSocketServer, async (t, server) => { server.on('/', okHandler); const url = format('unix:%s:%s', server.socketPath, '/'); - t.is((await gotUnixSocketEnabled(url)).body, 'ok'); + t.is((await gotUnixSocketsEnabled(url)).body, 'ok'); }); test('address with : works', withSocketServer, async (t, server) => { server.on('/foo:bar', okHandler); const url = format('unix:%s:%s', server.socketPath, '/foo:bar'); - t.is((await gotUnixSocketEnabled(url)).body, 'ok'); + t.is((await gotUnixSocketsEnabled(url)).body, 'ok'); }); test('throws on invalid URL', async t => { try { - await gotUnixSocketEnabled('unix:', {retry: {limit: 0}}); + await gotUnixSocketsEnabled('unix:', {retry: {limit: 0}}); } catch (error: any) { t.regex(error.code, /ENOTFOUND|EAI_AGAIN/); } @@ -52,7 +52,7 @@ if (process.platform !== 'win32') { server.on('/', okHandler); const url = format('unix:%s:%s', server.socketPath, '/'); - const instance = gotUnixSocketEnabled.extend({prefixUrl: url}); + const instance = gotUnixSocketsEnabled.extend({prefixUrl: url}); t.is((await instance('')).body, 'ok'); }); @@ -60,7 +60,7 @@ if (process.platform !== 'win32') { server.on('/?a=1', okHandler); const url = format('http://unix:%s:%s', server.socketPath, '/?a=1'); - t.is((await gotUnixSocketEnabled(url)).body, 'ok'); + t.is((await gotUnixSocketsEnabled(url)).body, 'ok'); }); test('redirects work', withSocketServer, async (t, server) => { @@ -68,10 +68,10 @@ if (process.platform !== 'win32') { server.on('/foo', okHandler); const url = format('http://unix:%s:%s', server.socketPath, '/'); - t.is((await gotUnixSocketEnabled(url)).body, 'ok'); + t.is((await gotUnixSocketsEnabled(url)).body, 'ok'); }); - test('unix: fails when unix socket is not enabled', async t => { + test('unix: fails when unix sockets are not enabled', async t => { try { await got('unix:'); } catch (error: any) { @@ -83,7 +83,7 @@ if (process.platform !== 'win32') { t.fail(); }); - test('http://unix:/ fails when unix socket is not enabled', async t => { + test('http://unix:/ fails when unix sockets are not enabled', async t => { try { await got('http://unix:'); } catch (error: any) { From ade3aa0c9b02662fa7e2bde51fdf598fad678cfe Mon Sep 17 00:00:00 2001 From: TommyDew42 Date: Tue, 5 Jul 2022 01:06:19 +0800 Subject: [PATCH 10/20] add enableUnixSockets option check to ensure it is indeed not enabled --- test/unix-socket.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/unix-socket.ts b/test/unix-socket.ts index cbea61c97..906d7d66b 100644 --- a/test/unix-socket.ts +++ b/test/unix-socket.ts @@ -73,6 +73,7 @@ if (process.platform !== 'win32') { test('unix: fails when unix sockets are not enabled', async t => { try { + t.assert(!got.defaults.options.enableUnixSockets); await got('unix:'); } catch (error: any) { t.assert(error.code === 'ERR_UNSUPPORTED_PROTOCOL'); @@ -85,6 +86,7 @@ if (process.platform !== 'win32') { test('http://unix:/ fails when unix sockets are not enabled', async t => { try { + t.assert(!got.defaults.options.enableUnixSockets); await got('http://unix:'); } catch (error: any) { t.regex(error.code, /ENOTFOUND|EAI_AGAIN/); From 4abb9310f73bda46958ce59b07c9c84352b068f1 Mon Sep 17 00:00:00 2001 From: TommyDew42 Date: Sat, 9 Jul 2022 00:15:17 +0800 Subject: [PATCH 11/20] improve enableUnixSockets documentation --- documentation/2-options.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/documentation/2-options.md b/documentation/2-options.md index 08a836d2f..fa2e0d322 100644 --- a/documentation/2-options.md +++ b/documentation/2-options.md @@ -921,15 +921,16 @@ For example, when sending a `POST` request and receiving a `302`, it will resend ### `enableUnixSockets` **Type: `boolean`**\ -**Default: `false`** - -Enable it with care if you accept untrusted user input for the URL. +**Default: `true`** When it is enabled, requests can also be sent via [UNIX Domain Sockets](https://serverfault.com/questions/124517/what-is-the-difference-between-unix-sockets-and-tcp-ip-sockets).\ Use the following URL scheme: `PROTOCOL://unix:SOCKET:PATH` +Enable it with care if you accept untrusted user input for the URL. +And make sure you do your own URL sanitizing. + - `PROTOCOL` - `http` or `https` -- `SOCKET` - Absolute path to a unix domain socket, for example: `/var/run/docker.sock` +- `SOCKET` - Absolute path to a UNIX domain socket, for example: `/var/run/docker.sock` - `PATH` - Request path, for example: `/v2/keys` ```js From bd8adb12965b11a11a49b3de8ba0c6afb48ce190 Mon Sep 17 00:00:00 2001 From: TommyDew42 Date: Sat, 9 Jul 2022 00:17:25 +0800 Subject: [PATCH 12/20] set enableUnixSockets default to be true --- source/core/options.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/core/options.ts b/source/core/options.ts index 16646f6f2..a8e764560 100644 --- a/source/core/options.ts +++ b/source/core/options.ts @@ -827,7 +827,7 @@ const defaultInternals: Options['_internals'] = { }, setHost: true, maxHeaderSize: undefined, - enableUnixSockets: false, + enableUnixSockets: true, }; const cloneInternals = (internals: typeof defaultInternals) => { From 46791f058997072c2a620ecbc4bf08b7b2df9886 Mon Sep 17 00:00:00 2001 From: TommyDew42 Date: Sat, 9 Jul 2022 00:49:12 +0800 Subject: [PATCH 13/20] fix and improve tests --- test/redirects.ts | 16 ++++++++-------- test/unix-socket.ts | 42 +++++++++++++++++++++--------------------- 2 files changed, 29 insertions(+), 29 deletions(-) diff --git a/test/redirects.ts b/test/redirects.ts index e1384fb36..927221aca 100644 --- a/test/redirects.ts +++ b/test/redirects.ts @@ -46,16 +46,14 @@ test('cannot redirect to UNIX protocol when UNIX sockets are enabled', withServe server.get('/protocol', unixProtocol); server.get('/hostname', unixHostname); - const gotUnixSocketsEnabled = got.extend({enableUnixSockets: true}); + t.true(got.defaults.options.enableUnixSockets); - t.assert(gotUnixSocketsEnabled.defaults.options.enableUnixSockets); - - await t.throwsAsync(gotUnixSocketsEnabled('protocol'), { + await t.throwsAsync(got('protocol'), { message: 'Cannot redirect to UNIX socket', instanceOf: RequestError, }); - await t.throwsAsync(gotUnixSocketsEnabled('hostname'), { + await t.throwsAsync(got('hostname'), { message: 'Cannot redirect to UNIX socket', instanceOf: RequestError, }); @@ -65,14 +63,16 @@ test('cannot redirect to UNIX protocol when UNIX sockets are not enabled', withS server.get('/protocol', unixProtocol); server.get('/hostname', unixHostname); - t.assert(!got.defaults.options.enableUnixSockets); + const gotUnixSocketsDisabled = got.extend({enableUnixSockets: false}); - await t.throwsAsync(got('protocol'), { + t.false(gotUnixSocketsDisabled.defaults.options.enableUnixSockets); + + await t.throwsAsync(gotUnixSocketsDisabled('protocol'), { message: 'Cannot redirect to UNIX socket', instanceOf: RequestError, }); - await t.throwsAsync(got('hostname'), { + await t.throwsAsync(gotUnixSocketsDisabled('hostname'), { message: 'Cannot redirect to UNIX socket', instanceOf: RequestError, }); diff --git a/test/unix-socket.ts b/test/unix-socket.ts index 906d7d66b..f01e65250 100644 --- a/test/unix-socket.ts +++ b/test/unix-socket.ts @@ -5,8 +5,6 @@ import {Handler} from 'express'; import got from '../source/index.js'; import {withSocketServer} from './helpers/with-server.js'; -const gotUnixSocketsEnabled = got.extend({enableUnixSockets: true}); - const okHandler: Handler = (_request, response) => { response.end('ok'); }; @@ -23,26 +21,26 @@ if (process.platform !== 'win32') { server.on('/', okHandler); const url = format('http://unix:%s:%s', server.socketPath, '/'); - t.is((await gotUnixSocketsEnabled(url)).body, 'ok'); + t.is((await got(url)).body, 'ok'); }); test('protocol-less works', withSocketServer, async (t, server) => { server.on('/', okHandler); const url = format('unix:%s:%s', server.socketPath, '/'); - t.is((await gotUnixSocketsEnabled(url)).body, 'ok'); + t.is((await got(url)).body, 'ok'); }); test('address with : works', withSocketServer, async (t, server) => { server.on('/foo:bar', okHandler); const url = format('unix:%s:%s', server.socketPath, '/foo:bar'); - t.is((await gotUnixSocketsEnabled(url)).body, 'ok'); + t.is((await got(url)).body, 'ok'); }); test('throws on invalid URL', async t => { try { - await gotUnixSocketsEnabled('unix:', {retry: {limit: 0}}); + await got('unix:', {retry: {limit: 0}}); } catch (error: any) { t.regex(error.code, /ENOTFOUND|EAI_AGAIN/); } @@ -52,7 +50,7 @@ if (process.platform !== 'win32') { server.on('/', okHandler); const url = format('unix:%s:%s', server.socketPath, '/'); - const instance = gotUnixSocketsEnabled.extend({prefixUrl: url}); + const instance = got.extend({prefixUrl: url}); t.is((await instance('')).body, 'ok'); }); @@ -60,7 +58,7 @@ if (process.platform !== 'win32') { server.on('/?a=1', okHandler); const url = format('http://unix:%s:%s', server.socketPath, '/?a=1'); - t.is((await gotUnixSocketsEnabled(url)).body, 'ok'); + t.is((await got(url)).body, 'ok'); }); test('redirects work', withSocketServer, async (t, server) => { @@ -68,25 +66,27 @@ if (process.platform !== 'win32') { server.on('/foo', okHandler); const url = format('http://unix:%s:%s', server.socketPath, '/'); - t.is((await gotUnixSocketsEnabled(url)).body, 'ok'); + t.is((await got(url)).body, 'ok'); }); - test('unix: fails when unix sockets are not enabled', async t => { - try { - t.assert(!got.defaults.options.enableUnixSockets); - await got('unix:'); - } catch (error: any) { - t.assert(error.code === 'ERR_UNSUPPORTED_PROTOCOL'); - return; - } + test('`unix:` fails when UNIX sockets are not enabled', async t => { + const gotUnixSocketsDisabled = got.extend({enableUnixSockets: false}); - // Fail if no error is thrown - t.fail(); + t.false(gotUnixSocketsDisabled.defaults.options.enableUnixSockets); + await t.throwsAsync( + gotUnixSocketsDisabled('unix:'), + { + code: 'ERR_UNSUPPORTED_PROTOCOL', + }, + ); }); - test('http://unix:/ fails when unix sockets are not enabled', async t => { + test('`http://unix:/` fails when UNIX sockets are not enabled', async t => { + const gotUnixSocketsDisabled = got.extend({enableUnixSockets: false}); + + t.false(gotUnixSocketsDisabled.defaults.options.enableUnixSockets); + try { - t.assert(!got.defaults.options.enableUnixSockets); await got('http://unix:'); } catch (error: any) { t.regex(error.code, /ENOTFOUND|EAI_AGAIN/); From 4d7069cb9e5aa512a8281493c6fb68a02edaf5c4 Mon Sep 17 00:00:00 2001 From: TommyDew42 Date: Sat, 9 Jul 2022 00:57:06 +0800 Subject: [PATCH 14/20] update the example and improve documentation --- documentation/2-options.md | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/documentation/2-options.md b/documentation/2-options.md index fa2e0d322..68c213791 100644 --- a/documentation/2-options.md +++ b/documentation/2-options.md @@ -926,8 +926,7 @@ For example, when sending a `POST` request and receiving a `302`, it will resend When it is enabled, requests can also be sent via [UNIX Domain Sockets](https://serverfault.com/questions/124517/what-is-the-difference-between-unix-sockets-and-tcp-ip-sockets).\ Use the following URL scheme: `PROTOCOL://unix:SOCKET:PATH` -Enable it with care if you accept untrusted user input for the URL. -And make sure you do your own URL sanitizing. +By default it is enabled, so make sure you do your own URL sanitizing if you accept untrusted user input for the URL. - `PROTOCOL` - `http` or `https` - `SOCKET` - Absolute path to a UNIX domain socket, for example: `/var/run/docker.sock` @@ -936,12 +935,16 @@ And make sure you do your own URL sanitizing. ```js import got from 'got'; -const gotUnixSocketsEnabled = got.extend({enableUnixSockets: true}); - -await gotUnixSocketsEnabled('http://unix:/var/run/docker.sock:/containers/json'); +await got('http://unix:/var/run/docker.sock:/containers/json'); // Or without protocol (HTTP by default) -await gotUnixSocketsEnabled('unix:/var/run/docker.sock:/containers/json'); +await got('unix:/var/run/docker.sock:/containers/json'); + +// Disable Unix sockets +const gotUnixSocketsDisabled = got.extend({enableUnixSockets: false}); + +// Error! +gotUnixSocketsDisabled('http://unix:/var/run/docker.sock:/containers/json') ``` ## Methods From afd1aa08ed38d84b76aa0f2fdcddd12d74e2057d Mon Sep 17 00:00:00 2001 From: TommyDew42 Date: Sat, 9 Jul 2022 13:00:36 +0800 Subject: [PATCH 15/20] Make reminder as a note --- documentation/2-options.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/documentation/2-options.md b/documentation/2-options.md index 68c213791..bec554867 100644 --- a/documentation/2-options.md +++ b/documentation/2-options.md @@ -926,8 +926,6 @@ For example, when sending a `POST` request and receiving a `302`, it will resend When it is enabled, requests can also be sent via [UNIX Domain Sockets](https://serverfault.com/questions/124517/what-is-the-difference-between-unix-sockets-and-tcp-ip-sockets).\ Use the following URL scheme: `PROTOCOL://unix:SOCKET:PATH` -By default it is enabled, so make sure you do your own URL sanitizing if you accept untrusted user input for the URL. - - `PROTOCOL` - `http` or `https` - `SOCKET` - Absolute path to a UNIX domain socket, for example: `/var/run/docker.sock` - `PATH` - Request path, for example: `/v2/keys` @@ -947,6 +945,10 @@ const gotUnixSocketsDisabled = got.extend({enableUnixSockets: false}); gotUnixSocketsDisabled('http://unix:/var/run/docker.sock:/containers/json') ``` +#### **Note:** +> - The option is enabled by default. +> - Make sure you do your own URL sanitizing if you accept untrusted user input for the URL. + ## Methods ### `options.merge(other: Options | OptionsInit)` From 91df1f35349fe21a9067d63682d8f7f1da042621 Mon Sep 17 00:00:00 2001 From: TommyDew42 Date: Sat, 9 Jul 2022 13:08:59 +0800 Subject: [PATCH 16/20] use error returned from throwsAsync --- test/unix-socket.ts | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/test/unix-socket.ts b/test/unix-socket.ts index f01e65250..f564b5b35 100644 --- a/test/unix-socket.ts +++ b/test/unix-socket.ts @@ -86,14 +86,7 @@ if (process.platform !== 'win32') { t.false(gotUnixSocketsDisabled.defaults.options.enableUnixSockets); - try { - await got('http://unix:'); - } catch (error: any) { - t.regex(error.code, /ENOTFOUND|EAI_AGAIN/); - return; - } - - // Fail if no error is thrown - t.fail(); + const error = await t.throwsAsync(got('http://unix:')); + t.regex(error.code, /ENOTFOUND|EAI_AGAIN/); }); } From 0331eee112dbc65da2be0c6260a6c4a221f1abe8 Mon Sep 17 00:00:00 2001 From: TommyDew42 Date: Sat, 9 Jul 2022 13:23:57 +0800 Subject: [PATCH 17/20] throw custom error when unix sockets are in use but the option is not enabled --- source/core/options.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/source/core/options.ts b/source/core/options.ts index a8e764560..9fb461c50 100644 --- a/source/core/options.ts +++ b/source/core/options.ts @@ -1402,7 +1402,7 @@ export default class Options { this._internals.url = url; decodeURI(urlString); - if (this._internals.enableUnixSockets && url.protocol === 'unix:') { + if (url.protocol === 'unix:') { url.href = `http://unix${url.pathname}${url.search}`; } @@ -1428,7 +1428,11 @@ export default class Options { this._internals.searchParams = undefined; } - if (this._internals.enableUnixSockets && url.hostname === 'unix') { + if (url.hostname === 'unix') { + if (!this._internals.enableUnixSockets) { + throw new Error('Using UNIX domain sockets but option `enableUnixSockets` is not enabled'); + } + const matches = /(?.+?):(?.+)/.exec(`${url.pathname}${url.search}`); if (matches?.groups) { From a311cabc629f46c675c8dee3dcd12ad4003b3317 Mon Sep 17 00:00:00 2001 From: TommyDew42 Date: Sat, 9 Jul 2022 13:24:08 +0800 Subject: [PATCH 18/20] update tests for the custom error --- test/unix-socket.ts | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/test/unix-socket.ts b/test/unix-socket.ts index f564b5b35..4523ec76f 100644 --- a/test/unix-socket.ts +++ b/test/unix-socket.ts @@ -76,7 +76,7 @@ if (process.platform !== 'win32') { await t.throwsAsync( gotUnixSocketsDisabled('unix:'), { - code: 'ERR_UNSUPPORTED_PROTOCOL', + message: 'Using UNIX domain sockets but option `enableUnixSockets` is not enabled', }, ); }); @@ -86,7 +86,11 @@ if (process.platform !== 'win32') { t.false(gotUnixSocketsDisabled.defaults.options.enableUnixSockets); - const error = await t.throwsAsync(got('http://unix:')); - t.regex(error.code, /ENOTFOUND|EAI_AGAIN/); + await t.throwsAsync( + gotUnixSocketsDisabled('http://unix:'), + { + message: 'Using UNIX domain sockets but option `enableUnixSockets` is not enabled', + }, + ); }); } From f07db64a0b39d96973229de86979fc06fdc09b20 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Wed, 20 Jul 2022 14:51:37 +0200 Subject: [PATCH 19/20] Update 2-options.md --- documentation/2-options.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/documentation/2-options.md b/documentation/2-options.md index bec554867..fa3eac5a7 100644 --- a/documentation/2-options.md +++ b/documentation/2-options.md @@ -923,7 +923,11 @@ For example, when sending a `POST` request and receiving a `302`, it will resend **Type: `boolean`**\ **Default: `true`** -When it is enabled, requests can also be sent via [UNIX Domain Sockets](https://serverfault.com/questions/124517/what-is-the-difference-between-unix-sockets-and-tcp-ip-sockets).\ +When enabled, requests can also be sent via [UNIX Domain Sockets](https://serverfault.com/questions/124517/what-is-the-difference-between-unix-sockets-and-tcp-ip-sockets). + +> **Warning** +> Make sure you do your own URL sanitizing if you accept untrusted user input for the URL. + Use the following URL scheme: `PROTOCOL://unix:SOCKET:PATH` - `PROTOCOL` - `http` or `https` @@ -945,10 +949,6 @@ const gotUnixSocketsDisabled = got.extend({enableUnixSockets: false}); gotUnixSocketsDisabled('http://unix:/var/run/docker.sock:/containers/json') ``` -#### **Note:** -> - The option is enabled by default. -> - Make sure you do your own URL sanitizing if you accept untrusted user input for the URL. - ## Methods ### `options.merge(other: Options | OptionsInit)` From 43ffebf081c73e545e935d005b72ec4d743db5f2 Mon Sep 17 00:00:00 2001 From: Szymon Marczak <36894700+szmarczak@users.noreply.github.com> Date: Thu, 21 Jul 2022 17:49:45 +0200 Subject: [PATCH 20/20] Update 2-options.md --- documentation/2-options.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/documentation/2-options.md b/documentation/2-options.md index fa3eac5a7..e7385a265 100644 --- a/documentation/2-options.md +++ b/documentation/2-options.md @@ -923,8 +923,8 @@ For example, when sending a `POST` request and receiving a `302`, it will resend **Type: `boolean`**\ **Default: `true`** -When enabled, requests can also be sent via [UNIX Domain Sockets](https://serverfault.com/questions/124517/what-is-the-difference-between-unix-sockets-and-tcp-ip-sockets). - +When enabled, requests can also be sent via [UNIX Domain Sockets](https://serverfault.com/questions/124517/what-is-the-difference-between-unix-sockets-and-tcp-ip-sockets). Please note that in the upcoming major release (Got v13) this default will be changed to `false` for security reasons. + > **Warning** > Make sure you do your own URL sanitizing if you accept untrusted user input for the URL. @@ -937,16 +937,16 @@ Use the following URL scheme: `PROTOCOL://unix:SOCKET:PATH` ```js import got from 'got'; -await got('http://unix:/var/run/docker.sock:/containers/json'); +await got('http://unix:/var/run/docker.sock:/containers/json', {enableUnixSockets: true}); // Or without protocol (HTTP by default) -await got('unix:/var/run/docker.sock:/containers/json'); +await got('unix:/var/run/docker.sock:/containers/json', {enableUnixSockets: true}); // Disable Unix sockets const gotUnixSocketsDisabled = got.extend({enableUnixSockets: false}); -// Error! -gotUnixSocketsDisabled('http://unix:/var/run/docker.sock:/containers/json') +// RequestError: Using UNIX domain sockets but option `enableUnixSockets` is not enabled +await gotUnixSocketsDisabled('http://unix:/var/run/docker.sock:/containers/json'); ``` ## Methods