@@ -12,108 +12,126 @@ const defaultErrorFn: LimitErrorFn = (payloadLimit) => new Error(`Payload too la
1212// Main function
1313export const p =
1414 < T = any > (
15- fn : ( body : Buffer ) => void ,
15+ fn : ( body : Buffer , req : ReqWithBody < T > ) => void ,
1616 payloadLimit = defaultPayloadLimit ,
1717 payloadLimitErrorFn : LimitErrorFn = defaultErrorFn
1818 ) =>
19- async ( req : ReqWithBody < T > , _res : Response , next ?: ( err ?: any ) => void ) => {
20- try {
19+ ( req : ReqWithBody < T > , _res : Response , next ?: ( err ?: any ) => void ) : Promise < T | undefined > =>
20+ new Promise ( ( resolve ) => {
2121 const body : Buffer [ ] = [ ]
22-
23- for await ( const chunk of req ) {
24- const totalSize = body . reduce ( ( total , buffer ) => total + buffer . byteLength , 0 )
25- if ( totalSize > payloadLimit ) throw payloadLimitErrorFn ( payloadLimit )
26- body . push ( chunk as Buffer )
27- }
28-
29- return fn ( Buffer . concat ( body ) )
30- } catch ( e ) {
31- next ?.( e )
32- }
33- }
22+ let totalSize = 0
23+
24+ req . on ( 'data' , ( chunk : Buffer ) => {
25+ totalSize += chunk . byteLength
26+ if ( totalSize > payloadLimit ) {
27+ req . removeAllListeners ( )
28+ next ?.( payloadLimitErrorFn ( payloadLimit ) )
29+ resolve ( undefined )
30+ } else {
31+ body . push ( chunk )
32+ }
33+ } )
34+
35+ req . on ( 'end' , ( ) => {
36+ try {
37+ resolve ( fn ( body . length === 1 ? body [ 0 ] : Buffer . concat ( body ) , req ) as T )
38+ } catch ( e ) {
39+ next ?.( e )
40+ resolve ( undefined )
41+ }
42+ } )
43+
44+ req . on ( 'error' , ( err : Error ) => {
45+ next ?.( err )
46+ resolve ( undefined )
47+ } )
48+ } )
3449
3550/**
3651 * Parse payload with a custom function
3752 * @param fn
3853 */
39- const custom =
40- < T = any > ( fn : ( body : Buffer ) => any , type ?: ParserOptions [ 'type' ] ) =>
41- async ( req : ReqWithBody , _res : Response , next ?: NextFunction ) => {
42- if ( hasBody ( req . method ! ) && checkType ( req , type ) ) req . body = await p < T > ( fn ) ( req , _res , next )
54+ const custom = < T = any > ( fn : ( body : Buffer ) => any , type ?: ParserOptions [ 'type' ] ) => {
55+ const parse = p < T > ( fn )
56+ return async ( req : ReqWithBody , _res : Response , next ?: NextFunction ) => {
57+ if ( hasBody ( req . method ! ) && checkType ( req , type ) ) req . body = await parse ( req , _res , next )
4358 next ?.( )
4459 }
60+ }
4561
4662/**
4763 * Parse JSON payload
4864 * @param options
4965 */
50- const json =
51- ( {
66+ const json = ( {
67+ payloadLimit,
68+ payloadLimitErrorFn,
69+ type,
70+ reviver
71+ } : ParserOptions < {
72+ reviver ?: ( this : any , key : string , value : any ) => any
73+ } > = { } ) => {
74+ const parse = p (
75+ ( x ) => ( x . length === 0 ? { } : JSON . parse ( x . toString ( ) , reviver ) ) ,
5276 payloadLimit ,
53- payloadLimitErrorFn,
54- type,
55- reviver
56- } : ParserOptions < {
57- reviver ?: ( this : any , key : string , value : any ) => any
58- } > = { } ) =>
59- async ( req : ReqWithBody , res : Response , next ?: NextFunction ) => {
77+ payloadLimitErrorFn
78+ )
79+ return async ( req : ReqWithBody , res : Response , next ?: NextFunction ) => {
6080 if ( hasBody ( req . method ! ) && checkType ( req , type ) ) {
61- req . body = await p (
62- ( x ) => {
63- const str = td . decode ( x )
64- return str ? JSON . parse ( str , reviver ) : { }
65- } ,
66- payloadLimit ,
67- payloadLimitErrorFn
68- ) ( req , res , next )
81+ req . body = await parse ( req , res , next )
6982 }
7083 next ?.( )
7184 }
85+ }
7286
7387/**
7488 * Parse raw payload
7589 * @param options
7690 */
77- const raw =
78- ( { payloadLimit , payloadLimitErrorFn , type } : ParserOptions = { } ) =>
79- async ( req : ReqWithBody , _res : Response , next ?: NextFunction ) => {
91+ const raw = ( { payloadLimit , payloadLimitErrorFn , type } : ParserOptions = { } ) => {
92+ const parse = p ( ( x ) => x , payloadLimit , payloadLimitErrorFn )
93+ return async ( req : ReqWithBody , _res : Response , next ?: NextFunction ) => {
8094 if ( hasBody ( req . method ! ) && checkType ( req , type ) ) {
81- req . body = await p ( ( x ) => x , payloadLimit , payloadLimitErrorFn ) ( req , _res , next )
95+ req . body = await parse ( req , _res , next )
8296 }
8397 next ?.( )
8498 }
99+ }
85100
86- const td = new TextDecoder ( )
87101/**
88102 * Stringify request payload
89103 * @param param0
90104 * @returns
91105 */
92- const text =
93- ( { payloadLimit , payloadLimitErrorFn , type } : ParserOptions = { } ) =>
94- async ( req : ReqWithBody , _res : Response , next ?: NextFunction ) => {
106+ const text = ( { payloadLimit , payloadLimitErrorFn , type } : ParserOptions = { } ) => {
107+ const parse = p ( ( x ) => x . toString ( ) , payloadLimit , payloadLimitErrorFn )
108+ return async ( req : ReqWithBody , _res : Response , next ?: NextFunction ) => {
95109 if ( hasBody ( req . method ! ) && checkType ( req , type ) ) {
96- req . body = await p ( ( x ) => td . decode ( x ) , payloadLimit , payloadLimitErrorFn ) ( req , _res , next )
110+ req . body = await parse ( req , _res , next )
97111 }
98112 next ?.( )
99113 }
114+ }
115+
116+ const td = new TextDecoder ( )
100117
101118/**
102119 * Parse urlencoded payload
103120 * @param options
104121 */
105- const urlencoded =
106- ( { payloadLimit, payloadLimitErrorFn, type } : ParserOptions = { } ) =>
107- async ( req : ReqWithBody , _res : Response , next ?: NextFunction ) => {
122+ const urlencoded = ( { payloadLimit, payloadLimitErrorFn, type } : ParserOptions = { } ) => {
123+ const parse = p (
124+ ( x ) => Object . fromEntries ( new URLSearchParams ( x . toString ( ) ) . entries ( ) ) ,
125+ payloadLimit ,
126+ payloadLimitErrorFn
127+ )
128+ return async ( req : ReqWithBody , _res : Response , next ?: NextFunction ) => {
108129 if ( hasBody ( req . method ! ) && checkType ( req , type ) ) {
109- req . body = await p (
110- ( x ) => Object . fromEntries ( new URLSearchParams ( x . toString ( ) ) . entries ( ) ) ,
111- payloadLimit ,
112- payloadLimitErrorFn
113- ) ( req , _res , next )
130+ req . body = await parse ( req , _res , next )
114131 }
115132 next ?.( )
116133 }
134+ }
117135
118136const getBoundary = ( contentType : string ) => {
119137 const match = / b o u n d a r y = ( .+ ) ; ? / . exec ( contentType )
@@ -153,11 +171,10 @@ const parseMultipart = (
153171
154172 const file = new File ( [ fileContent ] , filename [ 1 ] , { type : contentTypeMatch [ 1 ] } )
155173
156- parsedBody [ name ] = parsedBody [ name ] ? [ ... parsedBody [ name ] , file ] : [ file ]
174+ ; ( parsedBody [ name ] ??= [ ] ) . push ( file )
157175 return
158176 }
159- parsedBody [ name ] = parsedBody [ name ] ? [ ...parsedBody [ name ] , data ] : [ data ]
160- return
177+ ; ( parsedBody [ name ] ??= [ ] ) . push ( data )
161178 } )
162179
163180 return parsedBody
@@ -182,26 +199,27 @@ type MultipartOptions = Partial<{
182199 * Does not restrict total payload size by default.
183200 * @param options
184201 */
185- const multipart =
186- ( {
187- payloadLimit = Number . POSITIVE_INFINITY ,
188- payloadLimitErrorFn,
189- type,
190- ...opts
191- } : MultipartOptions & ParserOptions = { } ) =>
192- async ( req : ReqWithBody , res : Response , next ?: NextFunction ) => {
202+ const multipart = ( {
203+ payloadLimit = Number . POSITIVE_INFINITY ,
204+ payloadLimitErrorFn,
205+ type,
206+ ...opts
207+ } : MultipartOptions & ParserOptions = { } ) => {
208+ const parse = p (
209+ ( x , req ) => {
210+ const boundary = getBoundary ( req . headers [ 'content-type' ] ! )
211+ if ( boundary ) return parseMultipart ( td . decode ( x ) , boundary , opts )
212+ return { }
213+ } ,
214+ payloadLimit ,
215+ payloadLimitErrorFn
216+ )
217+ return async ( req : ReqWithBody , res : Response , next ?: NextFunction ) => {
193218 if ( hasBody ( req . method ! ) && checkType ( req , type ) ) {
194- req . body = await p (
195- ( x ) => {
196- const boundary = getBoundary ( req . headers [ 'content-type' ] ! )
197- if ( boundary ) return parseMultipart ( td . decode ( x ) , boundary , opts )
198- return { }
199- } ,
200- payloadLimit ,
201- payloadLimitErrorFn
202- ) ( req , res , next )
219+ req . body = await parse ( req , res , next )
203220 }
204221 next ?.( )
205222 }
223+ }
206224
207225export { custom , json , raw , text , urlencoded , multipart }
0 commit comments