pixl-server-web 1.3.21 → 1.3.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -8,6 +8,7 @@ This module is a component for use in [pixl-server](https://www.github.com/jhuck
8
8
  - [Usage](#usage)
9
9
  - [Configuration](#configuration)
10
10
  * [http_port](#http_port)
11
+ * [http_alt_ports](#http_alt_ports)
11
12
  * [http_bind_address](#http_bind_address)
12
13
  * [http_htdocs_dir](#http_htdocs_dir)
13
14
  * [http_max_upload_size](#http_max_upload_size)
@@ -47,12 +48,14 @@ This module is a component for use in [pixl-server](https://www.github.com/jhuck
47
48
  * [http_clean_headers](#http_clean_headers)
48
49
  * [http_log_socket_errors](#http_log_socket_errors)
49
50
  * [http_full_uri_match](#http_full_uri_match)
51
+ * [http_flatten_query](#http_flatten_query)
50
52
  * [http_req_max_dump_enabled](#http_req_max_dump_enabled)
51
53
  * [http_req_max_dump_dir](#http_req_max_dump_dir)
52
54
  * [http_req_max_dump_debounce](#http_req_max_dump_debounce)
53
55
  * [http_public_ip_offset](#http_public_ip_offset)
54
56
  * [https](#https)
55
57
  * [https_port](#https_port)
58
+ * [https_alt_ports](#https_alt_ports)
56
59
  * [https_cert_file](#https_cert_file)
57
60
  * [https_key_file](#https_key_file)
58
61
  * [https_ca_file](#https_ca_file)
@@ -167,11 +170,22 @@ The configuration for this component is set by passing in a `WebServer` key in t
167
170
 
168
171
  ## http_port
169
172
 
170
- This is the port to listen on. The standard web port is 80, but note that only the root user can listen on ports below 1024.
173
+ This is the main port to listen on. The standard web port is 80, but note that only the root user can listen on ports below 1024.
174
+
175
+ ## http_alt_ports
176
+
177
+ If you would like to have the server listen on additional ports, add them here as an array. Example:
178
+
179
+ ```js
180
+ {
181
+ "http_port": 80,
182
+ "http_alt_ports": [ 3000, 8080 ]
183
+ }
184
+ ```
171
185
 
172
186
  ## http_bind_address
173
187
 
174
- Optionally specify an exact local IP address to bind the listener to. By default this binds to all available addresses on the machine. Example:
188
+ Optionally specify an exact local IP address to bind the listeners to. By default this binds to all available addresses on the machine. Example:
175
189
 
176
190
  ```js
177
191
  {
@@ -571,6 +585,17 @@ This boolean allows you to enable HTTPS (SSL) support in the web server. It def
571
585
 
572
586
  If HTTPS mode is enabled, this is the port to listen on for secure requests. The standard HTTPS port is 443.
573
587
 
588
+ ## https_alt_ports
589
+
590
+ If you would like to have the server listen on additional HTTPS ports, add them here as an array. Example:
591
+
592
+ ```js
593
+ {
594
+ "https_port": 443,
595
+ "https_alt_ports": [ 9000, 9001 ]
596
+ }
597
+ ```
598
+
574
599
  ## https_cert_file
575
600
 
576
601
  If HTTPS mode is enabled, this should point to your SSL certificate file on disk. The certificate file typically has a `.crt` filename extension, or possibly `cert.pem` if using [Let's Encrypt](https://letsencrypt.org/).
package/lib/http.js CHANGED
@@ -8,10 +8,9 @@ const Perf = require('pixl-perf');
8
8
 
9
9
  module.exports = class HTTP {
10
10
 
11
- startHTTP(callback) {
11
+ startHTTP(port, callback) {
12
12
  // start http server
13
13
  var self = this;
14
- var port = this.config.get('http_port');
15
14
  var bind_addr = this.config.get('http_bind_address') || '';
16
15
  var max_conns = this.config.get('http_max_connections') || 0;
17
16
  var https_force = self.config.get('https_force') || false;
@@ -52,14 +51,14 @@ module.exports = class HTTP {
52
51
  }
53
52
  };
54
53
 
55
- this.http = require('http').createServer( handler );
54
+ var listener = require('http').createServer( handler );
56
55
 
57
- this.http.on('connection', function(socket) {
56
+ listener.on('connection', function(socket) {
58
57
  var ip = socket.remoteAddress || '';
59
58
 
60
59
  if (max_conns && (self.numConns >= max_conns)) {
61
60
  // reached maximum concurrent connections, abort new ones
62
- self.logError('maxconns', "Maximum concurrent connections reached, denying connection from: " + ip, { ip: ip, max: max_conns });
61
+ self.logError('maxconns', "Maximum concurrent connections reached, denying connection from: " + ip, { ip: ip, port: port, max: max_conns });
63
62
  socket.end();
64
63
  socket.unref();
65
64
  socket.destroy(); // hard close
@@ -68,7 +67,7 @@ module.exports = class HTTP {
68
67
  }
69
68
  if (self.server.shut) {
70
69
  // server is shutting down, abort new connections
71
- self.logError('shutdown', "Server is shutting down, denying connection from: " + ip, { ip: ip });
70
+ self.logError('shutdown', "Server is shutting down, denying connection from: " + ip, { ip: ip, port: port });
72
71
  socket.end();
73
72
  socket.unref();
74
73
  socket.destroy(); // hard close
@@ -78,7 +77,7 @@ module.exports = class HTTP {
78
77
  var id = self.getNextId('c');
79
78
  self.conns[ id ] = socket;
80
79
  self.numConns++;
81
- self.logDebug(8, "New incoming HTTP connection: " + id, { ip: ip, num_conns: self.numConns });
80
+ self.logDebug(8, "New incoming HTTP connection: " + id, { ip: ip, port: port, num_conns: self.numConns });
82
81
 
83
82
  // Disable the Nagle algorithm.
84
83
  socket.setNoDelay( true );
@@ -86,6 +85,7 @@ module.exports = class HTTP {
86
85
  // add our own metadata to socket
87
86
  socket._pixl_data = {
88
87
  id: id,
88
+ port: port,
89
89
  proto: 'http',
90
90
  port: port,
91
91
  time_start: (new Date()).getTime(),
@@ -101,6 +101,7 @@ module.exports = class HTTP {
101
101
  var msg = "Socket preliminary timeout waiting for initial request (" + socket_prelim_timeout + " seconds)";
102
102
  var err_args = {
103
103
  ip: ip,
104
+ port: port,
104
105
  pending: self.queue.length(),
105
106
  active: self.queue.running(),
106
107
  sockets: self.numConns
@@ -132,6 +133,7 @@ module.exports = class HTTP {
132
133
  self.logError(err.code || 'socket', "Socket error: " + id + ": " + msg, {
133
134
  ip: ip,
134
135
  ips: args.ips,
136
+ port: port,
135
137
  state: args.state,
136
138
  method: args.request.method,
137
139
  uri: args.request.url,
@@ -156,6 +158,7 @@ module.exports = class HTTP {
156
158
  var now = (new Date()).getTime();
157
159
  self.logDebug(8, "HTTP connection has closed: " + id, {
158
160
  ip: ip,
161
+ port: port,
159
162
  total_elapsed: now - socket._pixl_data.time_start,
160
163
  num_requests: socket._pixl_data.num_requests,
161
164
  bytes_in: socket._pixl_data.bytes_in,
@@ -167,7 +170,7 @@ module.exports = class HTTP {
167
170
  } );
168
171
  } );
169
172
 
170
- this.http.on('clientError', function(err, socket) {
173
+ listener.on('clientError', function(err, socket) {
171
174
  // https://nodejs.org/api/http.html#http_event_clienterror
172
175
  if (!socket._pixl_data) socket._pixl_data = {};
173
176
  var args = socket._pixl_data.current || { request: {}, id: 'n/a' };
@@ -181,6 +184,7 @@ module.exports = class HTTP {
181
184
  id: args.id,
182
185
  ip: socket.remoteAddress,
183
186
  ips: args.ips,
187
+ port: port,
184
188
  state: args.state,
185
189
  method: args.request.method,
186
190
  uri: args.request.url,
@@ -208,36 +212,37 @@ module.exports = class HTTP {
208
212
  }
209
213
  });
210
214
 
211
- this.http.once('error', function(err) {
215
+ listener.once('error', function(err) {
212
216
  // fatal startup error on HTTP server, probably EADDRINUSE
213
- self.logError('startup', "Failed to start HTTP listener: " + err.message);
217
+ self.logError('startup', "Failed to start HTTP listener on port: " + port + ": " + err.message);
214
218
  return callback(err);
215
219
  } );
216
220
 
217
221
  var listen_opts = { port: port };
218
222
  if (bind_addr) listen_opts.host = bind_addr;
219
223
 
220
- this.http.listen( listen_opts, function(err) {
224
+ listener.listen( listen_opts, function(err) {
221
225
  if (err) {
222
- self.logError('startup', "Failed to start HTTP listener: " + err.message);
226
+ self.logError('startup', "Failed to start HTTP listener on port: " + port + ": " + err.message);
223
227
  return callback(err);
224
228
  }
225
- var info = self.http.address();
229
+ var info = listener.address();
226
230
  self.logDebug(3, "Now listening for HTTP connections", info);
227
231
  if (!port) {
228
232
  port = info.port;
229
233
  self.config.set('http_port', port);
230
234
  self.logDebug(3, "Actual HTTP listener port chosen: " + port);
231
235
  }
236
+ self.listeners.push(listener);
232
237
  callback();
233
238
  } );
234
239
 
235
240
  // set idle socket timeout
236
241
  if (this.config.get('http_timeout')) {
237
- this.http.setTimeout( this.config.get('http_timeout') * 1000 );
242
+ listener.setTimeout( this.config.get('http_timeout') * 1000 );
238
243
  }
239
244
  if (this.config.get('http_keep_alive_timeout')) {
240
- this.http.keepAliveTimeout = this.config.get('http_keep_alive_timeout') * 1000;
245
+ listener.keepAliveTimeout = this.config.get('http_keep_alive_timeout') * 1000;
241
246
  }
242
247
  }
243
248
 
package/lib/https.js CHANGED
@@ -18,10 +18,9 @@ const ACL = require('pixl-acl');
18
18
 
19
19
  module.exports = class HTTP2 {
20
20
 
21
- startHTTPS(callback) {
21
+ startHTTPS(port, callback) {
22
22
  // start https server
23
23
  var self = this;
24
- var port = this.config.get('https_port');
25
24
  var bind_addr = this.config.get('https_bind_address') || this.config.get('http_bind_address') || '';
26
25
  var max_conns = this.config.get('https_max_connections') || this.config.get('http_max_connections') || 0;
27
26
  var socket_prelim_timeout = self.config.get('https_socket_prelim_timeout') || self.config.get('http_socket_prelim_timeout') || 0;
@@ -50,14 +49,14 @@ module.exports = class HTTP2 {
50
49
  // optional chain.pem or the like
51
50
  opts.ca = fs.readFileSync( this.config.get('https_ca_file') );
52
51
  }
53
- this.https = require('https').createServer( opts, handler );
52
+ var listener = require('https').createServer( opts, handler );
54
53
 
55
- this.https.on('secureConnection', function(socket) {
54
+ listener.on('secureConnection', function(socket) {
56
55
  var ip = socket.remoteAddress || '';
57
56
 
58
57
  if (max_conns && (self.numConns >= max_conns)) {
59
58
  // reached maximum concurrent connections, abort new ones
60
- self.logError('maxconns', "Maximum concurrent connections reached, denying request from: " + ip, { ip: ip, max: max_conns });
59
+ self.logError('maxconns', "Maximum concurrent connections reached, denying request from: " + ip, { ip: ip, port: port, max: max_conns });
61
60
  socket.end();
62
61
  socket.unref();
63
62
  socket.destroy(); // hard close
@@ -66,7 +65,7 @@ module.exports = class HTTP2 {
66
65
  }
67
66
  if (self.server.shut) {
68
67
  // server is shutting down, abort new connections
69
- self.logError('shutdown', "Server is shutting down, denying connection from: " + ip, { ip: ip });
68
+ self.logError('shutdown', "Server is shutting down, denying connection from: " + ip, { ip: ip, port: port});
70
69
  socket.end();
71
70
  socket.unref();
72
71
  socket.destroy(); // hard close
@@ -76,7 +75,7 @@ module.exports = class HTTP2 {
76
75
  var id = self.getNextId('cs');
77
76
  self.conns[ id ] = socket;
78
77
  self.numConns++;
79
- self.logDebug(8, "New incoming HTTPS (SSL) connection: " + id, { ip: ip, num_conns: self.numConns });
78
+ self.logDebug(8, "New incoming HTTPS (SSL) connection: " + id, { ip: ip, port: port, num_conns: self.numConns });
80
79
 
81
80
  // Disable the Nagle algorithm.
82
81
  socket.setNoDelay( true );
@@ -84,6 +83,7 @@ module.exports = class HTTP2 {
84
83
  // add our own metadata to socket
85
84
  socket._pixl_data = {
86
85
  id: id,
86
+ port: port,
87
87
  proto: 'https',
88
88
  port: port,
89
89
  time_start: (new Date()).getTime(),
@@ -99,6 +99,7 @@ module.exports = class HTTP2 {
99
99
  var msg = "Socket preliminary timeout waiting for initial request (" + socket_prelim_timeout + " seconds)";
100
100
  var err_args = {
101
101
  ip: ip,
102
+ port: port,
102
103
  pending: self.queue.length(),
103
104
  active: self.queue.running(),
104
105
  sockets: self.numConns
@@ -130,6 +131,7 @@ module.exports = class HTTP2 {
130
131
  self.logError(err.code || 'socket', "Socket error: " + id + ": " + msg, {
131
132
  ip: ip,
132
133
  ips: args.ips,
134
+ port: port,
133
135
  state: args.state,
134
136
  method: args.request.method,
135
137
  uri: args.request.url,
@@ -154,6 +156,7 @@ module.exports = class HTTP2 {
154
156
  var now = (new Date()).getTime();
155
157
  self.logDebug(8, "HTTPS (SSL) connection has closed: " + id, {
156
158
  ip: ip,
159
+ port: port,
157
160
  total_elapsed: now - socket._pixl_data.time_start,
158
161
  num_requests: socket._pixl_data.num_requests,
159
162
  bytes_in: socket._pixl_data.bytes_in,
@@ -165,7 +168,7 @@ module.exports = class HTTP2 {
165
168
  } );
166
169
  } );
167
170
 
168
- this.https.on('clientError', function(err, socket) {
171
+ listener.on('clientError', function(err, socket) {
169
172
  // https://nodejs.org/api/http.html#http_event_clienterror
170
173
  if (!socket._pixl_data) socket._pixl_data = {};
171
174
  var args = socket._pixl_data.current || { request: {}, id: 'n/a' };
@@ -179,6 +182,7 @@ module.exports = class HTTP2 {
179
182
  id: args.id,
180
183
  ip: socket.remoteAddress,
181
184
  ips: args.ips,
185
+ port: port,
182
186
  state: args.state,
183
187
  method: args.request.method,
184
188
  uri: args.request.url,
@@ -206,40 +210,41 @@ module.exports = class HTTP2 {
206
210
  }
207
211
  });
208
212
 
209
- this.https.once('error', function(err) {
213
+ listener.once('error', function(err) {
210
214
  // fatal startup error on HTTPS server, probably EADDRINUSE
211
- self.logError('startup', "Failed to start HTTPS listener: " + err.message);
215
+ self.logError('startup', "Failed to start HTTPS listener on port: " + port + ": " + err.message);
212
216
  return callback(err);
213
217
  } );
214
218
 
215
219
  var listen_opts = { port: port };
216
220
  if (bind_addr) listen_opts.host = bind_addr;
217
221
 
218
- this.https.listen( listen_opts, function(err) {
222
+ listener.listen( listen_opts, function(err) {
219
223
  if (err) {
220
- self.logError('startup', "Failed to start HTTPS listener: " + err.message);
224
+ self.logError('startup', "Failed to start HTTPS listener on port: " + port + ": " + err.message);
221
225
  return callback(err);
222
226
  }
223
- var info = self.https.address();
227
+ var info = listener.address();
224
228
  self.logDebug(3, "Now listening for HTTPS connections", info);
225
229
  if (!port) {
226
230
  port = info.port;
227
231
  self.config.set('https_port', port);
228
232
  self.logDebug(3, "Actual HTTPS listener port chosen: " + port);
229
233
  }
234
+ self.listeners.push(listener);
230
235
  callback();
231
236
  } );
232
237
 
233
238
  // set idle socket timeout
234
239
  var timeout_sec = this.config.get('https_timeout') || this.config.get('http_timeout') || 0;
235
240
  if (timeout_sec) {
236
- this.https.setTimeout( timeout_sec * 1000 );
241
+ listener.setTimeout( timeout_sec * 1000 );
237
242
  }
238
243
  if (this.config.get('https_keep_alive_timeout')) {
239
- this.https.keepAliveTimeout = this.config.get('https_keep_alive_timeout') * 1000;
244
+ listener.keepAliveTimeout = this.config.get('https_keep_alive_timeout') * 1000;
240
245
  }
241
246
  else if (this.config.get('http_keep_alive_timeout')) {
242
- this.https.keepAliveTimeout = this.config.get('http_keep_alive_timeout') * 1000;
247
+ listener.keepAliveTimeout = this.config.get('http_keep_alive_timeout') * 1000;
243
248
  }
244
249
  }
245
250
 
package/lib/response.js CHANGED
@@ -326,6 +326,8 @@ module.exports = class Response {
326
326
  id: args.id,
327
327
  proto: args.request.headers['ssl'] ? 'https' : socket_data.proto,
328
328
  ips: args.ips,
329
+ port: socket_data.port,
330
+ socket: socket_data.id,
329
331
  host: args.request.headers['host'] || '',
330
332
  ua: args.request.headers['user-agent'] || '',
331
333
  perf: metrics
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pixl-server-web",
3
- "version": "1.3.21",
3
+ "version": "1.3.22",
4
4
  "description": "A web server component for the pixl-server framework.",
5
5
  "author": "Joseph Huckaby <jhuckaby@gmail.com>",
6
6
  "homepage": "https://github.com/jhuckaby/pixl-server-web",
package/test/test.js CHANGED
@@ -33,6 +33,7 @@ var server = new PixlServer({
33
33
 
34
34
  "WebServer": {
35
35
  "http_port": 3020,
36
+ "http_alt_ports": [3120],
36
37
  "http_htdocs_dir": __dirname,
37
38
  "http_max_upload_size": 1024 * 10,
38
39
  "http_static_ttl": 3600,
@@ -53,6 +54,7 @@ var server = new PixlServer({
53
54
 
54
55
  "https": 1,
55
56
  "https_port": 3021,
57
+ "https_alt_ports": [3121],
56
58
  "https_cert_file": "ssl.crt",
57
59
  "https_key_file": "ssl.key",
58
60
  "https_force": 0,
@@ -191,6 +193,33 @@ module.exports = {
191
193
  );
192
194
  },
193
195
 
196
+ function testHTTPAltPort(test) {
197
+ // test simple HTTP GET request to webserver backend, alternate port
198
+ request.json( 'http://127.0.0.1:3120/json', false,
199
+ {
200
+ headers: {
201
+ 'X-Test': "Test"
202
+ }
203
+ },
204
+ function(err, resp, json, perf) {
205
+ test.ok( !err, "No error from PixlRequest: " + err );
206
+ test.ok( !!resp, "Got resp from PixlRequest" );
207
+ test.ok( resp.statusCode == 200, "Got 200 response: " + resp.statusCode );
208
+ test.ok( resp.headers['via'] == "WebServerTest 1.0", "Correct Via header: " + resp.headers['via'] );
209
+ test.ok( !!json, "Got JSON in response" );
210
+ test.ok( json.code == 0, "Correct code in JSON response: " + json.code );
211
+ test.ok( !!json.user, "Found user object in JSON response" );
212
+ test.ok( json.user.Name == "Joe", "Correct user name in JSON response: " + json.user.Name );
213
+
214
+ // request headers will be echoed back
215
+ test.ok( !!json.headers, "Found headers echoed in JSON response" );
216
+ test.ok( json.headers['x-test'] == "Test", "Found Test header echoed in JSON response" );
217
+
218
+ test.done();
219
+ }
220
+ );
221
+ },
222
+
194
223
  function testBadRequest(test) {
195
224
  // test bad HTTP GET request to webserver backend
196
225
  // this still resolves to the root dir index due to the ../
@@ -1576,6 +1605,35 @@ module.exports = {
1576
1605
  );
1577
1606
  },
1578
1607
 
1608
+ function testHTTPSAltPort(test) {
1609
+ // test HTTPS GET request to webserver backend on alt port
1610
+ request.json( 'https://127.0.0.1:3121/json', false,
1611
+ {
1612
+ rejectUnauthorized: false, // self-signed cert
1613
+ headers: {
1614
+ 'X-Test': "Test"
1615
+ }
1616
+ },
1617
+ function(err, resp, json, perf) {
1618
+ test.ok( !err, "No error from PixlRequest: " + err );
1619
+ test.ok( !!resp, "Got resp from PixlRequest" );
1620
+ test.ok( resp.statusCode == 200, "Got 200 response: " + resp.statusCode );
1621
+ test.ok( resp.headers['via'] == "WebServerTest 1.0", "Correct Via header: " + resp.headers['via'] );
1622
+ test.ok( !!json, "Got JSON in response" );
1623
+ test.ok( json.code == 0, "Correct code in JSON response: " + json.code );
1624
+ test.ok( !!json.user, "Found user object in JSON response" );
1625
+ test.ok( json.user.Name == "Joe", "Correct user name in JSON response: " + json.user.Name );
1626
+
1627
+ // request headers will be echoed back
1628
+ test.ok( !!json.headers, "Found headers echoed in JSON response" );
1629
+ test.ok( json.headers['x-test'] == "Test", "Found Test header echoed in JSON response" );
1630
+ test.ok( !!json.headers.ssl, "SSL pseudo-header present in echo" );
1631
+
1632
+ test.done();
1633
+ }
1634
+ );
1635
+ },
1636
+
1579
1637
  function testHTTPSPost(test) {
1580
1638
  request.post( 'https://127.0.0.1:3021/json',
1581
1639
  {
package/web_server.js CHANGED
@@ -91,6 +91,7 @@ class WebServer extends Component {
91
91
  this.logDebug(2, "pixl-server-web v" + this.version + " starting up");
92
92
 
93
93
  // setup connections and handlers
94
+ this.listeners = [];
94
95
  this.conns = {};
95
96
  this.requests = {};
96
97
  this.uriFilters = [];
@@ -194,16 +195,41 @@ class WebServer extends Component {
194
195
  // listen for tick events to swap stat buffers
195
196
  this.server.on( 'tick', this.tick.bind(this) );
196
197
 
197
- // start listeners
198
- this.startHTTP( function(err) {
199
- if (err) return callback(err);
200
-
201
- // also start HTTPS listener?
202
- if (self.config.get('https')) {
203
- self.startHTTPS( callback );
204
- }
205
- else callback(err);
198
+ this.startAll(callback);
199
+ }
200
+
201
+ startAll(callback) {
202
+ // start all HTTP(s) listeners
203
+ var self = this;
204
+ var tasks = [];
205
+
206
+ // always start plain HTTP on base port
207
+ tasks.push([ this.config.get('http_port'), 'startHTTP' ]);
208
+
209
+ // optional additional ports
210
+ (this.config.get('http_alt_ports') || []).forEach( function(port) {
211
+ tasks.push([ port, 'startHTTP' ]);
206
212
  } );
213
+
214
+ // optional HTTPS
215
+ if (this.config.get('https')) {
216
+ tasks.push([ this.config.get('https_port'), 'startHTTPS' ]);
217
+
218
+ // optional additional ports
219
+ (this.config.get('https_alt_ports') || []).forEach( function(port) {
220
+ tasks.push([ port, 'startHTTPS' ]);
221
+ } );
222
+ }
223
+
224
+ // start all listeners in parallel
225
+ async.each( tasks,
226
+ function(task, callback) {
227
+ var port = task[0];
228
+ var func = task[1];
229
+ self[func](port, callback);
230
+ },
231
+ callback
232
+ );
207
233
  }
208
234
 
209
235
  dumpAllRequests(callback) {
@@ -263,12 +289,13 @@ class WebServer extends Component {
263
289
  getStats() {
264
290
  // get current stats, merged with live socket and request info
265
291
  var socket_info = {};
266
- var listener_info = {};
292
+ var listener_info = [];
267
293
  var now = (new Date()).getTime();
268
294
  var num_sockets = 0;
269
295
 
270
- if (this.http) listener_info.http = this.http.address();
271
- if (this.https) listener_info.https = this.https.address();
296
+ listener_info = this.listeners.map( function(listener) {
297
+ return listener.address();
298
+ } );
272
299
 
273
300
  for (var key in this.conns) {
274
301
  var socket = this.conns[key];
@@ -432,7 +459,7 @@ class WebServer extends Component {
432
459
  // shutdown http server
433
460
  var self = this;
434
461
 
435
- if (this.http) {
462
+ if (this.listeners.length) {
436
463
  this.logDebug(2, "Shutting down HTTP server");
437
464
 
438
465
  for (var id in this.requests) {
@@ -461,12 +488,11 @@ class WebServer extends Component {
461
488
  this.numConns--;
462
489
  } // foreach conn
463
490
 
464
- this.http.close( function() { self.logDebug(3, "HTTP server has shut down."); } );
465
-
466
- if (this.https) {
467
- this.https.close( function() { self.logDebug(3, "HTTPS server has shut down."); } );
468
- }
469
- // delete this.http;
491
+ // close all listeners
492
+ this.listeners.forEach( function(listener) {
493
+ var info = listener.address() || { port: 'n/a' };
494
+ listener.close( function() { self.logDebug(3, "HTTP server on port " + info.port + " has shut down.", info); } );
495
+ } );
470
496
 
471
497
  this.requests = {};
472
498
  this.queue.kill();