@reldens/server-utils 0.44.0 → 0.46.0
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/.claude/api-reference.md +24 -1
- package/CLAUDE.md +1 -1
- package/lib/app-server-factory.js +39 -72
- package/lib/cdn-request-handler.js +2 -9
- package/lib/http2-cdn-server.js +106 -54
- package/package.json +3 -3
package/.claude/api-reference.md
CHANGED
|
@@ -77,6 +77,7 @@ Creates Express app servers with modular security components. Supports HTTP, HTT
|
|
|
77
77
|
- Lifecycle event dispatching
|
|
78
78
|
|
|
79
79
|
**Configuration Properties:**
|
|
80
|
+
- `http2CdnDomains` - Array of domain configurations for HTTP/2 CDN multi-certificate SNI (optional)
|
|
80
81
|
- `onError` - Custom error handler callback for server errors
|
|
81
82
|
- `onRequestSuccess` - Callback for successful requests
|
|
82
83
|
- `onRequestError` - Callback for failed requests
|
|
@@ -84,8 +85,11 @@ Creates Express app servers with modular security components. Supports HTTP, HTT
|
|
|
84
85
|
|
|
85
86
|
**Methods:**
|
|
86
87
|
- `createAppServer(config)` - Create and configure server
|
|
88
|
+
- `createHttp2CdnServer()` - Create HTTP/2 CDN server with optional multi-cert SNI
|
|
87
89
|
- `addDomain(domainConfig)` - Add virtual host domain
|
|
88
90
|
- `addDevelopmentDomain(domain)` - Add development domain
|
|
91
|
+
- `dispatch(eventName, eventData)` - Dispatch lifecycle event (wrapper for EventDispatcher)
|
|
92
|
+
- `handleError(errorType, error, context)` - Handle and log error (wrapper for ServerErrorHandler)
|
|
89
93
|
- `enableServeHome(app, callback)` - Enable homepage serving
|
|
90
94
|
- `serveStatics(app, staticPath)` - Serve static files
|
|
91
95
|
- `enableCSP(cspOptions)` - Enable Content Security Policy
|
|
@@ -157,6 +161,7 @@ File upload handling with Multer.
|
|
|
157
161
|
HTTP/2 secure server for CDN-like static file serving.
|
|
158
162
|
|
|
159
163
|
**Features:**
|
|
164
|
+
- Multi-certificate SNI support for multiple domains
|
|
160
165
|
- Optimized for CSS, JavaScript, images, and fonts
|
|
161
166
|
- Dynamic CORS origin validation with regex pattern support
|
|
162
167
|
- Configurable cache headers per file extension
|
|
@@ -167,19 +172,37 @@ HTTP/2 secure server for CDN-like static file serving.
|
|
|
167
172
|
- Comprehensive error handling (server, TLS, session, stream errors)
|
|
168
173
|
|
|
169
174
|
**Configuration Properties:**
|
|
175
|
+
- `domains` - Array of domain configurations for multi-certificate SNI (optional)
|
|
176
|
+
- `keyPath` - Path to SSL key file (backward compatibility, single cert mode)
|
|
177
|
+
- `certPath` - Path to SSL certificate file (backward compatibility, single cert mode)
|
|
170
178
|
- `onError` - Custom error handler callback for server errors
|
|
171
179
|
- `onRequestSuccess` - Callback for successful requests
|
|
172
180
|
- `onRequestError` - Callback for failed requests
|
|
173
181
|
- `onEvent` - Callback for lifecycle events
|
|
174
182
|
|
|
183
|
+
**Multi-Certificate Configuration Example:**
|
|
184
|
+
```javascript
|
|
185
|
+
domains: [
|
|
186
|
+
{hostname: 'cdn.domain1.com', keyPath: '/path/to/key1.pem', certPath: '/path/to/cert1.pem'},
|
|
187
|
+
{hostname: 'cdn.domain2.com', keyPath: '/path/to/key2.pem', certPath: '/path/to/cert2.pem'}
|
|
188
|
+
]
|
|
189
|
+
```
|
|
190
|
+
|
|
175
191
|
**Methods:**
|
|
176
|
-
- `create()` - Create HTTP/2 secure server
|
|
192
|
+
- `create()` - Create HTTP/2 secure server with SNI support
|
|
177
193
|
- `listen()` - Start listening on configured port
|
|
178
194
|
- `close()` - Gracefully close server
|
|
195
|
+
- `dispatch(eventName, eventData)` - Dispatch lifecycle event (wrapper for EventDispatcher)
|
|
196
|
+
- `handleError(errorType, error, context)` - Handle and log error (wrapper for ServerErrorHandler)
|
|
179
197
|
- `handleStream(stream, headers)` - Handle HTTP/2 stream
|
|
180
198
|
- `handleHttp1Request(req, res)` - Handle HTTP/1.1 fallback requests
|
|
181
199
|
- `resolveFilePath(requestPath)` - Resolve file path from request
|
|
182
200
|
- `setupEventHandlers()` - Configure server error event handlers
|
|
201
|
+
- `setupDomainConfiguration()` - Configure single or multi-certificate mode
|
|
202
|
+
- `validateCertificates()` - Validate all domain certificates exist
|
|
203
|
+
- `buildSniContexts()` - Build TLS contexts for each domain
|
|
204
|
+
- `getSniCallback()` - Get SNI callback for certificate selection
|
|
205
|
+
- `buildServerOptions()` - Build HTTP/2 server options with SNI support
|
|
183
206
|
|
|
184
207
|
## Utility Classes
|
|
185
208
|
|
package/CLAUDE.md
CHANGED
|
@@ -39,7 +39,7 @@ See `.claude/api-reference.md` for complete API documentation of all classes and
|
|
|
39
39
|
|
|
40
40
|
**UploaderFactory** - File upload handling with Multer and multi-level security validation.
|
|
41
41
|
|
|
42
|
-
**Http2CdnServer** - HTTP/2 secure server for CDN-like static file serving with CORS, cache headers, and callback-based logging.
|
|
42
|
+
**Http2CdnServer** - HTTP/2 secure server for CDN-like static file serving with multi-certificate SNI support, CORS, cache headers, and callback-based logging.
|
|
43
43
|
|
|
44
44
|
## Utility Classes Summary
|
|
45
45
|
|
|
@@ -115,13 +115,26 @@ class AppServerFactory
|
|
|
115
115
|
this.http2CdnCorsAllowAll = false;
|
|
116
116
|
this.http2CdnMimeTypes = {};
|
|
117
117
|
this.http2CdnCacheConfig = {};
|
|
118
|
+
this.http2CdnSecurityHeaders = {};
|
|
118
119
|
this.http2CdnServer = false;
|
|
120
|
+
this.http2CdnDomains = [];
|
|
119
121
|
this.reverseProxyEnabled = false;
|
|
120
122
|
this.reverseProxyRules = [];
|
|
121
123
|
this.onError = null;
|
|
122
124
|
this.onRequestSuccess = null;
|
|
123
125
|
this.onRequestError = null;
|
|
124
126
|
this.onEvent = null;
|
|
127
|
+
this.eventSource = 'appServerFactory';
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
dispatch(eventName, eventData)
|
|
131
|
+
{
|
|
132
|
+
EventDispatcher.dispatch(this.onEvent, eventName, this.eventSource, this, eventData);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
handleError(errorType, error, context)
|
|
136
|
+
{
|
|
137
|
+
ServerErrorHandler.handleError(this.onError, this.eventSource, this, errorType, error, context);
|
|
125
138
|
}
|
|
126
139
|
|
|
127
140
|
buildStaticHeaders(res, path)
|
|
@@ -167,13 +180,11 @@ class AppServerFactory
|
|
|
167
180
|
}
|
|
168
181
|
return false;
|
|
169
182
|
}
|
|
170
|
-
|
|
171
|
-
this.
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
{port: this.port, useHttps: this.useHttps, isDevelopmentMode: this.isDevelopmentMode}
|
|
176
|
-
);
|
|
183
|
+
this.dispatch('app-server-created', {
|
|
184
|
+
port: this.port,
|
|
185
|
+
useHttps: this.useHttps,
|
|
186
|
+
isDevelopmentMode: this.isDevelopmentMode
|
|
187
|
+
});
|
|
177
188
|
if(this.http2CdnEnabled){
|
|
178
189
|
if(!this.createHttp2CdnServer()){
|
|
179
190
|
this.error = {message: 'The createHttp2CdnServer() returned false.'};
|
|
@@ -191,9 +202,14 @@ class AppServerFactory
|
|
|
191
202
|
this.http2CdnServer = new Http2CdnServer();
|
|
192
203
|
this.http2CdnServer.enabled = this.http2CdnEnabled;
|
|
193
204
|
this.http2CdnServer.port = this.http2CdnPort;
|
|
194
|
-
this.
|
|
195
|
-
|
|
196
|
-
|
|
205
|
+
if(this.http2CdnDomains && 0 < this.http2CdnDomains.length){
|
|
206
|
+
this.http2CdnServer.domains = this.http2CdnDomains;
|
|
207
|
+
}
|
|
208
|
+
if(!this.http2CdnDomains || 0 === this.http2CdnDomains.length){
|
|
209
|
+
this.http2CdnServer.keyPath = this.http2CdnKeyPath || this.keyPath;
|
|
210
|
+
this.http2CdnServer.certPath = this.http2CdnCertPath || this.certPath;
|
|
211
|
+
this.http2CdnServer.httpsChain = this.http2CdnHttpsChain || this.httpsChain;
|
|
212
|
+
}
|
|
197
213
|
this.http2CdnServer.staticPaths = this.http2CdnStaticPaths;
|
|
198
214
|
this.http2CdnServer.cacheConfig = this.http2CdnCacheConfig && 0 < Object.keys(this.http2CdnCacheConfig).length
|
|
199
215
|
? this.http2CdnCacheConfig
|
|
@@ -203,6 +219,9 @@ class AppServerFactory
|
|
|
203
219
|
}
|
|
204
220
|
this.http2CdnServer.corsOrigins = this.http2CdnCorsOrigins;
|
|
205
221
|
this.http2CdnServer.corsAllowAll = this.http2CdnCorsAllowAll;
|
|
222
|
+
if(this.http2CdnSecurityHeaders && 0 < Object.keys(this.http2CdnSecurityHeaders).length){
|
|
223
|
+
this.http2CdnServer.securityHeaders = this.http2CdnSecurityHeaders;
|
|
224
|
+
}
|
|
206
225
|
this.http2CdnServer.onError = this.onError;
|
|
207
226
|
this.http2CdnServer.onRequestSuccess = this.onRequestSuccess;
|
|
208
227
|
this.http2CdnServer.onRequestError = this.onRequestError;
|
|
@@ -215,13 +234,7 @@ class AppServerFactory
|
|
|
215
234
|
this.error = this.http2CdnServer.error;
|
|
216
235
|
return false;
|
|
217
236
|
}
|
|
218
|
-
|
|
219
|
-
this.onEvent,
|
|
220
|
-
'http2-cdn-created',
|
|
221
|
-
'appServerFactory',
|
|
222
|
-
this,
|
|
223
|
-
{port: this.http2CdnPort}
|
|
224
|
-
);
|
|
237
|
+
this.dispatch('http2-cdn-created', {port: this.http2CdnPort});
|
|
225
238
|
return true;
|
|
226
239
|
}
|
|
227
240
|
|
|
@@ -430,14 +443,7 @@ class AppServerFactory
|
|
|
430
443
|
return next();
|
|
431
444
|
}
|
|
432
445
|
this.error = {message: 'No hostname provided and no default domain configured'};
|
|
433
|
-
|
|
434
|
-
this.onError,
|
|
435
|
-
'appServerFactory',
|
|
436
|
-
this,
|
|
437
|
-
'virtual-host-no-hostname',
|
|
438
|
-
this.error,
|
|
439
|
-
{request: req, response: res}
|
|
440
|
-
);
|
|
446
|
+
this.handleError('virtual-host-no-hostname', this.error, {request: req, response: res});
|
|
441
447
|
return res.status(400).send('Bad Request');
|
|
442
448
|
}
|
|
443
449
|
let domain = this.findDomainConfig(hostname);
|
|
@@ -447,10 +453,7 @@ class AppServerFactory
|
|
|
447
453
|
return next();
|
|
448
454
|
}
|
|
449
455
|
this.error = {message: 'Unknown domain: '+hostname};
|
|
450
|
-
|
|
451
|
-
this.onError,
|
|
452
|
-
'appServerFactory',
|
|
453
|
-
this,
|
|
456
|
+
this.handleError(
|
|
454
457
|
'virtual-host-unknown-domain',
|
|
455
458
|
this.error,
|
|
456
459
|
{hostname: hostname, request: req, response: res}
|
|
@@ -485,13 +488,7 @@ class AppServerFactory
|
|
|
485
488
|
{
|
|
486
489
|
if(!this.useHttps){
|
|
487
490
|
let httpServer = http.createServer(this.app);
|
|
488
|
-
|
|
489
|
-
this.onEvent,
|
|
490
|
-
'http-server-created',
|
|
491
|
-
'appServerFactory',
|
|
492
|
-
this,
|
|
493
|
-
{port: this.port}
|
|
494
|
-
);
|
|
491
|
+
this.dispatch('http-server-created', {port: this.port});
|
|
495
492
|
return httpServer;
|
|
496
493
|
}
|
|
497
494
|
if(this.useVirtualHosts && 0 < this.domains.length){
|
|
@@ -520,13 +517,7 @@ class AppServerFactory
|
|
|
520
517
|
}
|
|
521
518
|
}
|
|
522
519
|
let httpsServer = https.createServer(credentials, this.app);
|
|
523
|
-
|
|
524
|
-
this.onEvent,
|
|
525
|
-
'https-server-created',
|
|
526
|
-
'appServerFactory',
|
|
527
|
-
this,
|
|
528
|
-
{port: this.port}
|
|
529
|
-
);
|
|
520
|
+
this.dispatch('https-server-created', {port: this.port});
|
|
530
521
|
return httpsServer;
|
|
531
522
|
}
|
|
532
523
|
|
|
@@ -545,10 +536,7 @@ class AppServerFactory
|
|
|
545
536
|
let key = FileHandler.readFile(domain.keyPath, 'Domain Key');
|
|
546
537
|
if(!key){
|
|
547
538
|
this.error = {message: 'Could not read domain SSL key: '+domain.keyPath};
|
|
548
|
-
|
|
549
|
-
this.onError,
|
|
550
|
-
'appServerFactory',
|
|
551
|
-
this,
|
|
539
|
+
this.handleError(
|
|
552
540
|
'sni-key-read-failure',
|
|
553
541
|
this.error,
|
|
554
542
|
{hostname: hostname, domain: domain, keyPath: domain.keyPath}
|
|
@@ -558,10 +546,7 @@ class AppServerFactory
|
|
|
558
546
|
let cert = FileHandler.readFile(domain.certPath, 'Domain Cert');
|
|
559
547
|
if(!cert){
|
|
560
548
|
this.error = {message: 'Could not read domain SSL certificate: '+domain.certPath};
|
|
561
|
-
|
|
562
|
-
this.onError,
|
|
563
|
-
'appServerFactory',
|
|
564
|
-
this,
|
|
549
|
+
this.handleError(
|
|
565
550
|
'sni-cert-read-failure',
|
|
566
551
|
this.error,
|
|
567
552
|
{hostname: hostname, domain: domain, certPath: domain.certPath}
|
|
@@ -572,13 +557,7 @@ class AppServerFactory
|
|
|
572
557
|
callback(null, ctx);
|
|
573
558
|
};
|
|
574
559
|
let sniServer = https.createServer(httpsOptions, this.app);
|
|
575
|
-
|
|
576
|
-
this.onEvent,
|
|
577
|
-
'sni-server-created',
|
|
578
|
-
'appServerFactory',
|
|
579
|
-
this,
|
|
580
|
-
{port: this.port, domainsCount: this.domains.length}
|
|
581
|
-
);
|
|
560
|
+
this.dispatch('sni-server-created', {port: this.port, domainsCount: this.domains.length});
|
|
582
561
|
return sniServer;
|
|
583
562
|
}
|
|
584
563
|
|
|
@@ -605,13 +584,7 @@ class AppServerFactory
|
|
|
605
584
|
return false;
|
|
606
585
|
}
|
|
607
586
|
this.appServer.listen(listenPort);
|
|
608
|
-
|
|
609
|
-
this.onEvent,
|
|
610
|
-
'app-server-listening',
|
|
611
|
-
'appServerFactory',
|
|
612
|
-
this,
|
|
613
|
-
{port: listenPort}
|
|
614
|
-
);
|
|
587
|
+
this.dispatch('app-server-listening', {port: listenPort});
|
|
615
588
|
return true;
|
|
616
589
|
}
|
|
617
590
|
|
|
@@ -673,13 +646,7 @@ class AppServerFactory
|
|
|
673
646
|
return false;
|
|
674
647
|
}
|
|
675
648
|
this.domains.push(domainConfig);
|
|
676
|
-
|
|
677
|
-
this.onEvent,
|
|
678
|
-
'domain-added',
|
|
679
|
-
'appServerFactory',
|
|
680
|
-
this,
|
|
681
|
-
{hostname: domainConfig.hostname}
|
|
682
|
-
);
|
|
649
|
+
this.dispatch('domain-added', {hostname: domainConfig.hostname});
|
|
683
650
|
return true;
|
|
684
651
|
}
|
|
685
652
|
|
|
@@ -6,7 +6,6 @@
|
|
|
6
6
|
|
|
7
7
|
const { FileHandler } = require('./file-handler');
|
|
8
8
|
const { ServerFactoryUtils } = require('./server-factory-utils');
|
|
9
|
-
const { ServerErrorHandler } = require('./server-error-handler');
|
|
10
9
|
|
|
11
10
|
class CdnRequestHandler
|
|
12
11
|
{
|
|
@@ -62,10 +61,7 @@ class CdnRequestHandler
|
|
|
62
61
|
requestData.statusCode = 500;
|
|
63
62
|
requestData.responseTime = Date.now()-startTime;
|
|
64
63
|
requestData.error = err;
|
|
65
|
-
|
|
66
|
-
this.cdnServer.onError,
|
|
67
|
-
'http2CdnServer',
|
|
68
|
-
this.cdnServer,
|
|
64
|
+
this.cdnServer.handleError(
|
|
69
65
|
requestContext.isHttp2 ? 'stream-error' : 'http1-stream-error',
|
|
70
66
|
err,
|
|
71
67
|
{port: this.cdnServer.port, path: requestData.path}
|
|
@@ -77,10 +73,7 @@ class CdnRequestHandler
|
|
|
77
73
|
requestData.statusCode = 500;
|
|
78
74
|
requestData.responseTime = Date.now()-startTime;
|
|
79
75
|
requestData.error = err;
|
|
80
|
-
|
|
81
|
-
this.cdnServer.onError,
|
|
82
|
-
'http2CdnServer',
|
|
83
|
-
this.cdnServer,
|
|
76
|
+
this.cdnServer.handleError(
|
|
84
77
|
requestContext.isHttp2 ? 'handle-stream-error' : 'handle-http1-request-error',
|
|
85
78
|
err,
|
|
86
79
|
{port: this.cdnServer.port, path: requestData.path}
|
package/lib/http2-cdn-server.js
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
const http2 = require('http2');
|
|
8
|
+
const tls = require('tls');
|
|
8
9
|
const { FileHandler } = require('./file-handler');
|
|
9
10
|
const { ServerDefaultConfigurations } = require('./server-default-configurations');
|
|
10
11
|
const { ServerFactoryUtils } = require('./server-factory-utils');
|
|
@@ -41,22 +42,112 @@ class Http2CdnServer
|
|
|
41
42
|
this.onRequestError = null;
|
|
42
43
|
this.onEvent = null;
|
|
43
44
|
this.requestHandler = new CdnRequestHandler(this);
|
|
45
|
+
this.domains = [];
|
|
46
|
+
this.useMultiCert = false;
|
|
47
|
+
this.defaultDomain = null;
|
|
48
|
+
this.sniContexts = {};
|
|
49
|
+
this.eventSource = 'http2CdnServer';
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
dispatch(eventName, eventData)
|
|
53
|
+
{
|
|
54
|
+
EventDispatcher.dispatch(this.onEvent, eventName, this.eventSource, this, eventData);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
handleError(errorType, error, context)
|
|
58
|
+
{
|
|
59
|
+
ServerErrorHandler.handleError(this.onError, this.eventSource, this, errorType, error, context);
|
|
44
60
|
}
|
|
45
61
|
|
|
46
62
|
create()
|
|
47
63
|
{
|
|
48
|
-
|
|
49
|
-
|
|
64
|
+
this.setupDomainConfiguration();
|
|
65
|
+
if(!this.validateCertificates()){
|
|
50
66
|
return false;
|
|
51
67
|
}
|
|
52
|
-
|
|
68
|
+
if(this.useMultiCert){
|
|
69
|
+
this.buildSniContexts();
|
|
70
|
+
}
|
|
71
|
+
let options = this.buildServerOptions();
|
|
72
|
+
if(!options){
|
|
73
|
+
return false;
|
|
74
|
+
}
|
|
75
|
+
this.http2Server = http2.createSecureServer(options);
|
|
76
|
+
this.setupEventHandlers();
|
|
77
|
+
this.dispatch(
|
|
78
|
+
'cdn-server-created',
|
|
79
|
+
{port: this.port, allowHTTP1: this.allowHTTP1, multiCert: this.useMultiCert})
|
|
80
|
+
;
|
|
81
|
+
return true;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
setupDomainConfiguration()
|
|
85
|
+
{
|
|
86
|
+
if(this.domains && 0 < this.domains.length){
|
|
87
|
+
this.useMultiCert = true;
|
|
88
|
+
this.defaultDomain = this.domains[0];
|
|
89
|
+
this.dispatch('cdn-multi-cert-enabled', {domains: this.domains.map(d => d.hostname)});
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
if(this.keyPath && this.certPath){
|
|
93
|
+
this.useMultiCert = false;
|
|
94
|
+
this.domains = [{hostname: 'default', keyPath: this.keyPath, certPath: this.certPath}];
|
|
95
|
+
this.defaultDomain = this.domains[0];
|
|
96
|
+
this.dispatch('cdn-single-cert-mode', {hostname: this.defaultDomain.hostname});
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
this.error = {message: 'HTTP/2 CDN requires domains array or keyPath/certPath'};
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
validateCertificates()
|
|
103
|
+
{
|
|
104
|
+
for(let domain of this.domains){
|
|
105
|
+
if(!FileHandler.exists(domain.keyPath)){
|
|
106
|
+
this.error = {message: 'Certificate key not found for '+domain.hostname+': '+domain.keyPath};
|
|
107
|
+
this.handleError('certificate-key-not-found', this.error, {hostname: domain.hostname, keyPath: domain.keyPath});
|
|
108
|
+
return false;
|
|
109
|
+
}
|
|
110
|
+
if(!FileHandler.exists(domain.certPath)){
|
|
111
|
+
this.error = {message: 'Certificate file not found for '+domain.hostname+': '+domain.certPath};
|
|
112
|
+
this.handleError('certificate-not-found', this.error, {hostname: domain.hostname, certPath: domain.certPath});
|
|
113
|
+
return false;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
return true;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
buildSniContexts()
|
|
120
|
+
{
|
|
121
|
+
for(let domain of this.domains){
|
|
122
|
+
let key = FileHandler.readFile(domain.keyPath);
|
|
123
|
+
let cert = FileHandler.readFile(domain.certPath);
|
|
124
|
+
this.sniContexts[domain.hostname] = tls.createSecureContext({key, cert});
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
getSniCallback()
|
|
129
|
+
{
|
|
130
|
+
return (servername, callback) => {
|
|
131
|
+
this.dispatch('cdn-sni-request', {servername});
|
|
132
|
+
let context = this.sniContexts[servername];
|
|
133
|
+
if(!context){
|
|
134
|
+
this.dispatch('cdn-sni-fallback', {servername, defaultHostname: this.defaultDomain.hostname});
|
|
135
|
+
context = this.sniContexts[this.defaultDomain.hostname];
|
|
136
|
+
}
|
|
137
|
+
callback(null, context);
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
buildServerOptions()
|
|
142
|
+
{
|
|
143
|
+
let key = FileHandler.readFile(this.defaultDomain.keyPath);
|
|
53
144
|
if(!key){
|
|
54
|
-
this.error = {message: 'Could not read key from: '+this.keyPath};
|
|
145
|
+
this.error = {message: 'Could not read key from: '+this.defaultDomain.keyPath};
|
|
55
146
|
return false;
|
|
56
147
|
}
|
|
57
|
-
let cert = FileHandler.readFile(this.certPath);
|
|
148
|
+
let cert = FileHandler.readFile(this.defaultDomain.certPath);
|
|
58
149
|
if(!cert){
|
|
59
|
-
this.error = {message: 'Could not read cert from: '+this.certPath};
|
|
150
|
+
this.error = {message: 'Could not read cert from: '+this.defaultDomain.certPath};
|
|
60
151
|
return false;
|
|
61
152
|
}
|
|
62
153
|
let options = {key, cert, allowHTTP1: this.allowHTTP1};
|
|
@@ -66,16 +157,10 @@ class Http2CdnServer
|
|
|
66
157
|
options.ca = ca;
|
|
67
158
|
}
|
|
68
159
|
}
|
|
69
|
-
this.
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
'cdn-server-created',
|
|
74
|
-
'http2CdnServer',
|
|
75
|
-
this,
|
|
76
|
-
{port: this.port, allowHTTP1: this.allowHTTP1}
|
|
77
|
-
);
|
|
78
|
-
return true;
|
|
160
|
+
if(this.useMultiCert){
|
|
161
|
+
options.SNICallback = this.getSniCallback();
|
|
162
|
+
}
|
|
163
|
+
return options;
|
|
79
164
|
}
|
|
80
165
|
|
|
81
166
|
setupEventHandlers()
|
|
@@ -87,42 +172,15 @@ class Http2CdnServer
|
|
|
87
172
|
this.handleHttp1Request(req, res);
|
|
88
173
|
});
|
|
89
174
|
this.http2Server.on('error', (err) => {
|
|
90
|
-
|
|
91
|
-
this.onError,
|
|
92
|
-
'http2CdnServer',
|
|
93
|
-
this,
|
|
94
|
-
'server-error',
|
|
95
|
-
err,
|
|
96
|
-
{port: this.port}
|
|
97
|
-
);
|
|
175
|
+
this.handleError('server-error', err, {port: this.port});
|
|
98
176
|
});
|
|
99
177
|
this.http2Server.on('tlsClientError', (err, tlsSocket) => {
|
|
100
|
-
|
|
101
|
-
this.onError,
|
|
102
|
-
'http2CdnServer',
|
|
103
|
-
this,
|
|
104
|
-
'tls-client-error',
|
|
105
|
-
err,
|
|
106
|
-
{port: this.port, remoteAddress: tlsSocket.remoteAddress}
|
|
107
|
-
);
|
|
178
|
+
this.handleError('tls-client-error', err, {port: this.port, remoteAddress: tlsSocket.remoteAddress});
|
|
108
179
|
});
|
|
109
180
|
this.http2Server.on('sessionError', (err) => {
|
|
110
|
-
|
|
111
|
-
this.onError,
|
|
112
|
-
'http2CdnServer',
|
|
113
|
-
this,
|
|
114
|
-
'session-error',
|
|
115
|
-
err,
|
|
116
|
-
{port: this.port}
|
|
117
|
-
);
|
|
181
|
+
this.handleError('session-error', err, {port: this.port});
|
|
118
182
|
});
|
|
119
|
-
|
|
120
|
-
this.onEvent,
|
|
121
|
-
'cdn-handlers-setup',
|
|
122
|
-
'http2CdnServer',
|
|
123
|
-
this,
|
|
124
|
-
{port: this.port}
|
|
125
|
-
);
|
|
183
|
+
this.dispatch('cdn-handlers-setup', {port: this.port});
|
|
126
184
|
}
|
|
127
185
|
|
|
128
186
|
invokeRequestSuccess(requestData)
|
|
@@ -246,13 +304,7 @@ class Http2CdnServer
|
|
|
246
304
|
return false;
|
|
247
305
|
}
|
|
248
306
|
this.http2Server.listen(this.port);
|
|
249
|
-
|
|
250
|
-
this.onEvent,
|
|
251
|
-
'cdn-server-listening',
|
|
252
|
-
'http2CdnServer',
|
|
253
|
-
this,
|
|
254
|
-
{port: this.port}
|
|
255
|
-
);
|
|
307
|
+
this.dispatch('cdn-server-listening', {port: this.port});
|
|
256
308
|
return true;
|
|
257
309
|
}
|
|
258
310
|
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@reldens/server-utils",
|
|
3
3
|
"scope": "@reldens",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.46.0",
|
|
5
5
|
"description": "Reldens - Server Utils",
|
|
6
6
|
"author": "Damian A. Pastorini",
|
|
7
7
|
"license": "MIT",
|
|
@@ -38,10 +38,10 @@
|
|
|
38
38
|
"dependencies": {
|
|
39
39
|
"body-parser": "2.2.2",
|
|
40
40
|
"compression": "1.8.1",
|
|
41
|
-
"cors": "2.8.
|
|
41
|
+
"cors": "2.8.6",
|
|
42
42
|
"express": "4.22.1",
|
|
43
43
|
"express-rate-limit": "8.2.1",
|
|
44
|
-
"express-session": "1.
|
|
44
|
+
"express-session": "1.19.0",
|
|
45
45
|
"helmet": "8.1.0",
|
|
46
46
|
"http-proxy-middleware": "3.0.5",
|
|
47
47
|
"multer": "2.0.2",
|