@deepkit/http 1.0.1-alpha.85 → 1.0.1-alpha.87

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.
Files changed (54) hide show
  1. package/dist/cjs/src/controllers.js +1 -0
  2. package/dist/cjs/src/controllers.js.map +1 -1
  3. package/dist/cjs/src/decorator.js +12 -0
  4. package/dist/cjs/src/decorator.js.map +1 -1
  5. package/dist/cjs/src/filter.js +1 -0
  6. package/dist/cjs/src/filter.js.map +1 -1
  7. package/dist/cjs/src/http.d.ts +2 -0
  8. package/dist/cjs/src/http.js +32 -5
  9. package/dist/cjs/src/http.js.map +1 -1
  10. package/dist/cjs/src/kernel.js +1 -0
  11. package/dist/cjs/src/kernel.js.map +1 -1
  12. package/dist/cjs/src/logger.js +1 -0
  13. package/dist/cjs/src/logger.js.map +1 -1
  14. package/dist/cjs/src/middleware.js +1 -0
  15. package/dist/cjs/src/middleware.js.map +1 -1
  16. package/dist/cjs/src/model.d.ts +12 -5
  17. package/dist/cjs/src/model.js +79 -37
  18. package/dist/cjs/src/model.js.map +1 -1
  19. package/dist/cjs/src/module.js +1 -0
  20. package/dist/cjs/src/module.js.map +1 -1
  21. package/dist/cjs/src/router.js +28 -6
  22. package/dist/cjs/src/router.js.map +1 -1
  23. package/dist/cjs/src/static-serving.js +1 -0
  24. package/dist/cjs/src/static-serving.js.map +1 -1
  25. package/dist/cjs/tsconfig.tsbuildinfo +1 -1
  26. package/dist/esm/src/controllers.js +1 -0
  27. package/dist/esm/src/controllers.js.map +1 -1
  28. package/dist/esm/src/decorator.js +12 -0
  29. package/dist/esm/src/decorator.js.map +1 -1
  30. package/dist/esm/src/filter.js +1 -0
  31. package/dist/esm/src/filter.js.map +1 -1
  32. package/dist/esm/src/http.d.ts +2 -0
  33. package/dist/esm/src/http.js +34 -7
  34. package/dist/esm/src/http.js.map +1 -1
  35. package/dist/esm/src/kernel.js +1 -0
  36. package/dist/esm/src/kernel.js.map +1 -1
  37. package/dist/esm/src/logger.js +1 -0
  38. package/dist/esm/src/logger.js.map +1 -1
  39. package/dist/esm/src/middleware.js +1 -0
  40. package/dist/esm/src/middleware.js.map +1 -1
  41. package/dist/esm/src/model.d.ts +12 -5
  42. package/dist/esm/src/model.js +77 -37
  43. package/dist/esm/src/model.js.map +1 -1
  44. package/dist/esm/src/module.js +1 -0
  45. package/dist/esm/src/module.js.map +1 -1
  46. package/dist/esm/src/router.js +29 -7
  47. package/dist/esm/src/router.js.map +1 -1
  48. package/dist/esm/src/static-serving.js +1 -0
  49. package/dist/esm/src/static-serving.js.map +1 -1
  50. package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
  51. package/package.json +9 -9
  52. package/src/http.ts +58 -13
  53. package/src/model.ts +74 -36
  54. package/src/router.ts +25 -8
package/src/model.ts CHANGED
@@ -13,7 +13,7 @@ import { UploadedFile } from './router';
13
13
  import * as querystring from 'querystring';
14
14
  import { Writable } from 'stream';
15
15
  import { metaAnnotation, ReflectionKind, Type, ValidationErrorItem } from '@deepkit/type';
16
- import { isArray } from '@deepkit/core';
16
+ import { asyncOperation, isArray } from '@deepkit/core';
17
17
 
