-
Notifications
You must be signed in to change notification settings - Fork 73
/
multipart.parser.ts
55 lines (49 loc) · 1.64 KB
/
multipart.parser.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
import * as Busboy from 'busboy';
import { HttpRequest, HttpError, HttpStatus } from '@marblejs/core';
import { fromEvent, Observable, of, throwError, merge } from 'rxjs';
import { mapTo, mergeMap, tap, mergeMapTo, takeUntil, last } from 'rxjs/operators';
import { ParserOpts } from './multipart.interface';
import { parseField } from './multipart.parser.field';
import { parseFile } from './multipart.parser.file';
export const parseMultipart = (opts: ParserOpts) => (req: HttpRequest): Observable<HttpRequest> => {
const busboy = new Busboy({
headers: req.headers,
limits: {
fileSize: opts.maxFileSize,
files: opts.maxFileCount,
fields: opts.maxFieldCount,
fieldSize: opts.maxFieldSize,
},
});
const parseFile$ = parseFile(req)(opts)(
fromEvent(busboy, 'file'),
fromEvent(busboy, 'finish'),
);
const parseField$ = parseField(req)(
fromEvent(busboy, 'field'),
fromEvent(busboy, 'finish'),
);
const filesLimit$ = fromEvent(busboy, 'filesLimit').pipe(
takeUntil(fromEvent(busboy, 'finish')),
mergeMap(() => throwError(
new HttpError(`Reached max files count limit [${opts.maxFileCount}]`, HttpStatus.PRECONDITION_FAILED),
)),
);
const fieldsLimit$ = fromEvent(busboy, 'fieldsLimit').pipe(
takeUntil(fromEvent(busboy, 'finish')),
mergeMap(() => throwError(
new HttpError(`Reached max fields count limit [${opts.maxFieldCount}]`, HttpStatus.PRECONDITION_FAILED),
)),
);
return of(req).pipe(
tap(req => req.pipe(busboy)),
mergeMapTo(merge(
filesLimit$,
fieldsLimit$,
parseFile$,
parseField$,
)),
last(),
mapTo(req),
);
}