1
1
import { Writable } from 'stream' ;
2
+ import { IncomingHttpHeaders } from 'http' ;
2
3
import ServerlessRequest from './serverlessRequest' ;
3
4
import ServerlessResponse from './serverlessResponse' ;
4
5
6
+ type MultiValueHeaders = {
7
+ [ key : string ] : string [ ] ;
8
+ } ;
5
9
export const waitForStreamComplete = ( stream : Writable ) : Promise < Writable > => {
6
10
if ( stream . writableFinished || stream . writableEnded ) {
7
11
return Promise . resolve ( stream ) ;
8
12
}
9
13
10
14
return new Promise ( ( resolve , reject ) => {
11
- stream . once ( 'error' , complete ) ;
12
- stream . once ( 'end' , complete ) ;
13
- stream . once ( 'finish' , complete ) ;
14
-
15
15
let isComplete = false ;
16
16
17
17
function complete ( err ?: Error ) {
@@ -31,20 +31,65 @@ export const waitForStreamComplete = (stream: Writable): Promise<Writable> => {
31
31
resolve ( stream ) ;
32
32
}
33
33
}
34
+
35
+ stream . once ( 'error' , complete ) ;
36
+ stream . once ( 'end' , complete ) ;
37
+ stream . once ( 'finish' , complete ) ;
34
38
} ) ;
35
39
} ;
36
40
41
+ const sanitizeHeaders = ( headers : IncomingHttpHeaders ) => {
42
+ return Object . keys ( headers ) . reduce (
43
+ ( memo , key ) => {
44
+ const value = headers [ key ] ;
45
+
46
+ if ( Array . isArray ( value ) ) {
47
+ memo . multiValueHeaders [ key ] = value ;
48
+ if ( key . toLowerCase ( ) !== 'set-cookie' ) {
49
+ memo . headers [ key ] = value . join ( ', ' ) ;
50
+ }
51
+ } else {
52
+ memo . headers [ key ] = value == null ? '' : value . toString ( ) ;
53
+ }
54
+
55
+ return memo ;
56
+ } ,
57
+ {
58
+ headers : { } as IncomingHttpHeaders ,
59
+ multiValueHeaders : { } as MultiValueHeaders ,
60
+ } ,
61
+ ) ;
62
+ } ;
63
+
37
64
export const buildResponse = ( {
38
65
request,
39
66
response,
40
67
} : {
41
68
request : ServerlessRequest ;
42
69
response : ServerlessResponse ;
43
70
} ) => {
71
+ const { headers, multiValueHeaders } = sanitizeHeaders ( ServerlessResponse . headers ( response ) ) ;
72
+
73
+ let body = ServerlessResponse . body ( response ) . toString (
74
+ request . isBase64Encoded ? 'base64' : 'utf8' ,
75
+ ) ;
76
+ if ( headers [ 'transfer-encoding' ] === 'chunked' || response . chunkedEncoding ) {
77
+ const raw = ServerlessResponse . body ( response ) . toString ( ) . split ( '\r\n' ) ;
78
+ const parsed = [ ] ;
79
+ for ( let i = 0 ; i < raw . length ; i += 2 ) {
80
+ const size = parseInt ( raw [ i ] , 16 ) ;
81
+ const value = raw [ i + 1 ] ;
82
+ if ( value ) {
83
+ parsed . push ( value . substring ( 0 , size ) ) ;
84
+ }
85
+ }
86
+ body = parsed . join ( '' ) ;
87
+ }
44
88
return {
45
89
statusCode : response . statusCode ,
46
- body : ServerlessResponse . body ( response ) . toString ( request . isBase64Encoded ? 'base64' : 'utf8' ) ,
47
- headers : response . headers ,
90
+ body,
91
+ headers,
92
+ multiValueHeaders,
48
93
isBase64Encoded : request . isBase64Encoded ,
49
94
} ;
50
95
} ;
0 commit comments