ultimate-express 1.2.15 → 1.2.17

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
@@ -28,13 +28,13 @@ Tested using [wrk](https://github.com/wg/wrk) (`-d 60 -t 1 -c 200`). Etag was di
28
28
 
29
29
  | Test | Express req/sec | µExpress req/sec | Express throughput | µExpress throughput | µExpress speedup |
30
30
  | --------------------------------------------- | --------------- | ---------------- | ------------------ | ------------------- | ---------------- |
31
- | routing/simple-routes (/) | 10.90k | 70.10k | 2.04 MB/sec | 11.57 MB/sec | **6.43X** |
32
- | routing/lot-of-routes (/999) | 4.66k | 51.58k | 0.85 MB/sec | 8.07 MB/sec | **11.07X** |
33
- | routing/some-middlewares (/90) | 10.18k | 66.97k | 1.81 MB/sec | 10.42 MB/sec | **6.58X** |
34
- | routers/nested-routers (/abccc/nested/ddd) | 10.25k | 50.98k | 1.83 MB/sec | 7.98 MB/sec | **4.97X** |
35
- | middlewares/express-static (/static/index.js) | 7.52k | 31.08k | 6.92 MB/sec | 26.48 MB/sec | **4.13X** |
36
- | engines/ejs (/test) | 5.92k | 41.64k | 2.40 MB/sec | 16.55 MB/sec | **7.03X** |
37
- | middlewares/body-urlencoded (/abc) | 8.01k | 35.10k | 1.66 MB/sec | 7.02 MB/sec | **4.38X** |
31
+ | routing/simple-routes (/) | 11.16k | 75.14k | 2.08 MB/sec | 14.46 MB/sec | **6.73X** |
32
+ | routing/lot-of-routes (/999) | 4.63k | 54.57k | 0.84 MB/sec | 10.03 MB/sec | **11.78X** |
33
+ | routing/some-middlewares (/90) | 10.12k | 61.92k | 1.79 MB/sec | 11.32 MB/sec | **6.12X** |
34
+ | routers/nested-routers (/abccc/nested/ddd) | 10.18k | 51.15k | 1.82 MB/sec | 9.40 MB/sec | **5.02X** |
35
+ | middlewares/express-static (/static/index.js) | 6.58k | 32.45k | 10.15 MB/sec | 49.43 MB/sec | **4.87X** |
36
+ | engines/ejs (/test) | 5.50k | 40.82k | 2.45 MB/sec | 18.38 MB/sec | **7.42X** |
37
+ | middlewares/body-urlencoded (/abc) | 8.07k | 50.52k | 1.68 MB/sec | 10.78 MB/sec | **6.26X** |
38
38
 
39
39
  ### Performance against other frameworks
40
40
 
@@ -282,7 +282,7 @@ In general, basically all features and options are supported. Use [Express 4.x d
282
282
 
283
283
  ## Tested middlewares
284
284
 
285
- Most of the middlewares that are compatible with Express are compatible with µExpress. Here's list of middlewares that we test for compatibility:
285
+ Almost all middlewares that are compatible with Express are compatible with µExpress. Here's list of middlewares that we test for compatibility:
286
286
 
287
287
  - ✅ [body-parser](https://npmjs.com/package/body-parser) (use `express.text()` etc instead for better performance)
288
288
  - ✅ [cookie-parser](https://npmjs.com/package/cookie-parser)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ultimate-express",
3
- "version": "1.2.15",
3
+ "version": "1.2.17",
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": {
@@ -39,6 +39,7 @@
39
39
  "homepage": "https://github.com/dimdenGD/ultimate-express#readme",
40
40
  "dependencies": {
41
41
  "accepts": "^1.3.8",
42
+ "bytes": "^3.1.2",
42
43
  "cookie": "^0.6.0",
43
44
  "cookie-signature": "^1.2.1",
44
45
  "encodeurl": "^2.0.0",
@@ -155,13 +155,15 @@ function createBodyParser(defaultType, beforeReturn) {
155
155
  return (req, res, next) => {
156
156
  const type = req.headers['content-type'];
157
157
 
158
- // skip reading body for non-json content type
159
- if(!type) {
158
+ // skip reading body twice
159
+ if(req.bodyRead) {
160
160
  return next();
161
161
  }
162
162
 
163
- // skip reading body twice
164
- if(req.body) {
163
+ req.body = {};
164
+
165
+ // skip reading body for non-json content type
166
+ if(!type) {
165
167
  return next();
166
168
  }
167
169
 
@@ -216,6 +218,8 @@ function createBodyParser(defaultType, beforeReturn) {
216
218
  }
217
219
  }
218
220
 
221
+ req.bodyRead = true;
222
+
219
223
  function onData(buf) {
220
224
  if(!Buffer.isBuffer(buf)) {
221
225
  buf = Buffer.from(buf);
@@ -266,7 +270,12 @@ const json = createBodyParser('application/json', function(req, res, next, optio
266
270
  return next(new Error('Invalid body'));
267
271
  }
268
272
  }
269
- req.body = JSON.parse(buf.toString(), options.reviver);
273
+ try {
274
+ req.body = JSON.parse(buf.toString(), options.reviver);
275
+ } catch(e) {
276
+ return next(e);
277
+ }
278
+
270
279
  next();
271
280
  });
272
281
 
@@ -290,7 +299,12 @@ const text = createBodyParser('text/plain', function(req, res, next, options, bu
290
299
  if(encoding !== 'utf-8' && encoding !== 'utf-16le' && encoding !== 'latin1') {
291
300
  return next(new Error('Unsupported charset'));
292
301
  }
293
- req.body = buf.toString(encoding);
302
+ try {
303
+ req.body = buf.toString(encoding);
304
+ } catch(e) {
305
+ return next(e);
306
+ }
307
+
294
308
  next();
295
309
  });
296
310
 
package/src/request.js CHANGED
@@ -63,13 +63,12 @@ module.exports = class Request extends Readable {
63
63
  if(this.endsWithSlash && this.path !== '/' && !this.app.get('strict routing')) {
64
64
  this._opPath = this._opPath.slice(0, -1);
65
65
  }
66
- this.method = req.getMethod().toUpperCase();
66
+ this.method = req.getCaseSensitiveMethod().toUpperCase();
67
67
  this.params = {};
68
68
 
69
69
  this._gotParams = new Set();
70
70
  this._stack = [];
71
71
  this._paramStack = [];
72
- this.bufferedData = Buffer.allocUnsafe(0);
73
72
  this.receivedData = false;
74
73
  // reading ip is very slow in UWS, so its better to not do it unless truly needed
75
74
  if(this.app.needsIpAfterResponse || this.key < 100) {
@@ -87,6 +86,7 @@ module.exports = class Request extends Readable {
87
86
  this.method === 'PATCH' ||
88
87
  (additionalMethods && additionalMethods.includes(this.method))
89
88
  ) {
89
+ this.bufferedData = Buffer.allocUnsafe(0);
90
90
  this._res.onData((ab, isLast) => {
91
91
  // make stream actually readable
92
92
  this.receivedData = true;
@@ -105,7 +105,7 @@ module.exports = class Request extends Readable {
105
105
  }
106
106
 
107
107
  async _read() {
108
- if(!this.receivedData) {
108
+ if(!this.receivedData || !this.bufferedData) {
109
109
  return;
110
110
  }
111
111
  if(this.bufferedData.length > 0) {
package/src/response.js CHANGED
@@ -43,30 +43,30 @@ class Socket extends EventEmitter {
43
43
  constructor(response) {
44
44
  super();
45
45
  this.response = response;
46
- this.writable = true;
47
46
 
48
47
  this.on('error', (err) => {
49
48
  this.emit('close');
50
49
  });
51
- this.on('close', () => {
52
- this.writable = false;
53
- });
50
+ }
51
+ get writable() {
52
+ return !this.response.finished;
54
53
  }
55
54
  }
56
55
 
57
56
  module.exports = class Response extends Writable {
57
+ #socket = null;
58
58
  constructor(res, req, app) {
59
59
  super();
60
60
  this._req = req;
61
61
  this._res = res;
62
62
  this.headersSent = false;
63
63
  this.aborted = false;
64
- this.socket = new Socket(this);
65
64
  this.app = app;
66
65
  this.locals = {};
67
66
  this.aborted = false;
68
67
  this.statusCode = 200;
69
68
  this.chunkedTransfer = true;
69
+ this.finished = false;
70
70
  this.totalSize = 0;
71
71
  this.headers = {
72
72
  'connection': 'keep-alive',
@@ -92,11 +92,20 @@ module.exports = class Response extends Writable {
92
92
  }
93
93
  this._res.cork(() => {
94
94
  this._res.close();
95
- this.socket.emit('close');
95
+ this.finished = true;
96
+ if(this.socketExists) this.socket.emit('close');
96
97
  });
97
98
  });
98
- this.emit('socket', this.socket);
99
99
  }
100
+
101
+ get socket() {
102
+ this.socketExists = true;
103
+ if(!this.#socket) {
104
+ this.#socket = new Socket(this);
105
+ }
106
+ return this.#socket;
107
+ }
108
+
100
109
  _write(chunk, encoding, callback) {
101
110
  if(this.aborted) {
102
111
  const err = new Error('Request aborted');
@@ -135,7 +144,8 @@ module.exports = class Response extends Writable {
135
144
  const [ok, done] = this._res.tryEnd(chunk, this.totalSize);
136
145
  if(done) {
137
146
  this.destroy();
138
- this.socket.emit('close');
147
+ this.finished = true;
148
+ if(this.socketExists) this.socket.emit('close');
139
149
  callback();
140
150
  } else {
141
151
  // still writing
@@ -148,7 +158,8 @@ module.exports = class Response extends Writable {
148
158
  const [ok, done] = this._res.tryEnd(chunk.slice(offset - lastOffset), this.totalSize);
149
159
  if(done) {
150
160
  this.destroy();
151
- this.socket.emit('close');
161
+ this.finished = true;
162
+ if(this.socketExists) this.socket.emit('close');
152
163
  callback();
153
164
  } else if(ok) {
154
165
  callback();
@@ -213,7 +224,8 @@ module.exports = class Response extends Writable {
213
224
  this.headersSent = true;
214
225
  if(fresh) {
215
226
  this._res.end();
216
- this.socket.emit('close');
227
+ this.finished = true;
228
+ if(this.socketExists) this.socket.emit('close');
217
229
  return;
218
230
  }
219
231
  }
@@ -230,7 +242,8 @@ module.exports = class Response extends Writable {
230
242
  this._res.end(data);
231
243
  }
232
244
  }
233
- this.socket.emit('close');
245
+ this.finished = true;
246
+ if(this.socketExists) this.socket.emit('close');
234
247
  });
235
248
 
236
249
  return this;
@@ -692,12 +705,8 @@ module.exports = class Response extends Writable {
692
705
  return this;
693
706
  }
694
707
 
695
- get finished() {
696
- return !this.socket.writable;
697
- }
698
-
699
708
  get writableFinished() {
700
- return !this.socket.writable;
709
+ return this.finished;
701
710
  }
702
711
  }
703
712
 
@@ -728,7 +737,8 @@ function pipeStreamOverResponse(res, readStream, totalSize, callback) {
728
737
 
729
738
  if (done) {
730
739
  readStream.destroy();
731
- res.socket.emit('close');
740
+ res.finished = true;
741
+ if(res.socketExists) res.socket.emit('close');
732
742
  if(callback) callback();
733
743
  } else if (!ok) {
734
744
  readStream.pause();
@@ -743,7 +753,8 @@ function pipeStreamOverResponse(res, readStream, totalSize, callback) {
743
753
  const [ok, done] = res._res.tryEnd(res._res.ab.slice(offset - res._res.abOffset), totalSize);
744
754
  if (done) {
745
755
  readStream.destroy();
746
- res.socket.emit('close');
756
+ res.finished = true;
757
+ if(res.socketExists) res.socket.emit('close');
747
758
  if(callback) callback();
748
759
  } else if (ok) {
749
760
  readStream.resume();
@@ -757,7 +768,8 @@ function pipeStreamOverResponse(res, readStream, totalSize, callback) {
757
768
  if(callback) callback(e);
758
769
  if(!res.finished) {
759
770
  res._res.close();
760
- res.socket.emit('error', e);
771
+ res.finished = true;
772
+ if(res.socketExists) res.socket.emit('error', e);
761
773
  }
762
774
  });
763
775
  }