Macro-swift / MacroExpress

An unopinionated SwiftNIO based web framework, Express.js/Connect like.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Support `multipart/form-data` uploads

helje5 opened this issue · comments

We need a body parser for multipart/form-data uploads, as per apple/swift-nio#1724 (comment)

I.e. to handle things like

<form action="/upload" method="POST" enctype="multipart/form-data">
     <input type="file" id="filename" name="file" onchange="onchanged()" multiple="multiple" />
     <input type="submit" value="Upload">
</form>

Need to check whether there is a more official Node API for that. Generally I'd think this should stream the files to a temporary location, keep the file handles open, but unlink them - or just regular tmpfiles. The body structure would then have a reference to the file handles.

RFC: https://tools.ietf.org/html/rfc7578

Multer seems to be the default Node thing: https://www.npmjs.com/package/multer

var upload = multer({ dest: 'uploads/' })
app.post('/profile',               upload.single('avatar'),       function (req, res, next) {})
app.post('/photos/upload', upload.array('photos', 12), function (req, res, next) {})
app.post('/profile',               upload.none(),                     function (req, res, next) {})

// req.files is array of `photos` files
// req.body will contain the text fields, if there were any

File info: filename, originalname, encoding, mimetype, size, destination (DiskStorage), filename, path, buffer

Options:

  • dest (path) or storage (xyzStorage)
  • fileFilter
  • limits
  • preservePath

DiskStorage or MemoryStorage:

var storage = multer.diskStorage({
  destination: function (req, file, cb) {
    cb(null, '/tmp/my-uploads')
  },
  filename: function (req, file, cb) {
    cb(null, file.fieldname + '-' + Date.now())
  }
})
 
var upload = multer({ storage: storage })

var storage = multer.memoryStorage()
var upload = multer({ storage: storage })

The feature/multipart-formdata-1 now has an apparently working multipart/form-data parser, with quite a few tests. Only the MemoryStorage is supported so far, DiskStorage would require more async hops.

Performance doesn't seem to be too great yet, uploading a 3MB image (locally) takes 255ms in release (4s in debug), which seems a little slow for an M1 Mini. Need to check where the time gets lost.

Uploading my 3MB test image on M1 now takes 2ms in release (12ms in Debug), which seems quite reasonable. 100 MB take about 50ms, which also sounds OK.

What we don't have yet is DiskStorage (though it's prepared), I put that into a separate Issue #8.

The multer module is available in 0.8.0.

@helje5
Thank you very much!