Skip to content

Instantly share code, notes, and snippets.

@Announcement
Last active March 28, 2018 03:49
Show Gist options
  • Save Announcement/3f1c23f6399b7e9bea27ce35e1e2bdc8 to your computer and use it in GitHub Desktop.
Save Announcement/3f1c23f6399b7e9bea27ce35e1e2bdc8 to your computer and use it in GitHub Desktop.
parse FormData
const expression = {}
expression.header_content_type = header_content_type: /(?<mimetype>(?<mimetype_type>[a-z]+|\*)\/(?<mimetype_subtype>[a-z][a-z0-9]*(?:\-[a-z0-9]+)*|\*))(?:\s*;\s*charset=(?<charset>\S+))?(?:\s*;\s*boundary=(?<boundary>\S+))?/
expression.header_content_type.exec(request.headers['content-type'])
if (method === 'POST' || method === 'PUT' || method === 'PATCH' || method === 'DELETE') {
let data
if ((/(?:text|application)\/json/).test(request_contentType.groups.mimetype)) {
data = JSON.parse(packet.toString('utf8'))
}
if ((/application\/x-www-form-urlencoded/).test(request_contentType.groups.mimetype)) {
data = querystring.parse(packet.toString('utf8'))
}
if ((/multipart\/form-data/).test(request_contentType.groups.mimetype)) {
data = dump(from_FormData(request_contentType.groups.boundary, packet.toString('utf8')))
}
}
function from_FormData (boundary, data) {
const indexes = getIndexes(boundary, data)
const boundaries = getBoundaries(boundary, data, ...indexes)
return dump(getFormData(...boundaries))
function dump (them) {
if (them instanceof Set) {
const array = []
for (const each of them)
each.push(dump(each))
return array
}
if (them instanceof Map) {
const object = {}
for (const [k, v] of them)
object[k] = dump(v)
return object
}
return them
}
function * getIndexes (subject, content) {
for (let index = 0; (index = content.indexOf(subject, index)) !== -1; index += subject.length)
yield index
}
function * getBoundaries (boundary, data, ...indexes) {
for (let i = 0; i < indexes.length - 1; i++) {
const bounds = [indexes[i] + boundary.length, indexes[i + 1]]
const content = data.substring(...bounds)
yield content
}
}
function getFormData (...boundaries) {
const expression = {}
expression.contentDisposition = /Content-Disposition:\s*(inline|attachment|form-data)(?:\s*\;\s*name="([^"]+)")?(?:\s*\;\s*filename\*?="([^"]+)")?(\r\n){2}/
expression.contentBody = /^([\s\S]+)\r\n$/
const formData = new Map
for (const boundary of boundaries) {
const contentDispositionPattern = expression.contentDisposition.exec(boundary)
if (!contentDispositionPattern) return {boundary, error: 'Could not find appropriate `Content-Disposition` header'}
const contentBodyPattern = boundary.substring(contentDispositionPattern.index + contentDispositionPattern[0].length)
const contentDisposition = contentDispositionPattern[1]
const name = contentDispositionPattern[2]
const filename = contentDispositionPattern[3]
const contentBodyIndex2 = contentBodyPattern.lastIndexOf('\r\n')
const contentBody = contentBodyPattern.substring(0, contentBodyIndex2)
const submission = filename ? { filename, contentBody } : contentBody
if (formData.has(name)) {
if (formData.get(name) instanceof Set) {
formData.get(name).add(submission)
} else {
formData.set(name, new Set([formData.get(name), submission]))
}
} else {
formData.set(name, submission)
}
}
return formData
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment