Skip to content

Commit f9a386b

Browse files
committed
Cleanup host, port, and address config. Closes hapijs#2224
1 parent 5f444db commit f9a386b

File tree

7 files changed

+69
-55
lines changed

7 files changed

+69
-55
lines changed

docs/Reference.md

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -264,17 +264,21 @@ the sole connection where:
264264
- `id` - a unique connection identifier (using the format '{hostname}:{pid}:{now base36}').
265265
- `created` - the connection creation timestamp.
266266
- `started` - the connection start timestamp (`0` when stopped).
267-
- `port` - the port the connection was configured to (before
268-
[`server.start()`](#serverstartcallback)) or bound to (after
269-
[`server.start()`](#serverstartcallback)).
270-
- `host` - the host name the connection was configured to (defaults to `'0.0.0.0'` if no host was
271-
provided).
267+
- `port` - the connection port based on the following rules:
268+
- `undefined` when no port is configured or set to `0` and the server has not been started.
269+
- the configured port value when set before the server has been started.
270+
- the actual port assigned when no port is configured or set to `0` after the server has been
271+
started.
272+
- `host` - the host name the connection was configured to. Defaults to the operating system
273+
hostname when available, otherwise `'localhost'`.
274+
- `address` - the active IP address the connection was bound to after starting. Set to `undefined`
275+
until the server has been started or when using a non TCP port (e.g. UNIX domain socket).
272276
- `protocol` - the protocol used:
273277
- `'http'` - HTTP.
274278
- `'https'` - HTTPS.
275279
- `'socket'` - UNIX domain socket or Windows named pipe.
276280
- `uri` - a string representing the connection (e.g. 'http://example.com:8080' or
277-
'socket:/unix/domain/socket/path').
281+
'socket:/unix/domain/socket/path'). Only available when `info.port` is available.
278282

279283
When the server contains more than one connection, each [`server.connections`](#serverconnections)
280284
array member provides its own `connection.info`.
@@ -701,10 +705,14 @@ cache.set('norway', { capital: 'oslo' }, function (err) {
701705
### `server.connection([options])`
702706

703707
Adds an incoming server connection where:
704-
- `host` - the hostname or IP address. Defaults to `0.0.0.0` which means any available network
705-
interface. Set to `127.0.0.1` or `localhost` to restrict connection to only those coming from
706-
the same machine.
707-
- `port` - the TCP port the connection is listening to. Defaults to an ephemeral port (`0`) which
708+
- `host` - the public hostname or IP address. Used only to set `server.info.host` and
709+
`server.info.uri`. If not configured, defaults to the operating system hostname and if not
710+
available, to `'localhost'`.
711+
- `address` - sets the host name or IP address the connection will listen on. If not configured,
712+
defaults to `host` if present, otherwise to all available network interfaces (i.e. `'0.0.0.0'`).
713+
Set to `127.0.0.1` or `localhost` to restrict connection to only those coming from the same
714+
machine.
715+
- `port` - the TCP port the connection will listen to. Defaults to an ephemeral port (`0`) which
708716
uses an available port when the server is started (and assigned to `server.info.port`). If `port`
709717
is a string containing a '/' character, it is used as a UNIX domain socket path and if it starts
710718
with '\\.\pipe' as a Windows named pipe.

lib/connection.js

Lines changed: 19 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -43,19 +43,17 @@ exports = module.exports = internals.Connection = function (server, options) {
4343
this.settings.port = 0;
4444
}
4545

46+
this.type = (typeof this.settings.port === 'string' ? 'socket' : 'tcp');
47+
if (this.type === 'socket') {
48+
this.settings.port = (this.settings.port.indexOf('/') !== -1 ? Path.resolve(this.settings.port) : this.settings.port.toLowerCase());
49+
}
50+
4651
if (this.settings.autoListen === undefined) {
4752
this.settings.autoListen = true;
4853
}
4954

5055
Hoek.assert(this.settings.autoListen || !this.settings.port, 'Cannot specify port when autoListen is false');
51-
52-
// Connection properties
53-
54-
this._port = this.settings.port;
55-
this.type = (typeof this._port === 'string' ? 'socket' : 'tcp');
56-
if (this.type === 'socket') {
57-
this._port = (this._port.indexOf('/') !== -1 ? Path.resolve(this._port) : this._port.toLowerCase());
58-
}
56+
Hoek.assert(this.settings.autoListen || !this.settings.address, 'Cannot specify address when autoListen is false');
5957

6058
// Connection facilities
6159

@@ -94,13 +92,15 @@ exports = module.exports = internals.Connection = function (server, options) {
9492
this.info = {
9593
created: now,
9694
started: 0,
97-
host: this._hostname(),
98-
port: this._port,
99-
protocol: this.type === 'tcp' ? (this.settings.tls ? 'https' : 'http') : this.type
95+
host: this.settings.host || Os.hostname() || 'localhost',
96+
protocol: this.type === 'tcp' ? (this.settings.tls ? 'https' : 'http') : this.type,
97+
id: Os.hostname() + ':' + process.pid + ':' + now.toString(36)
10098
};
10199

102-
this.info.uri = this.info.protocol + ':' + (this.type === 'tcp' ? '//' + this.info.host + ':' + this.info.port : this.info.port);
103-
this.info.id = Os.hostname() + ':' + process.pid + ':' + now.toString(36);
100+
if (this.settings.port) {
101+
this.info.port = this.settings.port;
102+
this.info.uri = this.info.protocol + ':' + (this.type === 'tcp' ? '//' + this.info.host + ':' + this.info.port : this.info.port);
103+
}
104104
};
105105

106106
Hoek.inherits(internals.Connection, Events.EventEmitter);
@@ -114,11 +114,11 @@ internals.Connection.prototype._init = function () {
114114

115115
this.listener.once('listening', function () {
116116

117-
// Update the host, port, and uri with active values
117+
// Update the address, port, and uri with active values
118118

119119
if (self.type === 'tcp') {
120120
var address = self.listener.address();
121-
self.info.host = self._hostname(address.address);
121+
self.info.address = address.address;
122122
self.info.port = address.port;
123123
self.info.uri = self.info.protocol + '://' + self.info.host + ':' + self.info.port;
124124
}
@@ -140,12 +140,6 @@ internals.Connection.prototype._init = function () {
140140
};
141141

142142

143-
internals.Connection.prototype._hostname = function (address) {
144-
145-
return this.settings.host || address || Os.hostname() || 'localhost';
146-
};
147-
148-
149143
internals.Connection.prototype._start = function (callback) {
150144

151145
if (this._started) {
@@ -159,13 +153,12 @@ internals.Connection.prototype._start = function (callback) {
159153
return process.nextTick(callback);
160154
}
161155

162-
if (this.type !== 'tcp' ||
163-
!this.settings.host) {
164-
165-
this.listener.listen(this._port, callback);
156+
if (this.type !== 'tcp') {
157+
this.listener.listen(this.settings.port, callback);
166158
}
167159
else {
168-
this.listener.listen(this._port, this.settings.host, callback);
160+
var address = this.settings.address || this.settings.host || '0.0.0.0';
161+
this.listener.listen(this.settings.port, address, callback);
169162
}
170163
};
171164

lib/plugin.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,7 @@ internals.Plugin.prototype.register = function (plugins /*, [options], callback
213213

214214
for (var i = 0, il = selection.connections.length; i < il; ++i) {
215215
var connection = selection.connections[i];
216-
Hoek.assert(item.multiple || !connection._registrations[item.name], 'Plugin', item.name, 'already registered in:', connection.info.uri);
216+
Hoek.assert(item.multiple || !connection._registrations[item.name], 'Plugin', item.name, 'already registered in:', connection.info.host + ':' + connection.settings.port);
217217
connection._registrations[item.name] = item;
218218
}
219219

lib/schema.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,8 @@ internals.server = Joi.object({
193193

194194
internals.connection = internals.connectionBase.keys({
195195
autoListen: Joi.boolean(),
196-
host: Joi.string().hostname().allow(null),
196+
host: Joi.string().hostname(),
197+
address: Joi.string().hostname(),
197198
labels: internals.labels,
198199
listener: Joi.any(),
199200
port: Joi.alternatives([

lib/server.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ internals.Server.prototype.connection = function (options) {
103103
settings.routes.cors = Hoek.applyToDefaults(this._settings.connections.routes.cors || Defaults.cors, settings.routes.cors);
104104
settings.routes.security = Hoek.applyToDefaults(this._settings.connections.routes.security || Defaults.security, settings.routes.security);
105105

106-
settings = Schema.assert('connection', settings); // Applies validation changes (type cast)
106+
settings = Schema.assert('connection', settings); // Applies validation changes (type cast)
107107

108108
var connection = new Connection(this, settings);
109109
this.connections.push(connection);
@@ -133,7 +133,7 @@ internals.Server.prototype.start = function (callback) {
133133
var connection = dependency.connections[s];
134134
for (var d = 0, dl = dependency.deps.length; d < dl; ++d) {
135135
var dep = dependency.deps[d];
136-
Hoek.assert(connection._registrations[dep], 'Plugin', dependency.plugin, 'missing dependency', dep, 'in connection:', connection.info.uri);
136+
Hoek.assert(connection._registrations[dep], 'Plugin', dependency.plugin, 'missing dependency', dep, 'in connection:', connection.info.host + ':' + connection.settings.port);
137137
}
138138
}
139139
}

test/connection.js

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ describe('Connection', function () {
7070
done();
7171
});
7272

73-
it('defaults to 0.0.0.0 or :: when no host is provided', function (done) {
73+
it('defaults address to 0.0.0.0 or :: when no host is provided', function (done) {
7474

7575
var server = new Hapi.Server();
7676
server.connection();
@@ -81,7 +81,19 @@ describe('Connection', function () {
8181
expectedBoundAddress = '::';
8282
}
8383

84-
expect(server.info.host).to.equal(expectedBoundAddress);
84+
expect(server.info.address).to.equal(expectedBoundAddress);
85+
done();
86+
});
87+
});
88+
89+
it('uses address when present instead of host', function (done) {
90+
91+
var server = new Hapi.Server();
92+
server.connection({ host: 'no.such.domain.hapi', address: 'localhost' });
93+
server.start(function () {
94+
95+
expect(server.info.host).to.equal('no.such.domain.hapi');
96+
expect(server.info.address).to.equal('127.0.0.1');
8597
done();
8698
});
8799
});
@@ -93,7 +105,6 @@ describe('Connection', function () {
93105
server.connection({ port: port });
94106

95107
expect(server.connections[0].type).to.equal('socket');
96-
expect(server.connections[0]._port).to.equal(port);
97108

98109
server.start(function () {
99110

@@ -116,7 +127,6 @@ describe('Connection', function () {
116127
server.connection({ port: port });
117128

118129
expect(server.connections[0].type).to.equal('socket');
119-
expect(server.connections[0]._port).to.equal(port);
120130

121131
server.start(function () {
122132

@@ -265,8 +275,9 @@ describe('Connection', function () {
265275
expectedBoundAddress = '::';
266276
}
267277

268-
expect(server.info.host).to.equal(expectedBoundAddress);
269-
expect(server.info.port).to.not.equal(0);
278+
expect(server.info.host).to.equal(Os.hostname());
279+
expect(server.info.address).to.equal(expectedBoundAddress);
280+
expect(server.info.port).to.be.a.number().and.above(1);
270281
server.stop();
271282
done();
272283
});
@@ -300,9 +311,9 @@ describe('Connection', function () {
300311
};
301312

302313
var server = new Hapi.Server();
303-
server.connection();
314+
server.connection({ port: '8000' });
304315
expect(server.info.host).to.equal('localhost');
305-
expect(server.info.uri).to.equal('http://localhost:' + server.info.port);
316+
expect(server.info.uri).to.equal('http://localhost:8000');
306317
done();
307318
});
308319

test/plugin.js

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
// Load modules
22

3+
var Os = require('os');
34
var Path = require('path');
45
var Boom = require('boom');
56
var CatboxMemory = require('catbox-memory');
@@ -317,14 +318,14 @@ describe('Plugin', function () {
317318
};
318319

319320
var server = new Hapi.Server();
320-
server.connection();
321+
server.connection({ host: 'example.com' });
321322
server.register(test, function (err) {
322323

323324
expect(err).to.not.exist();
324325
expect(function () {
325326

326327
server.register(test, function (err) { });
327-
}).to.throw('Plugin test already registered in: ' + server.info.uri);
328+
}).to.throw('Plugin test already registered in: example.com:0');
328329

329330
done();
330331
});
@@ -1096,21 +1097,21 @@ describe('Plugin', function () {
10961097
expect(function () {
10971098

10981099
server.start();
1099-
}).to.throw('Plugin test missing dependency none in connection: ' + server.info.uri);
1100+
}).to.throw('Plugin test missing dependency none in connection: ' + Os.hostname() + ':0');
11001101
done();
11011102
});
11021103
});
11031104

11041105
it('fails to register multiple plugins with dependencies', function (done) {
11051106

11061107
var server = new Hapi.Server();
1107-
server.connection();
1108+
server.connection({ port: 80, host: 'localhost' });
11081109
server.register([internals.plugins.deps1, internals.plugins.deps3], function (err) {
11091110

11101111
expect(function () {
11111112

11121113
server.start();
1113-
}).to.throw('Plugin deps1 missing dependency deps2 in connection: ' + server.info.uri);
1114+
}).to.throw('Plugin deps1 missing dependency deps2 in connection: localhost:80');
11141115
done();
11151116
});
11161117
});
@@ -1176,13 +1177,13 @@ describe('Plugin', function () {
11761177
};
11771178

11781179
var server = new Hapi.Server();
1179-
server.connection();
1180+
server.connection({ port: 80, host: 'localhost' });
11801181
server.register(a, function (err) {
11811182

11821183
expect(function () {
11831184

11841185
server.start();
1185-
}).to.throw('Plugin b missing dependency c in connection: ' + server.info.uri);
1186+
}).to.throw('Plugin b missing dependency c in connection: localhost:80');
11861187
done();
11871188
});
11881189
});

0 commit comments

Comments
 (0)