Skip to content
This repository has been archived by the owner on Sep 28, 2021. It is now read-only.

Commit

Permalink
support listening on unix domain sockets
Browse files Browse the repository at this point in the history
This commit refactors the logic for parsing the http2 server's
listener options.

Fixes: grpc/grpc-node#258
  • Loading branch information
cjihrig committed Jan 27, 2020
1 parent fc04a0d commit 1143db7
Show file tree
Hide file tree
Showing 4 changed files with 103 additions and 4 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ The goal is to be largely compatible with the existing [`Server`](https://grpc.i
- [gRPC Compression](https://github.com/grpc/grpc/blob/master/doc/compression.md)
- [gRPC Environment Variables](https://github.com/grpc/grpc/blob/master/doc/environment_variables.md)
- [gRPC Keepalive](https://github.com/grpc/grpc/blob/master/doc/keepalive.md)
- [gRPC Name Resolution](https://github.com/grpc/grpc/blob/master/doc/naming.md)
- [gRPC Status Codes](https://github.com/grpc/grpc/blob/master/doc/statuscodes.md)

## Acknowledgement
Expand Down
35 changes: 35 additions & 0 deletions lib/server-resolver.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
'use strict';
const { isAbsolute, resolve } = require('path');
const { URL } = require('url');


function resolveToListenOptions (target, secure) {
if (target.startsWith('unix:')) {
if (target.startsWith('unix://')) {
const path = target.substring(7);

// The path following 'unix://' must be absolute.
if (!isAbsolute(path)) {
throw new Error(`'${target}' must specify an absolute path`);
}

return { path };
}

// The path following 'unix:' can be relative or absolute.
return { path: resolve(target.substring(5)) };
}

if (target.startsWith('dns:')) {
target = target.substring(4);
}

const url = new URL(`http://${target}`);
const defaultPort = secure === true ? 443 : 80;
const port = String(+url.port) === url.port ? +url.port : defaultPort;

return { host: url.hostname, port };
}


module.exports = { resolveToListenOptions };
7 changes: 3 additions & 4 deletions lib/server.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
'use strict';
const Http2 = require('http2');
const { URL } = require('url');
const { status, ServerCredentials } = require('@grpc/grpc-js');
const {
ServerDuplexStream,
Expand All @@ -9,6 +8,7 @@ const {
ServerWritableStream
} = require('./handler');
const { ServerCall } = require('./server-call');
const { resolveToListenOptions } = require('./server-resolver');
const { ServerSession } = require('./server-session');
const kHandlers = Symbol('handlers');
const kServer = Symbol('server');
Expand Down Expand Up @@ -123,8 +123,7 @@ class Server {
throw new TypeError('callback must be a function');
}

const url = new URL(`http://${port}`);
const options = { host: url.hostname, port: +url.port };
const listenOptions = resolveToListenOptions(port, creds._isSecure());
const http2ServerOptions = {
allowHTTP1: false,
settings: {
Expand Down Expand Up @@ -153,7 +152,7 @@ class Server {
}

this[kServer].once('error', onError);
this[kServer].listen(options, () => {
this[kServer].listen(listenOptions, () => {
const server = this[kServer];
const port = server.address().port;

Expand Down
64 changes: 64 additions & 0 deletions test/server-resolver.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
'use strict';
const Assert = require('assert');
const Path = require('path');
const Lab = require('@hapi/lab');
const { resolveToListenOptions } = require('../lib/server-resolver');

// Test shortcuts
const { describe, it } = exports.lab = Lab.script();


// Note(cjihrig): As of @grpc/[email protected], the client claims to support Unix
// domain sockets. However, testing the grpc-js client did not seem to work.
// Testing grpcurl with the flags `-plaintext -unix -authority 'localhost'` did
// work for an insecure server.
describe('Server Resolver', () => {
it('resolveToListenOptions() successfully parses inputs', () => {
[
[
resolveToListenOptions('dns:127.0.0.1:9999', true),
{ host: '127.0.0.1', port: 9999 }
],
[
resolveToListenOptions('dns:foo.bar.com:9999', false),
{ host: 'foo.bar.com', port: 9999 }
],
[
resolveToListenOptions('localhost:8080', true),
{ host: 'localhost', port: 8080 }
],
[
resolveToListenOptions('localhost:8080', false),
{ host: 'localhost', port: 8080 }
],
[
resolveToListenOptions('localhost', true),
{ host: 'localhost', port: 443 }
],
[
resolveToListenOptions('localhost', false),
{ host: 'localhost', port: 80 }
],
[
resolveToListenOptions('unix:/foo/bar', false),
{ path: '/foo/bar' }
],
[
resolveToListenOptions('unix:./foo/../baz/bar', false),
{ path: Path.join(process.cwd(), 'baz', 'bar') }
],
[
resolveToListenOptions('unix:///foo/bar', false),
{ path: '/foo/bar' }
]
].forEach(([actual, expected]) => {
Assert.deepStrictEqual(actual, expected);
});
});

it('resolveToListenOptions() throws if unix:// path is not absolute', () => {
Assert.throws(() => {
resolveToListenOptions('unix://./foo', false);
}, /^Error: 'unix:\/\/\.\/foo' must specify an absolute path$/);
});
});

0 comments on commit 1143db7

Please sign in to comment.