@middy/http-multipart-body-parser
Advanced tools
Comparing version 5.0.0-alpha.0 to 5.0.0-alpha.1
186
index.js
@@ -1,87 +0,107 @@ | ||
import BusBoy from 'busboy'; | ||
import { createError } from '@middy/util'; | ||
const mimePattern = /^multipart\/form-data(;.*)?$/; | ||
const fieldnamePattern = /(.+)\[(.*)]$/; | ||
import BusBoy from 'busboy' | ||
import { createError } from '@middy/util' | ||
const mimePattern = /^multipart\/form-data(;.*)?$/ | ||
const fieldnamePattern = /(.+)\[(.*)]$/ | ||
const defaults = { | ||
busboy: {}, | ||
charset: 'utf8', | ||
disableContentTypeError: true | ||
}; | ||
const httpMultipartBodyParserMiddleware = (opts = {})=>{ | ||
const options = { | ||
...defaults, | ||
...opts | ||
}; | ||
const httpMultipartBodyParserMiddlewareBefore = async (request)=>{ | ||
const { headers } = request.event; | ||
const contentType = headers['Content-Type'] ?? headers['content-type']; | ||
if (!mimePattern.test(contentType)) { | ||
if (options.disableContentTypeError) { | ||
return; | ||
} | ||
throw createError(415, 'Unsupported Media Type', { | ||
cause: contentType | ||
}); | ||
// busboy options as per documentation: https://www.npmjs.com/package/busboy#busboy-methods | ||
busboy: {}, | ||
charset: 'utf8', | ||
disableContentTypeError: false | ||
} | ||
const httpMultipartBodyParserMiddleware = (opts = {}) => { | ||
const options = { ...defaults, ...opts } | ||
const httpMultipartBodyParserMiddlewareBefore = async (request) => { | ||
const { headers } = request.event | ||
const contentType = headers?.['Content-Type'] ?? headers?.['content-type'] | ||
if (!mimePattern.test(contentType)) { | ||
if (options.disableContentTypeError) { | ||
return | ||
} | ||
throw createError(415, 'Unsupported Media Type', { | ||
cause: { package: '@middy/multipart-body-parser', data: contentType } | ||
}) | ||
} | ||
return parseMultipartData(request.event, options) | ||
.then((multipartData) => { | ||
// request.event.rawBody = body | ||
request.event.body = multipartData | ||
}) | ||
.catch((err) => { | ||
// UnprocessableEntity | ||
throw createError( | ||
415, | ||
'Invalid or malformed multipart/form-data was provided', | ||
{ cause: { package: '@middy/multipart-body-parser', data: err } } | ||
) | ||
}) | ||
} | ||
return { | ||
before: httpMultipartBodyParserMiddlewareBefore | ||
} | ||
} | ||
const parseMultipartData = (event, options) => { | ||
const multipartData = {} | ||
const charset = event.isBase64Encoded ? 'base64' : options.charset | ||
// header must be lowercase (content-type) | ||
const busboy = BusBoy({ | ||
...options.busboy, | ||
headers: { | ||
'content-type': | ||
event.headers['Content-Type'] ?? event.headers['content-type'] | ||
} | ||
}) | ||
return new Promise((resolve, reject) => { | ||
busboy | ||
.on('file', (fieldname, file, info) => { | ||
const { filename, encoding, mimeType: mimetype } = info | ||
const attachment = { | ||
filename, | ||
mimetype, | ||
encoding | ||
} | ||
return parseMultipartData(request.event, options).then((multipartData)=>{ | ||
request.event.body = multipartData; | ||
}).catch((cause)=>{ | ||
throw createError(415, 'Invalid or malformed multipart/form-data was provided', { | ||
cause | ||
}); | ||
}); | ||
}; | ||
return { | ||
before: httpMultipartBodyParserMiddlewareBefore | ||
}; | ||
}; | ||
const parseMultipartData = (event, options)=>{ | ||
const multipartData = {}; | ||
const charset = event.isBase64Encoded ? 'base64' : options.charset; | ||
const busboy = BusBoy({ | ||
...options.busboy, | ||
headers: { | ||
'content-type': event.headers['Content-Type'] ?? event.headers['content-type'] | ||
const chunks = [] | ||
file.on('data', (data) => { | ||
chunks.push(data) | ||
}) | ||
file.on('end', () => { | ||
attachment.truncated = file.truncated | ||
attachment.content = Buffer.concat(chunks) | ||
if (!multipartData[fieldname]) { | ||
multipartData[fieldname] = attachment | ||
} else { | ||
const current = multipartData[fieldname] | ||
multipartData[fieldname] = [attachment].concat(current) | ||
} | ||
}) | ||
}) | ||
.on('field', (fieldname, value) => { | ||
const matches = fieldname.match(fieldnamePattern) | ||
if (!matches) { | ||
multipartData[fieldname] = value | ||
} else { | ||
if (!multipartData[matches[1]]) { | ||
multipartData[matches[1]] = [] | ||
} | ||
multipartData[matches[1]].push(value) | ||
} | ||
}); | ||
return new Promise((resolve, reject)=>{ | ||
busboy.on('file', (fieldname, file, info)=>{ | ||
const { filename , encoding , mimeType: mimetype } = info; | ||
const attachment = { | ||
filename, | ||
mimetype, | ||
encoding | ||
}; | ||
const chunks = []; | ||
file.on('data', (data)=>{ | ||
chunks.push(data); | ||
}); | ||
file.on('end', ()=>{ | ||
attachment.truncated = file.truncated; | ||
attachment.content = Buffer.concat(chunks); | ||
if (!multipartData[fieldname]) { | ||
multipartData[fieldname] = attachment; | ||
} else { | ||
const current = multipartData[fieldname]; | ||
multipartData[fieldname] = [ | ||
attachment | ||
].concat(current); | ||
} | ||
}); | ||
}).on('field', (fieldname, value)=>{ | ||
const matches = fieldname.match(fieldnamePattern); | ||
if (!matches) { | ||
multipartData[fieldname] = value; | ||
} else { | ||
if (!multipartData[matches[1]]) { | ||
multipartData[matches[1]] = []; | ||
} | ||
multipartData[matches[1]].push(value); | ||
} | ||
}).on('close', ()=>resolve(multipartData)).on('error', (e)=>reject(e)); | ||
busboy.write(event.body, charset); | ||
busboy.end(); | ||
}); | ||
}; | ||
export default httpMultipartBodyParserMiddleware; | ||
}) | ||
.on('close', () => resolve(multipartData)) | ||
.on('error', (e) => reject(e)) | ||
busboy.write(event.body, charset) | ||
busboy.end() | ||
}) | ||
} | ||
export default httpMultipartBodyParserMiddleware |
{ | ||
"name": "@middy/http-multipart-body-parser", | ||
"version": "5.0.0-alpha.0", | ||
"version": "5.0.0-alpha.1", | ||
"description": "Http event normalizer middleware for the middy framework", | ||
@@ -13,3 +13,2 @@ "type": "module", | ||
}, | ||
"main": "./index.cjs", | ||
"module": "./index.js", | ||
@@ -21,6 +20,2 @@ "exports": { | ||
"default": "./index.js" | ||
}, | ||
"require": { | ||
"types": "./index.d.ts", | ||
"default": "./index.cjs" | ||
} | ||
@@ -32,3 +27,2 @@ } | ||
"index.js", | ||
"index.cjs", | ||
"index.d.ts" | ||
@@ -72,11 +66,11 @@ ], | ||
"dependencies": { | ||
"@middy/util": "5.0.0-alpha.0", | ||
"@middy/util": "5.0.0-alpha.1", | ||
"busboy": "1.6.0" | ||
}, | ||
"devDependencies": { | ||
"@middy/core": "5.0.0-alpha.0", | ||
"@middy/core": "5.0.0-alpha.1", | ||
"@types/aws-lambda": "^8.10.101", | ||
"type-fest": "^3.0.0" | ||
"type-fest": "^4.0.0" | ||
}, | ||
"gitHead": "08c35e3dba9efdad0b86666ce206ce302cc65d07" | ||
"gitHead": "ebce8d5df8783077fa49ba62ee9be20e8486a7f1" | ||
} |
@@ -22,4 +22,5 @@ <div align="center"> | ||
</a> | ||
<a href="https://lgtm.com/projects/g/middyjs/middy/context:javascript"> | ||
<img src="https://img.shields.io/lgtm/grade/javascript/g/middyjs/middy.svg?logo=lgtm&logoWidth=18" alt="Language grade: JavaScript" style="max-width:100%;"> | ||
<a href="https://github.com/middyjs/middy/actions/workflows/sast.yml"> | ||
<img src="https://github.com/middyjs/middy/actions/workflows/sast.yml/badge.svg | ||
?branch=main&event=push" alt="CodeQL" style="max-width:100%;"> | ||
</a> | ||
@@ -26,0 +27,0 @@ <a href="https://bestpractices.coreinfrastructure.org/projects/5280"> |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
47
9604
5
124
1
+ Added@middy/util@5.0.0-alpha.1(transitive)
- Removed@middy/util@5.0.0-alpha.0(transitive)
Updated@middy/util@5.0.0-alpha.1