diff --git a/README.md b/README.md index 2522b75..1c8758a 100644 --- a/README.md +++ b/README.md @@ -410,7 +410,13 @@ The API is actually located at [greenlock.js options](https://git.coolaj86.com/c The only "API" consists of two options, the rest is just a wrapper around `greenlock.js` to take LOC from 15 to 5: * `opts.app` An express app in the format `function (req, res) { ... }` (no `next`). -* `server = glx.listen(plainPort, tlsPort)` Accepts port numbers (or arrays of port numbers) to listen on, returns secure server. +* `server = glx.listen(plainAddr, tlsAddr, onListen)` Accepts port numbers (or arrays of port numbers) to listen on, returns secure server. + * `listen(80, 443)` + * `listen(80, 443, onListenSecure)` + * `listen(80, 443, onListenPlain, onListenSecure)` + * `listen('localhost:80', '0.0.0.0:443')` + * `listen('[::1]:80', '[::]:443')` + * `listen('/tmp/glx.plain.sock', '/tmp/glx.secure.sock')` Brief overview of some simple options for `greenlock.js`: diff --git a/index.js b/index.js index 9e77029..df9a806 100644 --- a/index.js +++ b/index.js @@ -29,68 +29,66 @@ module.exports.create = function (opts) { console.error(e.code + ": '" + e.address + ":" + e.port + "'"); } - function _listenHttp(plainPort) { + function _listen(plainPort, plain) { if (!plainPort) { plainPort = 80; } - var p = plainPort; + + var parts = String(plainPort).split(':'); + var p = parts.pop(); + var addr = parts.join(':').replace(/^\[/, '').replace(/\]$/, ''); + var args = []; + var httpType; + var server; var validHttpPort = (parseInt(p, 10) >= 0); - if (!validHttpPort) { console.warn("'" + p + "' doesn't seem to be a valid port number for http"); } - var plainServer = require('http').createServer( - greenlock.middleware.sanitizeHost(greenlock.middleware(require('redirect-https')())) - ); + + function tryPlain() { + server = require('http').createServer( + greenlock.middleware.sanitizeHost(greenlock.middleware(require('redirect-https')())) + ); + httpType = 'http'; + } + + function trySecure() { + var https; + try { + https = require('spdy'); + greenlock.tlsOptions.spdy = { protocols: [ 'h2', 'http/1.1' ], plain: false }; + httpType = 'http2 (spdy/h2)'; + } catch(e) { + https = require('https'); + httpType = 'https'; + } + server = https.createServer( + greenlock.tlsOptions + , greenlock.middleware.sanitizeHost(function (req, res) { + try { + greenlock.app(req, res); + } catch(e) { + console.error("[error] [greenlock.app] Your HTTP handler had an uncaught error:"); + console.error(e); + } + }) + ); + server.type = httpType; + } + + if (addr) { args[1] = addr; } + if (!validHttpPort && !/(\/)|(\\\\)/.test(p)) { + console.warn("'" + p + "' doesn't seem to be a valid port number, socket path, or pipe"); + } + if (plain) { tryPlain(); } else { trySecure(); } + var promise = new PromiseA(function (resolve) { - plainServer.listen(p, function () { - resolve(plainServer); - }).on('error', function (e) { - if (plainServer.listenerCount('error') < 2) { + args[0] = p; + args.push(function () { resolve(server); }); + server.listen.apply(server, args).on('error', function (e) { + if (server.listenerCount('error') < 2) { console.warn("Did not successfully create http server and bind to port '" + p + "':"); explainError(e); process.exit(41); } }); }); - promise.server = plainServer; - return promise; - } - function _listenHttps(port) { - if (!port) { port = 443; } - - var p = port; - var validHttpsPort = (parseInt(p, 10) >= 0); - var httpType; - if (!validHttpsPort) { console.warn("'" + p + "' doesn't seem to be a valid port number for https"); } - var https; - try { - https = require('spdy'); - greenlock.tlsOptions.spdy = { protocols: [ 'h2', 'http/1.1' ], plain: false }; - httpType = 'http2 (spdy/h2)'; - } catch(e) { - https = require('https'); - httpType = 'https'; - } - var server = https.createServer( - greenlock.tlsOptions - , greenlock.middleware.sanitizeHost(function (req, res) { - try { - greenlock.app(req, res); - } catch(e) { - console.error("[error] [greenlock.app] Your HTTP handler had an uncaught error:"); - console.error(e); - } - }) - ); - server.type = httpType; - var promise = new PromiseA(function (resolve) { - server.listen(p, function () { - resolve(server); - }).on('error', function (e) { - if (server.listenerCount('error') < 2) { - console.warn("Did not successfully create https server and bind to port '" + p + "':"); - explainError(e); - process.exit(43); - } - }); - }); promise.server = server; return promise; } @@ -101,40 +99,36 @@ module.exports.create = function (opts) { res.end("Hello, World!\nWith Love,\nGreenlock for Express.js"); }; - opts.listen = function (plainPort, port, fn1, fn2) { + opts.listen = function (plainPort, port, fnPlain, fn) { var promises = []; var server; var plainServer; - var fn; - var fnPlain; - if (fn2) { - fn = fn2; - fnPlain = fn1; - } else { - fn = fn1; + if (!fn) { + fn = fnPlain; + fnPlain = null; } - promises.push(_listenHttp(plainPort, !fnPlain)); - promises.push(_listenHttps(port, !fn)); + promises.push(_listen(plainPort, true)); + promises.push(_listen(port, false)); server = promises[1].server; plainServer = promises[0].server; PromiseA.all(promises).then(function () { - // Report h2/https status - if ('function' === typeof fn) { - 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); + console.info('[:' + (plainServer.address().port || plainServer.address()) + + "] Handling ACME challenges and redirecting to " + server.type); + } + + // Report h2/https status + if ('function' === typeof fn) { + fn.apply(server); + } else if (server.listenerCount('listening') < 2) { + console.info('[:' + (server.address().port || server.address()) + "] Serving " + server.type); } }); diff --git a/package.json b/package.json index 53964dd..6ecad7d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "greenlock-express", - "version": "2.4.1", + "version": "2.4.2", "description": "Free SSL and managed or automatic HTTPS for node.js with Express, Koa, Connect, Hapi, and all other middleware systems.", "main": "index.js", "homepage": "https://git.coolaj86.com/coolaj86/greenlock-express.js", diff --git a/test/greenlock.js b/test/greenlock.js index c8ef4b7..37b1973 100644 --- a/test/greenlock.js +++ b/test/greenlock.js @@ -18,6 +18,8 @@ server1.on('listening', function () { console.log("### THREE 3333 - All is well server1", this.address()); setTimeout(function () { // so that the address() object doesn't disappear + server1.close(); + server1.unencrypted.close(); }, 10); }); setTimeout(function () { @@ -25,8 +27,15 @@ setTimeout(function () { console.log("### FIVE 55555 - Started server 2!"); setTimeout(function () { server2.close(); - // TODO greenlock needs a close event (and to listen to its server's close event) - process.exit(0); + server2.unencrypted.close(); + server6.close(); + server6.unencrypted.close(); + server7.close(); + server7.unencrypted.close(); + setTimeout(function () { + // TODO greenlock needs a close event (and to listen to its server's close event) + process.exit(0); + }, 1000); }, 1000); }); server2.on('listening', function () { @@ -49,6 +58,18 @@ server3.on('error', function () { var server4 = greenlock.listen(7080, 7443, function () { console.log('Success: server4: plain'); + server4.unencrypted.close(); }, function () { console.log('Success: server4: ' + server4.type); + server4.close(); }); + +var server5 = greenlock.listen(10080, 10443, function () { + console.log("Server 5 with one fn", this.address()); + server5.close(); + server5.unencrypted.close(); +}); + +var server6 = greenlock.listen('[::]:11080', '[::1]:11443'); + +var server7 = greenlock.listen('/tmp/gl.plain.sock', '/tmp/gl.sec.sock');