ultimate-express 1.3.17 → 1.3.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ultimate-express",
3
- "version": "1.3.17",
3
+ "version": "1.3.19",
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": {
@@ -72,7 +72,8 @@
72
72
  "ejs": "^3.1.10",
73
73
  "errorhandler": "^1.5.1",
74
74
  "exit-hook": "^2.2.1",
75
- "express": "^4.19.2",
75
+ "express-4": "npm:express@4",
76
+ "express-5": "npm:express@5",
76
77
  "express-art-template": "^1.0.1",
77
78
  "express-async-errors": "^3.1.1",
78
79
  "express-dot-engine": "^1.0.8",
@@ -180,11 +180,6 @@ function createBodyParser(defaultType, beforeReturn) {
180
180
  return next();
181
181
  }
182
182
 
183
- // skip reading too large body
184
- if(length && +length > options.limit) {
185
- return next(new Error('Request entity too large'));
186
- }
187
-
188
183
  if(options.simpleType) {
189
184
  const semicolonIndex = type.indexOf(';');
190
185
  const clearType = semicolonIndex !== -1 ? type.substring(0, semicolonIndex) : type;
@@ -203,6 +198,12 @@ function createBodyParser(defaultType, beforeReturn) {
203
198
  }
204
199
  }
205
200
 
201
+ // skip reading too large body
202
+ if(length && +length > options.limit) {
203
+ return next(new Error('Request entity too large'));
204
+ }
205
+
206
+
206
207
  // skip reading body for non-POST requests
207
208
  // this makes it +10k req/sec faster
208
209
  if( additionalMethods === undefined ) additionalMethods = req.app.get('body methods') ?? null;
