ultimate-express 1.3.4 → 1.3.6

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
@@ -24,7 +24,7 @@ Similar projects based on uWebSockets:
24
24
 
25
25
  ### Test results
26
26
 
27
- Tested using [wrk](https://github.com/wg/wrk) (`-d 60 -t 1 -c 200`). Etag was disabled in both Express and µExpress. Tested on Ubuntu 22.04, Node.js 20.17.0, AMD Ryzen 5 3600, 64GB RAM.
27
+ Tested using [wrk](https://github.com/wg/wrk) (`-d 60 -t 1 -c 200`). Tested on Ubuntu 22.04, Node.js 20.17.0, AMD Ryzen 5 3600, 64GB RAM.
28
28
 
29
29
  | Test | Express req/sec | µExpress req/sec | Express throughput | µExpress throughput | µExpress speedup |
30
30
  | --------------------------------------------- | --------------- | ---------------- | ------------------ | ------------------- | ---------------- |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ultimate-express",
3
- "version": "1.3.4",
3
+ "version": "1.3.6",
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": {
@@ -8,7 +8,7 @@
8
8
  "dev": "node --inspect=9229 demo/index.js"
9
9
  },
10
10
  "engines": {
11
- "node": ">=16"
11
+ "node": ">=18"
12
12
  },
13
13
  "files": [
14
14
  "src",
@@ -80,6 +80,7 @@
80
80
  "express-rate-limit": "^7.4.0",
81
81
  "express-session": "^1.18.0",
82
82
  "express-subdomain": "^1.0.6",
83
+ "formdata-node": "^6.0.3",
83
84
  "method-override": "^3.0.0",
84
85
  "multer": "^1.4.5-lts.1",
85
86
  "mustache-express": "^1.3.2",
@@ -86,7 +86,7 @@ function static(root, options) {
86
86
 
87
87
  if(stat.isDirectory()) {
88
88
  if(!req.endsWithSlash) {
89
- if(options.redirect) return res.redirect(301, req.path + '/');
89
+ if(options.redirect) return res.redirect(301, req._originalPath + '/');
90
90
  else {
91
91
  if(!options.fallthrough) {
92
92
  res.status(404);
@@ -234,7 +234,10 @@ function createBodyParser(defaultType, beforeReturn) {
234
234
  if(inflate) {
235
235
  buf = inflate.process(buf);
236
236
  }
237
- abs.push(buf);
237
+
238
+ // shallow copy, to avoid shared references for large bodies.
239
+ abs.push(Buffer.from(buf));
240
+
238
241
  totalSize += buf.length;
239
242
  if(totalSize > options.limit) {
240
243
  return next(new Error('Request entity too large'));
package/src/request.js CHANGED
@@ -60,6 +60,7 @@ module.exports = class Request extends Readable {
60
60
  this.path = iq !== -1 ? this.url.substring(0, iq) : this.url;
61
61
  this.endsWithSlash = this.path[this.path.length - 1] === '/';
62
62
  this._opPath = this.path;
63
+ this._originalPath = this.path;
63
64
  if(this.endsWithSlash && this.path !== '/' && !this.app.get('strict routing')) {
64
65
  this._opPath = this._opPath.slice(0, -1);
65
66
  }
@@ -119,7 +120,7 @@ module.exports = class Request extends Readable {
119
120
  }
120
121
 
121
122
  get baseUrl() {
122
- let match = this.path.match(patternToRegex(this._stack.join(""), true));
123
+ let match = this._originalPath.match(patternToRegex(this._stack.join(""), true));
123
124
  return match ? match[0] : '';
124
125
  }
125
126
 
package/src/router.js CHANGED
@@ -285,7 +285,7 @@ module.exports = class Router extends EventEmitter {
285
285
  if(!matchedRoute && !response.headersSent && !response.aborted) {
286
286
  response.status(404);
287
287
  request.noEtag = true;
288
- this._sendErrorPage(request, response, `Cannot ${request.method} ${request.path}`, false);
288
+ this._sendErrorPage(request, response, `Cannot ${request.method} ${request._originalPath}`, false);
289
289
  }
290
290
  };
291
291
  route.optimizedPath = optimizedPath;
@@ -359,7 +359,7 @@ module.exports = class Router extends EventEmitter {
359
359
  if(route.optimizedParams) {
360
360
  req.params = req.optimizedParams;
361
361
  } else if(typeof route.path === 'string' && (route.path.includes(':') || route.path.includes('*')) && route.pattern instanceof RegExp) {
362
- let path = req.path;
362
+ let path = req._originalPath;
363
363
  if(req._stack.length > 0) {
364
364
  path = path.replace(this.getFullMountpath(req), '');
365
365
  }
@@ -449,16 +449,20 @@ module.exports = class Router extends EventEmitter {
449
449
  if(route.use) {
450
450
  const strictRouting = this.get('strict routing');
451
451
  req._stack.push(route.path);
452
- req._opPath = req.path.replace(this.getFullMountpath(req), '');
453
- if(strictRouting) {
454
- if(req.endsWithSlash && req.path !== '/') {
455
- req._opPath += '/';
452
+ req._opPath = req._originalPath.replace(this.getFullMountpath(req), '');
453
+ if(req.endsWithSlash && req._opPath[req._opPath.length - 1] !== '/') {
454
+ if(strictRouting) {
455
+ req._opPath += '/';
456
+ } else {
457
+ req._opPath = req._opPath.slice(0, -1);
456
458
  }
457
- } else if(req.endsWithSlash && req.path !== '/') {
458
- req._opPath = req._opPath.slice(0, -1);
459
459
  }
460
460
  req.url = req._opPath + req.urlQuery;
461
- if(req.url === '') req.url = '/';
461
+ req.path = req._opPath;
462
+ if(req._opPath === '') {
463
+ req.url = '/';
464
+ req.path = '/';
465
+ }
462
466
  }
463
467
  return new Promise((resolve) => {
464
468
  const next = async (thingamabob) => {
@@ -467,16 +471,21 @@ module.exports = class Router extends EventEmitter {
467
471
  if(route.use && thingamabob !== 'skipPop') {
468
472
  req._stack.pop();
469
473
  const strictRouting = this.get('strict routing');
470
- req._opPath = req._stack.length > 0 ? req.path.replace(this.getFullMountpath(req), '') : req.path;
474
+ req._opPath = req._stack.length > 0 ? req._originalPath.replace(this.getFullMountpath(req), '') : req._originalPath;
471
475
  if(strictRouting) {
472
- if(req.endsWithSlash && req.path !== '/') {
476
+ if(req.endsWithSlash && req._opPath[req._opPath.length - 1] !== '/') {
473
477
  req._opPath += '/';
474
478
  }
475
- } else if(req.endsWithSlash && req.path !== '/' && req._opPath[req._opPath.length - 1] === '/') {
476
- req._opPath = req._opPath.slice(0, -1);
477
479
  }
478
480
  req.url = req._opPath + req.urlQuery;
479
- if(req.url === '') req.url = '/';
481
+ req.path = req._opPath;
482
+ if(req._opPath === '') {
483
+ req.url = '/';
484
+ req.path = '/';
485
+ }
486
+ if(!strictRouting && req.endsWithSlash && req._originalPath !== '/' && req._opPath[req._opPath.length - 1] === '/') {
487
+ req._opPath = req._opPath.slice(0, -1);
488
+ }
480
489
  if(req.app.parent && route.callback.constructor.name === 'Application') {
481
490
  req.app = req.app.parent;
482
491
  }
@@ -498,7 +507,7 @@ module.exports = class Router extends EventEmitter {
498
507
  if(callback.settings.mergeParams) {
499
508
  req._paramStack.push(req.params);
500
509
  }
501
- if(callback.settings['strict routing'] && req.endsWithSlash && req.path !== '/') {
510
+ if(callback.settings['strict routing'] && req.endsWithSlash && req._opPath[req._opPath.length - 1] !== '/') {
502
511
  req._opPath += '/';
503
512
  }
504
513
  const routed = await callback._routeRequest(req, res, 0);