Formidable: Better handling for file uploads. Now supports multiple keys
All checks were successful
continuous-integration/appveyor/branch AppVeyor build succeeded
All checks were successful
continuous-integration/appveyor/branch AppVeyor build succeeded
This commit is contained in:
parent
baf2d896c1
commit
5f916e97ea
5 changed files with 101 additions and 44 deletions
30
flaska.mjs
30
flaska.mjs
|
@ -248,29 +248,41 @@ export function FormidableHandler(formidable, org = {}) {
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.req.body = fields
|
ctx.req.body = fields
|
||||||
ctx.req.file = files?.file || null
|
ctx.req.files = files
|
||||||
|
ctx.req.file = null
|
||||||
|
|
||||||
if (!ctx.req.file) {
|
|
||||||
|
if (!ctx.req.files) {
|
||||||
return res()
|
return res()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let keys = Object.keys(files).filter(key => Boolean(ctx.req.files[key]))
|
||||||
|
|
||||||
|
Promise.all(
|
||||||
|
keys.map(key => {
|
||||||
let filename
|
let filename
|
||||||
let target
|
let target
|
||||||
|
|
||||||
try {
|
try {
|
||||||
filename = opts.filename(ctx.req.file) || ctx.req.file.name
|
filename = opts.filename(ctx.req.files[key]) || ctx.req.files[key].name
|
||||||
target = path.join(opts.uploadDir, filename)
|
target = path.join(opts.uploadDir, filename)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
return rej(err)
|
return Promise.reject(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
rename(ctx.req.file.path, target)
|
return rename(ctx.req.files[key].path, target)
|
||||||
.then(function() {
|
.then(function() {
|
||||||
ctx.req.file.path = target
|
ctx.req.files[key].path = target
|
||||||
ctx.req.file.filename = filename
|
ctx.req.files[key].filename = filename
|
||||||
})
|
})
|
||||||
.then(res, rej)
|
})
|
||||||
|
)
|
||||||
|
.then(() => {
|
||||||
|
if (keys.length === 1 && keys[0] === 'file') {
|
||||||
|
ctx.req.file = ctx.req.files.file
|
||||||
|
}
|
||||||
|
res()
|
||||||
|
}, rej)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "flaska",
|
"name": "flaska",
|
||||||
"version": "1.2.5",
|
"version": "1.3.0",
|
||||||
"description": "Flaska is a micro web-framework for node. It is designed to be fast, simple and lightweight, and is distributed as a single file module with no dependencies.",
|
"description": "Flaska is a micro web-framework for node. It is designed to be fast, simple and lightweight, and is distributed as a single file module with no dependencies.",
|
||||||
"main": "flaska.mjs",
|
"main": "flaska.mjs",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|
|
@ -126,27 +126,44 @@ const random = (length = 8) => {
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
Client.prototype.upload = function(url, file, method = 'POST', body = {}) {
|
Client.prototype.upload = function(url, files, method = 'POST', body = {}) {
|
||||||
return fs.readFile(file).then(data => {
|
|
||||||
const crlf = '\r\n'
|
|
||||||
const filename = path.basename(file)
|
|
||||||
const boundary = `---------${random(32)}`
|
const boundary = `---------${random(32)}`
|
||||||
|
const crlf = '\r\n'
|
||||||
|
let upload = files
|
||||||
|
|
||||||
const multipartBody = Buffer.concat([
|
if (typeof(upload) === 'string') {
|
||||||
Buffer.from(
|
upload = {
|
||||||
|
file: files
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let keys = Object.keys(upload)
|
||||||
|
let uploadBody = []
|
||||||
|
|
||||||
|
return Promise.all(keys.map(key => {
|
||||||
|
let file = upload[key]
|
||||||
|
return fs.readFile(file).then(data => {
|
||||||
|
const filename = path.basename(file)
|
||||||
|
|
||||||
|
uploadBody.push(Buffer.from(
|
||||||
`${crlf}--${boundary}${crlf}` +
|
`${crlf}--${boundary}${crlf}` +
|
||||||
`Content-Disposition: form-data; name="file"; filename="${filename}"` + crlf + crlf
|
`Content-Disposition: form-data; name="${key}"; filename="${filename}"` + crlf + crlf
|
||||||
),
|
))
|
||||||
data,
|
uploadBody.push(data)
|
||||||
|
})
|
||||||
|
}))
|
||||||
|
.then(() => {
|
||||||
|
uploadBody.push(
|
||||||
Buffer.concat(Object.keys(body).map(function(key) {
|
Buffer.concat(Object.keys(body).map(function(key) {
|
||||||
return Buffer.from(''
|
return Buffer.from(''
|
||||||
+ `${crlf}--${boundary}${crlf}`
|
+ `${crlf}--${boundary}${crlf}`
|
||||||
+ `Content-Disposition: form-data; name="${key}"` + crlf + crlf
|
+ `Content-Disposition: form-data; name="${key}"` + crlf + crlf
|
||||||
+ JSON.stringify(body[key])
|
+ JSON.stringify(body[key])
|
||||||
)
|
)
|
||||||
})),
|
}))
|
||||||
Buffer.from(`${crlf}--${boundary}--`),
|
)
|
||||||
])
|
uploadBody.push(Buffer.from(`${crlf}--${boundary}--`))
|
||||||
|
|
||||||
|
let multipartBody = Buffer.concat(uploadBody)
|
||||||
|
|
||||||
return this.customRequest(method, url, multipartBody, {
|
return this.customRequest(method, url, multipartBody, {
|
||||||
timeout: 5000,
|
timeout: 5000,
|
||||||
|
|
|
@ -60,6 +60,13 @@ flaska.post('/file/upload', FormidableHandler(formidable, {
|
||||||
uploaded.push(ctx.req.file)
|
uploaded.push(ctx.req.file)
|
||||||
ctx.body = ctx.req.file
|
ctx.body = ctx.req.file
|
||||||
})
|
})
|
||||||
|
flaska.post('/file/upload/many', FormidableHandler(formidable, {
|
||||||
|
uploadDir: './test/upload',
|
||||||
|
}), function(ctx) {
|
||||||
|
uploaded.push(ctx.req.files.herp)
|
||||||
|
uploaded.push(ctx.req.files.derp)
|
||||||
|
ctx.body = ctx.req.files
|
||||||
|
})
|
||||||
flaska.get('/file/leak', function(ctx) {
|
flaska.get('/file/leak', function(ctx) {
|
||||||
file = fsSync.createReadStream('./test/test.png')
|
file = fsSync.createReadStream('./test/test.png')
|
||||||
ctx.body = file
|
ctx.body = file
|
||||||
|
@ -308,6 +315,27 @@ t.describe('/file/upload', function() {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.describe('/file/upload/many', function() {
|
||||||
|
t.test('server should upload file', async function() {
|
||||||
|
let res = await client.upload('/file/upload/many', {
|
||||||
|
herp: './test/test.jpg',
|
||||||
|
derp: './test/test.png',
|
||||||
|
})
|
||||||
|
|
||||||
|
let [statSourcePng, statSourceJpg, statTargetHerp, statTargetDerp] = await Promise.all([
|
||||||
|
fs.stat('./test/test.png'),
|
||||||
|
fs.stat('./test/test.jpg'),
|
||||||
|
fs.stat(res.herp.path),
|
||||||
|
fs.stat(res.derp.path),
|
||||||
|
])
|
||||||
|
|
||||||
|
assert.strictEqual(statSourceJpg.size, statTargetHerp.size)
|
||||||
|
assert.strictEqual(statSourceJpg.size, res.herp.size)
|
||||||
|
assert.strictEqual(statSourcePng.size, statTargetDerp.size)
|
||||||
|
assert.strictEqual(statSourcePng.size, res.derp.size)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
t.describe('HEAD', function() {
|
t.describe('HEAD', function() {
|
||||||
const agent = new http.Agent({
|
const agent = new http.Agent({
|
||||||
keepAlive: true,
|
keepAlive: true,
|
||||||
|
|
BIN
test/test.jpg
Normal file
BIN
test/test.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 32 KiB |
Loading…
Reference in a new issue