package/src/request.js CHANGED
@@ -72,6 +72,7 @@ module.exports = class Request extends Readable {
72
72
  this._stack = [];
73
73
  this._paramStack = [];
74
74
  this.receivedData = false;
75
+ this.doneReadingData = false;
75
76
  // reading ip is very slow in UWS, so its better to not do it unless truly needed
76
77
  if(this.app.needsIpAfterResponse || this.key < 100) {
77
78
  // if app needs ip after response, read it now because after response its not accessible
@@ -92,30 +93,30 @@ module.exports = class Request extends Readable {
92
93
  this._res.onData((ab, isLast) => {
93
94
  // make stream actually readable
94
95
  this.receivedData = true;
96
+ if(isLast) {
97
+ this.doneReadingData = true;
98
+ }
95
99
  // instead of pushing data immediately, buffer it
96
100
  // because writable streams cant handle the amount of data uWS gives (usually 512kb+)
97
101
  const chunk = Buffer.from(ab);
98
102
  this.bufferedData = Buffer.concat([this.bufferedData, chunk]);
99
- if(isLast) {
100
- // once its done start pushing data
101
- this._read();
102
- }
103
+ this._read();
103
104
  });
104
105
  } else {
105
106
  this.receivedData = true;
106
107
  }
107
108
  }
108
109
 
109
- async _read() {
110
+ _read() {
110
111
  if(!this.receivedData || !this.bufferedData) {
111
112
  return;
112
113
  }
113
114
  if(this.bufferedData.length > 0) {
114
- // push 64kb chunks
115
- const chunk = this.bufferedData.subarray(0, 1024 * 64);
116
- this.bufferedData = this.bufferedData.subarray(1024 * 64);
115
+ // push 128kb chunks
116
+ const chunk = this.bufferedData.subarray(0, 1024 * 128);
117
+ this.bufferedData = this.bufferedData.subarray(1024 * 128);
117
118
  this.push(chunk);
118
- } else {
119
+ } else if(this.doneReadingData) {
119
120
  this.push(null);
120
121
  }
121
122
  }
package/src/response.js CHANGED
@@ -78,6 +78,7 @@ module.exports = class Response extends Writable {
78
78
  this.finished = false;
79
79
  this.aborted = false;
80
80
  this.statusCode = 200;
81
+ this.statusText = undefined;
81
82
  this.chunkedTransfer = true;
82
83
  this.totalSize = 0;
83
84
  this.headers = {
@@ -132,7 +133,8 @@ module.exports = class Response extends Writable {
132
133
  this._res.cork(() => {
133
134
  if(!this.headersSent) {
134
135
  this.writeHead(this.statusCode);
135
- this._res.writeStatus(this.statusCode.toString());
136
+ const statusMessage = this.statusText ?? statuses.message[this.statusCode] ?? '';
137
+ this._res.writeStatus(`${this.statusCode} ${statusMessage}`.trim());
136
138
  this.writeHeaders(typeof chunk === 'string');
137
139
  }
138
140
  if(!Buffer.isBuffer(chunk) && !(chunk instanceof ArrayBuffer)) {
@@ -181,6 +183,9 @@ module.exports = class Response extends Writable {
181
183
  }
182
184
  writeHead(statusCode, statusMessage, headers) {
183
185
  this.statusCode = statusCode;
186
+ if(typeof statusMessage === 'string') {
187
+ this.statusText = statusMessage;
188
+ }
184
189
  if(!headers) {
185
190
  if(!statusMessage) return;
186
191
  headers = statusMessage;
@@ -235,7 +240,8 @@ module.exports = class Response extends Writable {
235
240
  this.headers['etag'] = etagFn(data);
236
241
  }
237
242
  const fresh = this.req.fresh;
238
- this._res.writeStatus(fresh ? '304' : this.statusCode.toString());
243
+ const statusMessage = this.statusText ?? statuses.message[this.statusCode] ?? '';
244
+ this._res.writeStatus(fresh ? '304 Not Modified' : `${this.statusCode} ${statusMessage}`.trim());
239
245
  this.writeHeaders(true);
240
246
  if(fresh) {
241
247
  this._res.end();
@@ -556,7 +562,9 @@ module.exports = class Response extends Writable {
556
562
  get(field) {
557
563
  return this.headers[field.toLowerCase()];
558
564
  }
559
- getHeader = this.get;
565
+ getHeader(field) {
566
+ return this.get(field);
567
+ }
560
568
  removeHeader(field) {
561
569
  delete this.headers[field.toLowerCase()];
562
570
  return this;
@@ -568,7 +576,7 @@ module.exports = class Response extends Writable {
568
576
  const newVal = [];
569
577
  if(Array.isArray(old)) {
570
578
  newVal.push(...old);
571
- } else if(old) {
579
+ } else {
572
580
  newVal.push(old);
573
581
  }
574
582
  if(Array.isArray(value)) {
@@ -740,7 +748,8 @@ function pipeStreamOverResponse(res, readStream, totalSize, callback) {
740
748
  res._res.cork(() => {
741
749
  if(!res.headersSent) {
742
750
  res.writeHead(res.statusCode);
743
- res._res.writeStatus(res.statusCode.toString());
751
+ const statusMessage = res.statusText ?? statuses.message[res.statusCode] ?? '';
752
+ res._res.writeStatus(`${res.statusCode} ${statusMessage}`.trim());
744
753
  res.writeHeaders(true);
745
754
  }
746
755
  const ab = chunk.buffer.slice(chunk.byteOffset, chunk.byteOffset + chunk.byteLength);
package/src/router.js CHANGED
@@ -19,6 +19,7 @@ const Response = require("./response.js");
19
19
  const Request = require("./request.js");
20
20
  const { EventEmitter } = require("tseep");
21
21
  const compileDeclarative = require("./declarative.js");
22
+ const statuses = require("statuses");
22
23
 
23
24
  let resCodes = {}, resDecMethods = ['set', 'setHeader', 'header', 'send', 'end', 'append', 'status'];
24
25
  for(let method of resDecMethods) {
@@ -108,6 +109,10 @@ module.exports = class Router extends EventEmitter {
108
109
  let path = req._opPath;
109
110
  let pattern = route.pattern;
110
111
 
112
+ if(req.endsWithSlash && path.endsWith('/') && !this.get('strict routing')) {
113
+ path = path.slice(0, -1);
114
+ }
115
+
111
116
  if (typeof pattern === 'string') {
112
117
  if(pattern === '/*') {
113
118
  return true;
@@ -351,6 +356,9 @@ module.exports = class Router extends EventEmitter {
351
356
  }
352
357
 
353
358
  _extractParams(pattern, path) {
359
+ if(path.endsWith('/')) {
360
+ path = path.slice(0, -1);
361
+ }
354
362
  let match = pattern.exec(path);
355
363
  const obj = match?.groups ?? new NullObject();
356
364
  for(let i = 1; i < match.length; i++) {
@@ -598,7 +606,7 @@ module.exports = class Router extends EventEmitter {
598
606
 
599
607
  _sendErrorPage(request, response, err, checkEnv = false) {
600
608
  if(checkEnv && this.get('env') === 'production') {
601
- err = 'Internal Server Error';
609
+ err = response.statusCode >= 400 ? (statuses.message[response.statusCode] ?? 'Internal Server Error') : 'Internal Server Error';
602
610
  }
603
611
  request.noEtag = true;
604
612
  response.setHeader('Content-Type', 'text/html; charset=utf-8');