This repository has been archived by the owner on Nov 17, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 17
/
SNIServer.js
111 lines (91 loc) · 2.49 KB
/
SNIServer.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
'use strict';
const https = require('https');
const tls = require('tls');
const debug = require('debug', 'beame:sni');
const config = require('../../config/Config');
const logger = new (require('../utils/Logger'))(config.AppModules.SNIServer);
const servers = {};
const portRegex = /:.*/;
class SNIServer {
// TODO: static method SNIServer.something instead of getSNIServer function below
constructor(port, requestListener) {
this.port = port;
this.hosts = {};
this.requestListener = requestListener || this.requestHandler.bind(this);
this.server = null;
this.started = false;
}
//noinspection JSUnusedGlobalSymbols
start(callback) {
if (this.started) {
callback();
return;
}
this.server = https.createServer({
SNICallback: this.SNICallback.bind(this)
}, this.requestListener);
this.server.listen(this.port, callback);
for (let host in this.hosts) {
//noinspection JSUnfilteredForInLoop
logger.info(`starting server on ${host}`);
}
this.started = true;
}
getServer() {
return this.server;
};
getPort() {
return this.server.address().port;
};
addFqdn(fqdn, certs, listener) {
if (!this.hosts[fqdn]) {
this.hosts[fqdn] = {};
}
this.hosts[fqdn].certs = certs;
if (listener) {
this.addListener(fqdn, listener);
}
}
requestHandler(req, res) {
debug('requestHandler() headers=%j', req.headers);
if(!req.headers.host) {
logger.warn("SNIServer: Failed to extract host header", req.headers);
return null;
}
const host = req.headers.host.replace(portRegex, '');
if (!this.hosts[host]) {
return null;
}
return this.hosts[host].listener(req, res);
}
addListener(fqdn, listener) {
if (!this.hosts[fqdn]) {
this.hosts[fqdn] = {};
}
this.hosts[fqdn].listener = listener;
}
getSecureContext(servername) {
if (!this.hosts[servername]) {
logger.error(`SNIServer.getSecureContext: Host ${servername} is unknown`);
return null;
}
if (!this.hosts[servername].secureContext) {
this.hosts[servername].secureContext = tls.createSecureContext(this.hosts[servername].certs);
}
return this.hosts[servername].secureContext;
}
SNICallback(servername, cb) {
if (!this.hosts[servername]) {
cb(`Host ${servername} is unknown`, null);
return;
}
cb(null, this.getSecureContext(servername));
}
static get(port, requestListener) {
if (!servers[port]) {
servers[port] = new SNIServer(port, requestListener);
}
return servers[port];
}
}
module.exports = SNIServer;