18
18
  export class HttpResponse extends ServerResponse {
19
19
  status(code: number) {
@@ -22,6 +22,62 @@ export class HttpResponse extends ServerResponse {
22
22
  }
23
23
  }
24
24
 
25
+ /**
26
+ * Reads the body of the request and returns it as a Buffer.
27
+ * The result will be cached in the request object as `request.body`.
28
+ *
29
+ * Deepkit's router will automatically use `request.body` if available.
30
+ */
31
+ export function readBody(request: IncomingMessage): Promise<Buffer> {
32
+ return asyncOperation((resolve, reject) => {
33
+ const chunks: Buffer[] = [];
34
+ request.on('data', (chunk: Buffer) => {
35
+ chunks.push(chunk);
36
+ });
37
+ request.on('end', () => {
38
+ const body = Buffer.concat(chunks);
39
+ //the router uses this now instead of trying to read the body again
40
+ (request as HttpRequest).body = body;
41
+ resolve(body);
42
+ });
43
+ request.on('error', (error: Error) => {
44
+ reject(error);
45
+ });
46
+ });
47
+ }
48
+
49
+ export function createRequestWithCachedBody(request: Partial<IncomingMessage>, body: Buffer): HttpRequest {
50
+ const headers = request.headers;
51
+ const method = request.method;
52
+ const url = request.url;
53
+
54
+ const writable = new Writable({
55
+ write(chunk, encoding, callback) {
56
+ callback();
57
+ },
58
+ writev(chunks, callback) {
59
+ callback();
60
+ }
61
+ });
62
+ return new (class extends HttpRequest {
63
+ url = url;
64
+ method = method;
65
+ position = 0;
66
+
67
+ headers = headers as any;
68
+
69
+ _read(size: number) {
70
+ if (this.complete) {
71
+ this.push(null);
72
+ } else {
73
+ //in Node 18 this seems to be necessary to not trigger the abort event
74
+ this.complete = true;
75
+ this.push(body);
76
+ }
77
+ }
78
+ })(writable as any);
79
+ }
80
+
25
81
  export type HttpRequestQuery = { [name: string]: string };
26
82
  export type HttpRequestResolvedParameters = { [name: string]: any };
27
83
 
@@ -107,37 +163,11 @@ export class RequestBuilder {
107
163
  }
108
164
 
109
165
  build(): HttpRequest {
110
- const headers = this._headers;
111
- const method = this.method;
112
- const url = this.getUrl();
113
- const bodyContent = this.contentBuffer;
114
-
115
- const writable = new Writable({
116
- write(chunk, encoding, callback) {
117
- callback();
118
- },
119
- writev(chunks, callback) {
120
- callback();
121
- }
122
- });
123
- const request = new (class extends HttpRequest {
124
- url = url;
125
- method = method;
126
- position = 0;
127
-
128
- headers = headers;
129
-
130
- _read(size: number) {
131
- if (this.complete) {
132
- this.push(null);
133
- } else {
134
- //in Node 18 this seems to be necessary to not trigger the abort event
135
- this.complete = true;
136
- this.push(bodyContent);
137
- }
138
- }
139
- })(writable as any);
140
- return request;
166
+ return createRequestWithCachedBody({
167
+ method: this.method,
168
+ url: this.getUrl(),
169
+ headers: this._headers,
170
+ }, this.contentBuffer);
141
171
  }
142
172
 
143
173
  headers(headers: { [name: string]: string }): this {
@@ -182,10 +212,18 @@ export class HttpRequest extends IncomingMessage {
182
212
  public uploadedFiles: { [name: string]: UploadedFile } = {};
183
213
 
184
214
  /**
185
- * Cache of parsed fields. If middleware prior to Deepkit populates this,
186
- * Deepkit will re-use it.
215
+ * The router sets the body when it was read.
187
216
  */
188
- public body?: { [name: string]: any };
217
+ public body?: Buffer;
218
+
219
+ async readBody(): Promise<Buffer> {
220
+ if (this.body) return this.body;
221
+ return await readBody(this);
222
+ }
223
+
224
+ async readBodyText(): Promise<string> {
225
+ return (await this.readBody()).toString('utf8');
226
+ }
189
227
 
190
228
  static GET(path: string): RequestBuilder {
191
229
  return new RequestBuilder(path);
@@ -234,7 +272,7 @@ export class HttpRequest extends IncomingMessage {
234
272
 
235
273
  export class MemoryHttpResponse extends HttpResponse {
236
274
  public body: Buffer = Buffer.alloc(0);
237
- public headers: {[name: string]: number | string | string[] | undefined} = Object.create(null);
275
+ public headers: { [name: string]: number | string | string[] | undefined } = Object.create(null);
238
276
 
239
277
  setHeader(name: string, value: number | string | ReadonlyArray<string>): this {
240
278
  this.headers[name] = value as any;
package/src/router.ts CHANGED
@@ -31,7 +31,7 @@ import {
31
31
  // @ts-ignore
32
32
  import formidable from 'formidable';
33
33
  import { HttpAction, httpClass, HttpController, HttpDecorator } from './decorator';
34
- import { BodyValidationError, getRegExp, HttpRequest, HttpRequestQuery, HttpRequestResolvedParameters, ValidatedBody } from './model';
34
+ import { BodyValidationError, createRequestWithCachedBody, getRegExp, HttpRequest, HttpRequestQuery, HttpRequestResolvedParameters, ValidatedBody } from './model';
35
35
  import { InjectorContext, InjectorModule, TagRegistry } from '@deepkit/injector';
36
36
  import { Logger, LoggerInterface } from '@deepkit/logger';
37
37
  import { HttpControllers } from './controllers';
@@ -628,10 +628,7 @@ export class HttpRouter {
628
628
  hash: 'sha1',
629
629
  });
630
630
  return asyncOperation((resolve, reject) => {
631
- if (req.body) {
632
- return resolve(req.body);
633
- }
634
- form.parse(req, (err: any, fields: any, files: any) => {
631
+ function parseData(err: any, fields: any, files: any) {
635
632
  if (err) {
636
633
  reject(err);
637
634
  } else {
@@ -643,12 +640,32 @@ export class HttpRouter {
643
640
  name: file.originalFilename,
644
641
  type: file.mimetype,
645
642
  lastModifiedDate: file.lastModifiedDate,
646
- }
643
+ };
647
644
  }
648
- const body = req.body = { ...fields, ...foundFiles };
645
+ const body = { ...fields, ...foundFiles };
649
646
  resolve(body);
650
647
  }
648
+ }
649
+
650
+ if (req.body) {
651
+ form.parse(createRequestWithCachedBody(req, req.body), parseData);
652
+ return;
653
+ }
654
+
655
+ const chunks: Buffer[] = [];
656
+
657
+ function read(chunk: Buffer) {
658
+ chunks.push(chunk);
659
+ }
660
+
661
+ req.on('data', read);
662
+ req.once('end', () => {
663
+ req.body = Buffer.concat(chunks);
664
+ req.off('data', read);
651
665
  });
666
+ req.once('error', () => req.off('data', read));
667
+
668
+ form.parse(req, parseData);
652
669
  });
653
670
  }
654
671
 
@@ -683,7 +700,7 @@ export class HttpRouter {
683
700
  const routeConfigVar = compiler.reserveVariable('routeConfigVar', routeConfig);
684
701
  const parsedRoute = parseRouteControllerAction(routeConfig);
685
702
  const path = routeConfig.getFullPath();
686
- const pathParamStarter = path.indexOf(':')
703
+ const pathParamStarter = path.indexOf(':');
687
704
  const prefix = path.substr(0, pathParamStarter);
688
705
 
689
706
  const regexVar = compiler.reserveVariable('regex', new RegExp('^' + parsedRoute.regex + '$'));