Skip to content

Commit fb21041

Browse files
authored
Add unix sockets support (#578)
* Implement basic UNIX socket support Fixes #405. * Simplify socket logic * Document socket URL format * Add unix sockets to CHANGELOG
1 parent d439910 commit fb21041

File tree

4 files changed

+67
-8
lines changed

4 files changed

+67
-8
lines changed

CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,15 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
77

88
## [Unreleased]
99

10+
### Added
11+
12+
- Added support for UNIX socket URLs ([#405](https://github.com/arangodb/arangojs/issues/405))
13+
14+
In addition to the `unix:///socket/path` and `http+unix:///socket/path`
15+
URL formats recognized by ArangoDB, arangojs also supports the format
16+
`http://unix:/socket/path` commonly supported in the Node ecosystem and
17+
automatically converts ArangoDB endpoint URLs between them.
18+
1019
## [6.7.0] - 2018-10-24
1120

1221
### Changed

docs/Drivers/JS/Reference/Database/README.md

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,24 @@ If _config_ is a string, it will be interpreted as _config.url_.
2323
can be used to automatically pick up additional coordinators/followers at
2424
any point.
2525

26+
When running ArangoDB on a unix socket, e.g. `/tmp/arangodb.sock` the
27+
following URL formats are supported for unix sockets:
28+
29+
* `unix:///tmp/arangodb.sock` (no SSL)
30+
* `http+unix:///tmp/arangodb.sock` (or `https+unix://` for SSL)
31+
* `http://unix:/tmp/arangodb.sock` (or `https://unix:` for SSL)
32+
33+
Additionally `ssl` and `tls` are treated as synonymous with `https` and
34+
`tcp` is treated as synonymous with `http`, so the following URLs are
35+
considered identical:
36+
37+
* `tcp://localhost:8529` and `http://localhost:8529`
38+
* `ssl://localhost:8529` and `https://localhost:8529`
39+
* `tcp+unix:///tmp/arangodb.sock` and `http+unix:///tmp/arangodb.sock`
40+
* `ssl+unix:///tmp/arangodb.sock` and `https+unix:///tmp/arangodb.sock`
41+
* `tcp://unix:/tmp/arangodb.sock` and `http://unix:/tmp/arangodb.sock`
42+
* `ssl://unix:/tmp/arangodb.sock` and `https://unix:/tmp/arangodb.sock`
43+
2644
{% hint 'warning' %}
2745
As of arangojs 6.0.0 it is no longer possible to pass
2846
the username or password from the URL. Use
@@ -47,9 +65,12 @@ If _config_ is a string, it will be interpreted as _config.url_.
4765
- **isAbsolute**: `boolean` (Default: `false`)
4866

4967
If this option is explicitly set to `true`, the _url_ will be treated as the
50-
absolute database path. This is an escape hatch to allow using arangojs with
51-
database APIs exposed with a reverse proxy and makes it impossible to switch
52-
databases with _useDatabase_ or using _acquireHostList_.
68+
absolute database path and arangojs will not append the database path to it.
69+
70+
**Note:** This makes it impossible to switch databases with _useDatabase_
71+
or using _acquireHostList_. This is only intended to be used as an escape
72+
hatch when working with standalone servers exposing a single database API
73+
from behind a reverse proxy, which is not a recommended setup.
5374

5475
- **arangoVersion**: `number` (Default: `30000`)
5576

src/connection.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -226,8 +226,10 @@ export class Connection {
226226
}
227227

228228
private _sanitizeEndpointUrl(url: string): string {
229-
if (url.startsWith("tcp:")) return url.replace(/^tcp:/, "http:");
230-
if (url.startsWith("ssl:")) return url.replace(/^ssl:/, "https:");
229+
const raw = url.match(/^(tcp|ssl|tls)((?::|\+).+)/);
230+
if (raw) url = (raw[1] === "tcp" ? "http" : "https") + raw[2];
231+
const unix = url.match(/^(?:(https?)\+)?unix:\/\/(\/.+)/);
232+
if (unix) url = `${unix[1] || "http"}://unix:${unix[2]}`;
231233
return url;
232234
}
233235

src/util/request.node.ts

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import {
22
Agent as HttpAgent,
33
ClientRequest,
4+
ClientRequestArgs,
45
IncomingMessage,
56
request as httpRequest
67
} from "http";
@@ -40,7 +41,29 @@ export function createRequest(
4041
agent: any
4142
): RequestFunction {
4243
const baseUrlParts = parseUrl(baseUrl);
44+
if (!baseUrlParts.protocol) {
45+
throw new Error(`Invalid URL (no protocol): ${baseUrl}`);
46+
}
4347
const isTls = baseUrlParts.protocol === "https:";
48+
let socketPath: string | undefined;
49+
if (baseUrl.startsWith(`${baseUrlParts.protocol}//unix:`)) {
50+
if (!baseUrlParts.pathname) {
51+
throw new Error(
52+
`Unix socket URL must be in the format http://unix:/socket/path, http+unix:///socket/path or unix:///socket/path not ${baseUrl}`
53+
);
54+
}
55+
const i = baseUrlParts.pathname.indexOf(":");
56+
if (i === -1) {
57+
socketPath = baseUrlParts.pathname;
58+
baseUrlParts.pathname = undefined;
59+
} else {
60+
socketPath = baseUrlParts.pathname.slice(0, i);
61+
baseUrlParts.pathname = baseUrlParts.pathname.slice(i + 1) || undefined;
62+
}
63+
}
64+
if (socketPath && !socketPath.replace(/\//g, "").length) {
65+
throw new Error(`Invalid URL (empty unix socket path): ${baseUrl}`);
66+
}
4467
if (!agent) {
4568
if (isTls) agent = new HttpsAgent(agentOptions);
4669
else agent = new HttpAgent(agentOptions);
@@ -64,9 +87,13 @@ export function createRequest(
6487
if (body && !headers["content-length"]) {
6588
headers["content-length"] = String(Buffer.byteLength(body));
6689
}
67-
const options: any = { path, method, headers, agent };
68-
options.hostname = baseUrlParts.hostname;
69-
options.port = baseUrlParts.port;
90+
const options: ClientRequestArgs = { path, method, headers, agent };
91+
if (socketPath) {
92+
options.socketPath = socketPath;
93+
} else {
94+
options.host = baseUrlParts.hostname;
95+
options.port = baseUrlParts.port;
96+
}
7097
options.auth = baseUrlParts.auth;
7198
let called = false;
7299
try {

0 commit comments

Comments
 (0)