@@ -110,40 +110,85 @@ const getHonoInput = async (c: Context) => {
110
110
111
111
try {
112
112
const contentType = c . req . header ( 'content-type' ) || '' ;
113
+
113
114
if ( typeIs . is ( contentType , [ 'application/json' ] ) ) {
114
115
try {
115
- draft . data = await c . req . json ( ) ;
116
+ const rawBody = await resolveRawBody ( c ) ;
117
+ const decodedBody = decodeBuffer ( rawBody , contentType ) ;
118
+ draft . data = safeJsonParse ( decodedBody ) ;
116
119
} catch {
117
120
draft . data = { } ;
118
121
}
119
122
} else if ( typeIs . is ( contentType , [ 'multipart/form-data' ] ) ) {
120
- const formData = await resolveHonoFormData ( c ) ;
121
- draft . formData = formData ;
123
+ draft . formData = await resolveFormData ( c ) ;
122
124
} else if ( typeIs . is ( contentType , [ 'application/x-www-form-urlencoded' ] ) ) {
123
- draft . formUrlencoded = await c . req . parseBody ( ) ;
125
+ const rawBody = await resolveRawBody ( c ) ;
126
+ const decodedBody = decodeBuffer ( rawBody , contentType ) ;
127
+ draft . formUrlencoded = parseUrlEncoded ( decodedBody ) ;
124
128
} else {
125
- draft . body = await c . req . parseBody ( ) ;
129
+ const rawBody = await resolveRawBody ( c ) ;
130
+ draft . body = rawBody . toString ( 'utf8' ) ;
126
131
}
127
132
} catch ( error ) {
128
133
draft . body = null ;
129
134
}
130
135
return draft ;
131
136
} ;
132
137
133
- const resolveHonoFormData = ( c : Context ) : Promise < Record < string , any > > => {
134
- const form = formidable ( { multiples : true } ) ;
138
+ const resolveFormData = ( c : Context ) : Promise < Record < string , any > > => {
135
139
return new Promise ( ( resolve , reject ) => {
136
- form . parse ( c . env . node ?. req , ( err , fields , files ) => {
137
- if ( err ) {
138
- reject ( err ) ;
139
- }
140
+ try {
141
+ const nodeReadable = c . env . node ?. req ;
140
142
141
- resolve ( {
142
- ...fields ,
143
- ...files ,
143
+ if ( ! c . env . node ?. req ) return { } ;
144
+
145
+ nodeReadable . headers = {
146
+ 'content-type' : c . env . node . req . headers [ 'content-type' ] ,
147
+ 'content-length' : c . env . node . req . headers [ 'content-length' ] ,
148
+ } ;
149
+ const form = formidable ( {
150
+ multiples : true ,
144
151
} ) ;
145
- } ) ;
152
+
153
+ form . parse ( nodeReadable , ( err , fields , files ) => {
154
+ if ( err ) reject ( err ) ;
155
+ resolve ( { ...fields , ...files } ) ;
156
+ } ) ;
157
+ } catch ( error ) {
158
+ reject ( error ) ;
159
+ }
146
160
} ) ;
147
161
} ;
148
162
163
+ async function resolveRawBody ( c : Context ) : Promise < Buffer > {
164
+ const nodeReadable = c . env . node ?. req ;
165
+ if ( ! nodeReadable ) return Buffer . from ( '' ) ;
166
+
167
+ const chunks : Buffer [ ] = [ ] ;
168
+ for await ( const chunk of nodeReadable ) {
169
+ chunks . push ( Buffer . isBuffer ( chunk ) ? chunk : Buffer . from ( chunk ) ) ;
170
+ }
171
+ return Buffer . concat ( chunks as any ) ;
172
+ }
173
+
174
+ function decodeBuffer ( body : Buffer , contentType : string ) : string {
175
+ const charset = contentType . match ( / c h a r s e t = ( [ \w - ] + ) / ) ?. [ 1 ] || 'utf8' ;
176
+ return body . toString ( charset as BufferEncoding ) ;
177
+ }
178
+
179
+ function parseUrlEncoded ( data : string ) : Record < string , any > {
180
+ const params = new URLSearchParams ( data ) ;
181
+ return Object . fromEntries ( params . entries ( ) ) ;
182
+ }
183
+
184
+ function safeJsonParse ( data : string ) : Record < string , any > {
185
+ if ( ! data . trim ( ) ) return { } ;
186
+ try {
187
+ return JSON . parse ( data ) ;
188
+ } catch ( error ) {
189
+ const { message } = error as Error ;
190
+ throw new Error ( `Invalid JSON: ${ message ? message : 'parse error' } ` ) ;
191
+ }
192
+ }
193
+
149
194
export default createHonoRoutes ;
0 commit comments