@@ -5,14 +5,21 @@ export const RED = '🔴';
55export const GREEN = '🟢' ;
66export const YELLOW = '🟡' ;
77
8+ type ParsedRequestParams = {
9+ queryParams : Record < string , any > ;
10+ postData : Record < string , any > ;
11+ postDataType : 'json' | 'form-data' | null ;
12+ } ;
13+
814/**
915 * Take a CDP request, and convert both its query params and post data
1016 * into a combined object
1117 */
1218export const getRequestParams = ( request : Protocol . Network . Request ) => {
13- const reqParams = {
19+ const reqParams : ParsedRequestParams = {
1420 queryParams : { } ,
1521 postData : { } ,
22+ postDataType : null ,
1623 } ;
1724
1825 // Get URL params and store them
@@ -22,9 +29,22 @@ export const getRequestParams = (request: Protocol.Network.Request) => {
2229
2330 // Get the post data and store it
2431 if ( request . hasPostData && request . postData ) {
25- const data = parseJSON ( request . postData ) ;
26- if ( ! data ) return reqParams ;
27- reqParams . postData = data ;
32+ const jsonPayload = parseJSON ( request . postData ) ;
33+
34+ if ( jsonPayload ) {
35+ reqParams . postDataType = 'json' ;
36+ reqParams . postData = jsonPayload ;
37+ return reqParams ;
38+ }
39+
40+ // We need to handle multipart form data if the body is not already a JSON payload
41+ const boundary = getBoundary ( request ) ;
42+
43+ if ( boundary ) {
44+ const formData = parseFormData ( request . postData , boundary ) ;
45+ reqParams . postDataType = 'form-data' ;
46+ reqParams . postData = formData ;
47+ }
2848 }
2949
3050 return reqParams ;
@@ -108,3 +128,50 @@ export const formatError = (errorText?: string) => {
108128
109129 return `(failed) ${ errorText } ` ;
110130} ;
131+
132+ /**
133+ * Parse multipart-form data
134+ */
135+ export const parseFormData = ( data : string , boundary : string ) => {
136+ const fields : Record < string , string > = { } ;
137+ const parts = data . split ( `--${ boundary } ` ) . filter ( ( p ) => p . trim ( ) && p . trim ( ) !== '--' ) ;
138+
139+ for ( const part of parts ) {
140+ const [ rawHeaders , ...rest ] = part . split ( '\r\n\r\n' ) ;
141+ if ( ! rawHeaders || ! rest . length ) continue ;
142+
143+ const nameMatch = rawHeaders . match ( / n a m e = " ( [ ^ " ] + ) " / ) ;
144+ if ( ! nameMatch ) continue ;
145+
146+ const name = nameMatch [ 1 ] ;
147+ const value = rest . join ( '\r\n\r\n' ) . replace ( / \r \n $ / , '' ) ; // remove trailing newline
148+ fields [ name ] = value ;
149+ }
150+
151+ return fields ;
152+ } ;
153+
154+ /**
155+ * Turn an object back into form-data
156+ */
157+ export const assembleFormData = ( fields : Record < string , string > , boundary : string ) => {
158+ let body = '' ;
159+
160+ for ( const [ name , value ] of Object . entries ( fields ) ) {
161+ body += `--${ boundary } \r\n` ;
162+ body += `Content-Disposition: form-data; name="${ name } "\r\n\r\n` ;
163+ body += `${ value } \r\n` ;
164+ }
165+ body += `--${ boundary } --\r\n` ;
166+ return body ;
167+ } ;
168+
169+ /**
170+ * Check if a request is a multipart form data request, if so, return the
171+ * boundary
172+ */
173+ export const getBoundary = ( request : Protocol . Network . Request ) => {
174+ const contentType = request . headers [ 'Content-Type' ] ?? request . headers [ 'content-type' ] ?? '' ;
175+ const boundary = contentType . split ( 'boundary=' ) [ 1 ] ;
176+ return boundary ;
177+ } ;
0 commit comments