Skip to content

Commit

Permalink
Add enableUnixSockets option (#2062)
Browse files Browse the repository at this point in the history
Co-authored-by: Sindre Sorhus <sindresorhus@gmail.com>
Co-authored-by: Szymon Marczak <36894700+szmarczak@users.noreply.github.com>
  • Loading branch information
3 people authored Jul 21, 2022
1 parent d4c2913 commit 461b3d4
Show file tree
Hide file tree
Showing 8 changed files with 97 additions and 19 deletions.
31 changes: 31 additions & 0 deletions documentation/2-options.md
Original file line number Diff line number Diff line change
Expand Up @@ -918,6 +918,37 @@ 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`.

### `enableUnixSockets`

**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). 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.
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', {enableUnixSockets: true});

// Or without protocol (HTTP by default)
await got('unix:/var/run/docker.sock:/containers/json', {enableUnixSockets: true});

// Disable Unix sockets
const gotUnixSocketsDisabled = got.extend({enableUnixSockets: false});

// RequestError: Using UNIX domain sockets but option `enableUnixSockets` is not enabled
await gotUnixSocketsDisabled('http://unix:/var/run/docker.sock:/containers/json');
```

## Methods

### `options.merge(other: Options | OptionsInit)`
Expand Down
2 changes: 1 addition & 1 deletion documentation/migration-guides/axios.md
Original file line number Diff line number Diff line change
Expand Up @@ -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#enableunixsockets)
- `responseEncoding`[`encoding`](../2-options.md#encoding)
- `auth.username`[`username`](../2-options.md#username)
- `auth.password`[`password`](../2-options.md#password)
Expand Down
2 changes: 1 addition & 1 deletion documentation/migration-guides/request.md
Original file line number Diff line number Diff line change
Expand Up @@ -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#enableunixsockets): `http://unix:SOCKET:PATH`

The `time` option does not exist, assume [it's always true](../6-timeout.md).

Expand Down
16 changes: 1 addition & 15 deletions documentation/tips.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,21 +92,7 @@ for await (const commitData of pagination) {
<a name="unix"></a>
### 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 the [`enableUnixSockets` option](./2-options.md#enableunixsockets).

### Testing

Expand Down
2 changes: 1 addition & 1 deletion readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -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#enableunixsockets)

#### Integration

Expand Down
15 changes: 15 additions & 0 deletions source/core/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -827,6 +827,7 @@ const defaultInternals: Options['_internals'] = {
},
setHost: true,
maxHeaderSize: undefined,
enableUnixSockets: true,
};

const cloneInternals = (internals: typeof defaultInternals) => {
Expand Down Expand Up @@ -1428,6 +1429,10 @@ export default class Options {
}

if (url.hostname === 'unix') {
if (!this._internals.enableUnixSockets) {
throw new Error('Using UNIX domain sockets but option `enableUnixSockets` is not enabled');
}

const matches = /(?<socketPath>.+?):(?<path>.+)/.exec(`${url.pathname}${url.search}`);

if (matches?.groups) {
Expand Down Expand Up @@ -2345,6 +2350,16 @@ export default class Options {
this._internals.maxHeaderSize = value;
}

get enableUnixSockets() {
return this._internals.enableUnixSockets;
}

set enableUnixSockets(value: boolean) {
assert.boolean(value);

this._internals.enableUnixSockets = value;
}

// eslint-disable-next-line @typescript-eslint/naming-convention
toJSON() {
return {...this._internals};
Expand Down
23 changes: 22 additions & 1 deletion test/redirects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,12 @@ 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 sockets are enabled', withServer, async (t, server, got) => {
server.get('/protocol', unixProtocol);
server.get('/hostname', unixHostname);

t.true(got.defaults.options.enableUnixSockets);

await t.throwsAsync(got('protocol'), {
message: 'Cannot redirect to UNIX socket',
instanceOf: RequestError,
Expand All @@ -57,6 +59,25 @@ test('cannot redirect to unix protocol', 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);

const gotUnixSocketsDisabled = got.extend({enableUnixSockets: false});

t.false(gotUnixSocketsDisabled.defaults.options.enableUnixSockets);

await t.throwsAsync(gotUnixSocketsDisabled('protocol'), {
message: 'Cannot redirect to UNIX socket',
instanceOf: RequestError,
});

await t.throwsAsync(gotUnixSocketsDisabled('hostname'), {
message: 'Cannot redirect to UNIX socket',
instanceOf: RequestError,
});
});

test('follows redirect', withServer, async (t, server, got) => {
server.get('/', reachedHandler);
server.get('/finite', finiteHandler);
Expand Down
25 changes: 25 additions & 0 deletions test/unix-socket.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,4 +68,29 @@ if (process.platform !== 'win32') {
const url = format('http://unix:%s:%s', server.socketPath, '/');
t.is((await got(url)).body, 'ok');
});

test('`unix:` fails when UNIX sockets are not enabled', async t => {
const gotUnixSocketsDisabled = got.extend({enableUnixSockets: false});

t.false(gotUnixSocketsDisabled.defaults.options.enableUnixSockets);
await t.throwsAsync(
gotUnixSocketsDisabled('unix:'),
{
message: 'Using UNIX domain sockets but option `enableUnixSockets` is not enabled',
},
);
});

test('`http://unix:/` fails when UNIX sockets are not enabled', async t => {
const gotUnixSocketsDisabled = got.extend({enableUnixSockets: false});

t.false(gotUnixSocketsDisabled.defaults.options.enableUnixSockets);

await t.throwsAsync(
gotUnixSocketsDisabled('http://unix:'),
{
message: 'Using UNIX domain sockets but option `enableUnixSockets` is not enabled',
},
);
});
}

0 comments on commit 461b3d4

Please sign in to comment.