ultimate-express 1.2.17 → 1.2.19
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 +2 -2
- package/package.json +1 -1
- package/src/application.js +15 -9
- package/src/response.js +38 -43
- package/src/router.js +11 -6
package/README.md
CHANGED
|
@@ -79,7 +79,7 @@ https.createServer({
|
|
|
79
79
|
|
|
80
80
|
You have to pass `uwsOptions` to the `express()` constructor:
|
|
81
81
|
```js
|
|
82
|
-
const express = require("
|
|
82
|
+
const express = require("ultimate-express");
|
|
83
83
|
|
|
84
84
|
const app = express({
|
|
85
85
|
uwsOptions: {
|
|
@@ -312,4 +312,4 @@ Any Express view engine should work. Here's list of engines we include in our te
|
|
|
312
312
|
- ✅ [express-dot-engine](https://npmjs.com/package/express-dot-engine)
|
|
313
313
|
- ✅ [express-art-template](https://npmjs.com/package/express-art-template)
|
|
314
314
|
- ✅ [express-handlebars](https://npmjs.com/package/express-handlebars)
|
|
315
|
-
- ✅ [swig](https://npmjs.com/package/swig)
|
|
315
|
+
- ✅ [swig](https://npmjs.com/package/swig)
|
package/package.json
CHANGED
package/src/application.js
CHANGED
|
@@ -183,7 +183,7 @@ class Application extends Router {
|
|
|
183
183
|
const matchedRoute = await this._routeRequest(request, response);
|
|
184
184
|
if(!matchedRoute && !response.headersSent && !response.aborted) {
|
|
185
185
|
response.status(404);
|
|
186
|
-
|
|
186
|
+
this._sendErrorPage(request, response, `Cannot ${request.method} ${request.path}`, false);
|
|
187
187
|
}
|
|
188
188
|
});
|
|
189
189
|
}
|
|
@@ -194,23 +194,29 @@ class Application extends Router {
|
|
|
194
194
|
callback = port;
|
|
195
195
|
port = 0;
|
|
196
196
|
}
|
|
197
|
+
const onListen = socket => {
|
|
198
|
+
if(!socket) {
|
|
199
|
+
let err = new Error('Failed to listen on port ' + port + '. No permission or address already in use.');
|
|
200
|
+
throw err;
|
|
201
|
+
}
|
|
202
|
+
this.port = uWS.us_socket_local_port(socket);
|
|
203
|
+
callback(this.port);
|
|
204
|
+
};
|
|
197
205
|
let fn = 'listen';
|
|
206
|
+
let args = [port];
|
|
198
207
|
if(typeof port !== 'number') {
|
|
199
208
|
if(!isNaN(Number(port))) {
|
|
200
209
|
port = Number(port);
|
|
210
|
+
args.push(onListen);
|
|
201
211
|
} else {
|
|
202
212
|
fn = 'listen_unix';
|
|
213
|
+
args.unshift(onListen);
|
|
203
214
|
}
|
|
215
|
+
} else {
|
|
216
|
+
args.push(onListen);
|
|
204
217
|
}
|
|
205
218
|
this.listenCalled = true;
|
|
206
|
-
this.uwsApp[fn](
|
|
207
|
-
if(!socket) {
|
|
208
|
-
let err = new Error('Failed to listen on port ' + port + '. No permission or address already in use.');
|
|
209
|
-
throw err;
|
|
210
|
-
}
|
|
211
|
-
this.port = uWS.us_socket_local_port(socket);
|
|
212
|
-
callback(this.port);
|
|
213
|
-
});
|
|
219
|
+
this.uwsApp[fn](...args);
|
|
214
220
|
}
|
|
215
221
|
|
|
216
222
|
address() {
|
package/src/response.js
CHANGED
|
@@ -116,19 +116,7 @@ module.exports = class Response extends Writable {
|
|
|
116
116
|
if(!this.headersSent) {
|
|
117
117
|
this.writeHead(this.statusCode);
|
|
118
118
|
this._res.writeStatus(this.statusCode.toString());
|
|
119
|
-
|
|
120
|
-
if(header === 'content-length') {
|
|
121
|
-
// if content-length is set, disable chunked transfer encoding, since size is known
|
|
122
|
-
this.chunkedTransfer = false;
|
|
123
|
-
this.totalSize = parseInt(this.headers[header]);
|
|
124
|
-
continue;
|
|
125
|
-
}
|
|
126
|
-
this._res.writeHeader(header, this.headers[header]);
|
|
127
|
-
}
|
|
128
|
-
if(!this.headers['content-type']) {
|
|
129
|
-
this._res.writeHeader('content-type', 'text/html' + (typeof chunk === 'string' ? `; charset=utf-8` : ''));
|
|
130
|
-
}
|
|
131
|
-
this.headersSent = true;
|
|
119
|
+
this.writeHeaders(typeof chunk === 'string');
|
|
132
120
|
}
|
|
133
121
|
if(!Buffer.isBuffer(chunk) && !(chunk instanceof ArrayBuffer)) {
|
|
134
122
|
chunk = Buffer.from(chunk);
|
|
@@ -184,6 +172,27 @@ module.exports = class Response extends Writable {
|
|
|
184
172
|
this.set(header, headers[header]);
|
|
185
173
|
}
|
|
186
174
|
}
|
|
175
|
+
writeHeaders(utf8) {
|
|
176
|
+
for(const header in this.headers) {
|
|
177
|
+
if(header === 'content-length') {
|
|
178
|
+
// if content-length is set, disable chunked transfer encoding, since size is known
|
|
179
|
+
this.chunkedTransfer = false;
|
|
180
|
+
this.totalSize = parseInt(this.headers[header]);
|
|
181
|
+
continue;
|
|
182
|
+
}
|
|
183
|
+
if(Array.isArray(this.headers[header])) {
|
|
184
|
+
for(let value of this.headers[header]) {
|
|
185
|
+
this._res.writeHeader(header, value);
|
|
186
|
+
}
|
|
187
|
+
} else {
|
|
188
|
+
this._res.writeHeader(header, this.headers[header]);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
if(!this.headers['content-type']) {
|
|
192
|
+
this._res.writeHeader('content-type', 'text/html' + (utf8 ? `; charset=utf-8` : ''));
|
|
193
|
+
}
|
|
194
|
+
this.headersSent = true;
|
|
195
|
+
}
|
|
187
196
|
_implicitHeader() {
|
|
188
197
|
// compatibility function
|
|
189
198
|
// usually should send headers but this is useless for us
|
|
@@ -212,16 +221,7 @@ module.exports = class Response extends Writable {
|
|
|
212
221
|
}
|
|
213
222
|
const fresh = this.req.fresh;
|
|
214
223
|
this._res.writeStatus(fresh ? '304' : this.statusCode.toString());
|
|
215
|
-
|
|
216
|
-
if(header === 'content-length') {
|
|
217
|
-
continue;
|
|
218
|
-
}
|
|
219
|
-
this._res.writeHeader(header, this.headers[header]);
|
|
220
|
-
}
|
|
221
|
-
if(!this.headers['content-type']) {
|
|
222
|
-
this._res.writeHeader('content-type', 'text/html' + (typeof data === 'string' ? `; charset=utf-8` : ''));
|
|
223
|
-
}
|
|
224
|
-
this.headersSent = true;
|
|
224
|
+
this.writeHeaders(true);
|
|
225
225
|
if(fresh) {
|
|
226
226
|
this._res.end();
|
|
227
227
|
this.finished = true;
|
|
@@ -543,18 +543,22 @@ module.exports = class Response extends Writable {
|
|
|
543
543
|
}
|
|
544
544
|
append(field, value) {
|
|
545
545
|
field = field.toLowerCase();
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
546
|
+
const old = this.headers[field];
|
|
547
|
+
if(old) {
|
|
548
|
+
const newVal = [];
|
|
549
|
+
if(Array.isArray(old)) {
|
|
550
|
+
newVal.push(...old);
|
|
551
|
+
} else if(old) {
|
|
552
|
+
newVal.push(old);
|
|
551
553
|
}
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
this.headers[field] = value.join(', ');
|
|
554
|
+
if(Array.isArray(value)) {
|
|
555
|
+
newVal.push(...value);
|
|
556
|
+
} else {
|
|
557
|
+
newVal.push(value);
|
|
557
558
|
}
|
|
559
|
+
this.headers[field] = newVal;
|
|
560
|
+
} else {
|
|
561
|
+
this.headers[field] = value;
|
|
558
562
|
}
|
|
559
563
|
return this;
|
|
560
564
|
}
|
|
@@ -719,16 +723,7 @@ function pipeStreamOverResponse(res, readStream, totalSize, callback) {
|
|
|
719
723
|
if(!res.headersSent) {
|
|
720
724
|
res.writeHead(res.statusCode);
|
|
721
725
|
res._res.writeStatus(res.statusCode.toString());
|
|
722
|
-
|
|
723
|
-
if(header === 'content-length') {
|
|
724
|
-
continue;
|
|
725
|
-
}
|
|
726
|
-
res._res.writeHeader(header, res.headers[header]);
|
|
727
|
-
}
|
|
728
|
-
if(!res.headers['content-type']) {
|
|
729
|
-
res._res.writeHeader('content-type', 'text/html; charset=utf-8');
|
|
730
|
-
}
|
|
731
|
-
res.headersSent = true;
|
|
726
|
+
res.writeHeaders(true);
|
|
732
727
|
}
|
|
733
728
|
const ab = chunk.buffer.slice(chunk.byteOffset, chunk.byteOffset + chunk.byteLength);
|
|
734
729
|
|
package/src/router.js
CHANGED
|
@@ -276,7 +276,8 @@ module.exports = class Router extends EventEmitter {
|
|
|
276
276
|
const matchedRoute = await this._routeRequest(request, response, 0, optimizedPath, true, route);
|
|
277
277
|
if(!matchedRoute && !response.headersSent && !response.aborted) {
|
|
278
278
|
response.status(404);
|
|
279
|
-
|
|
279
|
+
request.noEtag = true;
|
|
280
|
+
this._sendErrorPage(request, response, `Cannot ${request.method} ${request.path}`, false);
|
|
280
281
|
}
|
|
281
282
|
};
|
|
282
283
|
route.optimizedPath = optimizedPath;
|
|
@@ -305,7 +306,7 @@ module.exports = class Router extends EventEmitter {
|
|
|
305
306
|
if(response.statusCode === 200) {
|
|
306
307
|
response.statusCode = 500;
|
|
307
308
|
}
|
|
308
|
-
|
|
309
|
+
this._sendErrorPage(request, response, err, true);
|
|
309
310
|
}
|
|
310
311
|
});
|
|
311
312
|
}
|
|
@@ -313,7 +314,7 @@ module.exports = class Router extends EventEmitter {
|
|
|
313
314
|
if(response.statusCode === 200) {
|
|
314
315
|
response.statusCode = 500;
|
|
315
316
|
}
|
|
316
|
-
|
|
317
|
+
this._sendErrorPage(request, response, err, true);
|
|
317
318
|
}
|
|
318
319
|
|
|
319
320
|
#extractParams(pattern, path) {
|
|
@@ -524,11 +525,15 @@ module.exports = class Router extends EventEmitter {
|
|
|
524
525
|
return fns;
|
|
525
526
|
}
|
|
526
527
|
|
|
527
|
-
|
|
528
|
+
_sendErrorPage(request, response, err, checkEnv = false) {
|
|
528
529
|
if(checkEnv && this.get('env') === 'production') {
|
|
529
530
|
err = 'Internal Server Error';
|
|
530
531
|
}
|
|
531
|
-
|
|
532
|
+
request.noEtag = true;
|
|
533
|
+
response.setHeader('Content-Type', 'text/html; charset=utf-8');
|
|
534
|
+
response.setHeader('X-Content-Type-Options', 'nosniff');
|
|
535
|
+
response.setHeader('Content-Security-Policy', "default-src 'none'");
|
|
536
|
+
response.send(`<!DOCTYPE html>\n` +
|
|
532
537
|
`<html lang="en">\n` +
|
|
533
538
|
`<head>\n` +
|
|
534
539
|
`<meta charset="utf-8">\n` +
|
|
@@ -537,6 +542,6 @@ module.exports = class Router extends EventEmitter {
|
|
|
537
542
|
`<body>\n` +
|
|
538
543
|
`<pre>${err?.stack ?? err}</pre>\n` +
|
|
539
544
|
`</body>\n` +
|
|
540
|
-
`</html>\n
|
|
545
|
+
`</html>\n`);
|
|
541
546
|
}
|
|
542
547
|
}
|