v2.4.1: allow two function listeners and return server.unecrypted for error listening

This commit is contained in:
AJ ONeal 2018-08-17 20:43:32 -06:00
parent 6f960b1a2a
commit 38de3e9d1c
4 changed files with 61 additions and 18 deletions

View File

@ -330,6 +330,15 @@ var server = glx.listen(80, 443, function () {
}); });
``` ```
Note: You shouldn't be using the plain HTTP server for anything except, potentially, for error handling
on the listen event (if the default print-and-quit behavior doesn't work for your use case).
If you need to do that, here's how:
```
var plainServer = server.unencrypted;
plainServer.on('error', function (err) { ... });
```
The Automatic Certificate Issuance is initiated via SNI (`httpsOptions.SNICallback`). The Automatic Certificate Issuance is initiated via SNI (`httpsOptions.SNICallback`).
For security, domain validation MUST have an approval callback in *production*. For security, domain validation MUST have an approval callback in *production*.

View File

@ -29,7 +29,7 @@ module.exports.create = function (opts) {
console.error(e.code + ": '" + e.address + ":" + e.port + "'"); console.error(e.code + ": '" + e.address + ":" + e.port + "'");
} }
function _listenHttp(plainPort, sayAnything) { function _listenHttp(plainPort) {
if (!plainPort) { plainPort = 80; } if (!plainPort) { plainPort = 80; }
var p = plainPort; var p = plainPort;
var validHttpPort = (parseInt(p, 10) >= 0); var validHttpPort = (parseInt(p, 10) >= 0);
@ -39,10 +39,7 @@ module.exports.create = function (opts) {
); );
var promise = new PromiseA(function (resolve) { var promise = new PromiseA(function (resolve) {
plainServer.listen(p, function () { plainServer.listen(p, function () {
if (sayAnything) { resolve(plainServer);
console.info("Success! Bound to port '" + p + "' to handle ACME challenges and redirect to https");
}
resolve();
}).on('error', function (e) { }).on('error', function (e) {
if (plainServer.listenerCount('error') < 2) { if (plainServer.listenerCount('error') < 2) {
console.warn("Did not successfully create http server and bind to port '" + p + "':"); console.warn("Did not successfully create http server and bind to port '" + p + "':");
@ -55,18 +52,21 @@ module.exports.create = function (opts) {
return promise; return promise;
} }
function _listenHttps(port, sayAnything) { function _listenHttps(port) {
if (!port) { port = 443; } if (!port) { port = 443; }
var p = port; var p = port;
var validHttpsPort = (parseInt(p, 10) >= 0); var validHttpsPort = (parseInt(p, 10) >= 0);
var httpType;
if (!validHttpsPort) { console.warn("'" + p + "' doesn't seem to be a valid port number for https"); } if (!validHttpsPort) { console.warn("'" + p + "' doesn't seem to be a valid port number for https"); }
var https; var https;
try { try {
https = require('spdy'); https = require('spdy');
greenlock.tlsOptions.spdy = { protocols: [ 'h2', 'http/1.1' ], plain: false }; greenlock.tlsOptions.spdy = { protocols: [ 'h2', 'http/1.1' ], plain: false };
httpType = 'http2 (spdy/h2)';
} catch(e) { } catch(e) {
https = require('https'); https = require('https');
httpType = 'https';
} }
var server = https.createServer( var server = https.createServer(
greenlock.tlsOptions greenlock.tlsOptions
@ -79,11 +79,9 @@ module.exports.create = function (opts) {
} }
}) })
); );
server.type = httpType;
var promise = new PromiseA(function (resolve) { var promise = new PromiseA(function (resolve) {
server.listen(p, function () { server.listen(p, function () {
if (sayAnything) {
console.info("Success! Serving https on port '" + p + "'");
}
resolve(server); resolve(server);
}).on('error', function (e) { }).on('error', function (e) {
if (server.listenerCount('error') < 2) { if (server.listenerCount('error') < 2) {
@ -103,21 +101,44 @@ module.exports.create = function (opts) {
res.end("Hello, World!\nWith Love,\nGreenlock for Express.js"); res.end("Hello, World!\nWith Love,\nGreenlock for Express.js");
}; };
opts.listen = function (plainPort, port, fn) { opts.listen = function (plainPort, port, fn1, fn2) {
var promises = []; var promises = [];
var server; var server;
var plainServer;
promises.push(_listenHttp(plainPort, !fn)); var fn;
var fnPlain;
if (fn2) {
fn = fn2;
fnPlain = fn1;
} else {
fn = fn1;
}
promises.push(_listenHttp(plainPort, !fnPlain));
promises.push(_listenHttps(port, !fn)); promises.push(_listenHttps(port, !fn));
server = promises[1].server; server = promises[1].server;
plainServer = promises[0].server;
PromiseA.all(promises).then(function () { PromiseA.all(promises).then(function () {
// Report h2/https status
if ('function' === typeof fn) { if ('function' === typeof fn) {
fn.apply(server); fn.apply(server);
} else if (server.listenerCount('listening') < 2) {
console.info("Success! Serving " + server.type + " on port '" + server.address().port + "'");
}
// Report plain http status
if ('function' === typeof fnPlain) {
fnPlain.apply(plainServer);
} else if (!fn && plainServer.listenerCount('listening') < 2) {
console.info("Success! Bound to port '" + plainServer.address().port
+ "' to handle ACME challenges and redirect to " + server.type);
} }
return server;
}); });
server.unencrypted = plainServer;
return server; return server;
}; };

View File

@ -1,6 +1,6 @@
{ {
"name": "greenlock-express", "name": "greenlock-express",
"version": "2.4.0", "version": "2.4.1",
"description": "Free SSL and managed or automatic HTTPS for node.js with Express, Koa, Connect, Hapi, and all other middleware systems.", "description": "Free SSL and managed or automatic HTTPS for node.js with Express, Koa, Connect, Hapi, and all other middleware systems.",
"main": "index.js", "main": "index.js",
"homepage": "https://git.coolaj86.com/coolaj86/greenlock-express.js", "homepage": "https://git.coolaj86.com/coolaj86/greenlock-express.js",

View File

@ -16,7 +16,9 @@ var greenlock = Greenlock.create({
var server1 = greenlock.listen(5080, 5443); var server1 = greenlock.listen(5080, 5443);
server1.on('listening', function () { server1.on('listening', function () {
console.log("### THREE 3333 - All is well server1", this.address()); console.log("### THREE 3333 - All is well server1", this.address());
server1.close(); setTimeout(function () {
// so that the address() object doesn't disappear
}, 10);
}); });
setTimeout(function () { setTimeout(function () {
var server2 = greenlock.listen(6080, 6443, function () { var server2 = greenlock.listen(6080, 6443, function () {
@ -32,10 +34,21 @@ setTimeout(function () {
}); });
}, 1000); }, 1000);
var server3 = greenlock.listen(7080, 22, function () { var server3 = greenlock.listen(22, 22, function () {
// ignore console.error("Error: expected to get an error when launching plain server on port 22");
}, function () {
console.error("Error: expected to get an error when launching " + server3.type + " server on port 22");
});
server3.unencrypted.on('error', function () {
console.log("Success: caught expected (plain) error");
}); });
server3.on('error', function () { server3.on('error', function () {
console.log("Success: caught expected error"); console.log("Success: caught expected " + server3.type + " error");
server3.close(); //server3.close();
});
var server4 = greenlock.listen(7080, 7443, function () {
console.log('Success: server4: plain');
}, function () {
console.log('Success: server4: ' + server4.type);
}); });