ultimate-express 1.2.17 → 1.2.20

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 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("u-express");
82
+ const express = require("ultimate-express");
83
83
 
84
84
  const app = express({
85
85
  uwsOptions: {
@@ -144,7 +144,8 @@ In general, basically all features and options are supported. Use [Express 4.x d
144
144
 
145
145
  ### Application
146
146
 
147
- - ✅ app.listen()
147
+ - ✅ app.listen(port[, host][, callback])
148
+ - ✅ app.listen(unix_socket[, callback])
148
149
  - ✅ app.METHOD() (app.get, app.post, etc.)
149
150
  - ✅ app.route()
150
151
  - ✅ app.all()
@@ -312,4 +313,4 @@ Any Express view engine should work. Here's list of engines we include in our te
312
313
  - ✅ [express-dot-engine](https://npmjs.com/package/express-dot-engine)
313
314
  - ✅ [express-art-template](https://npmjs.com/package/express-art-template)
314
315
  - ✅ [express-handlebars](https://npmjs.com/package/express-handlebars)
315
- - ✅ [swig](https://npmjs.com/package/swig)
316
+ - ✅ [swig](https://npmjs.com/package/swig)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ultimate-express",
3
- "version": "1.2.17",
3
+ "version": "1.2.20",
4
4
  "description": "The Ultimate Express. Fastest http server with full Express compatibility, based on uWebSockets.",
5
5
  "main": "src/index.js",
6
6
  "scripts": {
@@ -183,34 +183,52 @@ 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
- response.send(this._generateErrorPage(`Cannot ${request.method} ${request.path}`, false));
186
+ this._sendErrorPage(request, response, `Cannot ${request.method} ${request.path}`, false);
187
187
  }
188
188
  });
189
189
  }
190
190
 
191
- listen(port, callback) {
191
+ listen(port, host, callback) {
192
192
  this.#createRequestHandler();
193
+ // support listen(callback)
193
194
  if(!callback && typeof port === 'function') {
194
195
  callback = port;
195
196
  port = 0;
196
197
  }
198
+ // support listen(port, callback)
199
+ if(typeof host === 'function') {
200
+ callback = host;
201
+ host = undefined;
202
+ }
203
+ const onListen = socket => {
204
+ if(!socket) {
205
+ let err = new Error('Failed to listen on port ' + port + '. No permission or address already in use.');
206
+ throw err;
207
+ }
208
+ this.port = uWS.us_socket_local_port(socket);
209
+ callback(this.port);
210
+ };
197
211
  let fn = 'listen';
212
+ let args = [port];
198
213
  if(typeof port !== 'number') {
199
214
  if(!isNaN(Number(port))) {
200
215
  port = Number(port);
216
+ args.push(onListen);
217
+ if(host) {
218
+ args.unshift(host);
219
+ }
201
220
  } else {
202
221
  fn = 'listen_unix';
222
+ args.unshift(onListen);
223
+ if(host) {
224
+ args.unshift(host);
225
+ }
203
226
  }
227
+ } else {
228
+ args.push(onListen);
204
229
  }
205
230
  this.listenCalled = true;
206
- this.uwsApp[fn](port, socket => {
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
- });
231
+ this.uwsApp[fn](...args);
214
232
  }
215
233
 
216
234
  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
- for(const header in this.headers) {
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
- for(const header in this.headers) {
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
- if(this.headers[field]) {
547
- if(typeof value === 'string' || typeof value === 'number') {
548
- this.headers[field] += ', ' + value;
549
- } else if(Array.isArray(value)) {
550
- this.headers[field] += ', ' + value.join(', ');
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
- } else {
553
- if(typeof value === 'string' || typeof value === 'number') {
554
- this.headers[field] = value.toString();
555
- } else if(Array.isArray(value)) {
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
- for(const header in res.headers) {
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
- response.send(this._generateErrorPage(`Cannot ${request.method} ${request.path}`, false));
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
- response.send(this._generateErrorPage(err, true));
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
- response.send(this._generateErrorPage(err, true));
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
- _generateErrorPage(err, checkEnv = false) {
528
+ _sendErrorPage(request, response, err, checkEnv = false) {
528
529
  if(checkEnv && this.get('env') === 'production') {
529
530
  err = 'Internal Server Error';
530
531
  }
531
- return `<!DOCTYPE html>\n` +
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
  }