node-formidable / formidable

The most used, flexible, fast and streaming parser for multipart form data. Supports uploading to serverless environments, AWS S3, Azure, GCP or the filesystem. Used in production.
MIT License
7k stars 680 forks source link

Support the contentType of multipart field. #974

Closed msojocs closed 2 months ago

msojocs commented 2 months ago

Support plan

Context

What problem are you trying to solve?

const form = formidable({
        uploadDir: storagePath,
        createDirsFromUploads: true,
        keepExtensions: true,
    });
    form.parse<'chatType' | 'peerUid' | 'guildId', "file">(req, (err, fields, files) => {
        if (err) {
            log.error('file parse error:', err)
            next(err);
            return;
        }

            log.info('fields:', fields);
            log.info('files:', files);
    })

If the 'Content-Type' was set, formidable wil parse the field as file.

raw data:

POST http://127.0.0.1:8081/group/uploadFile HTTP/1.1
User-Agent: Apifox/1.0.0 (https://apifox.com)
Accept: */*
Host: 127.0.0.1:8081
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
Content-Type: multipart/form-data; boundary=--------------------------420820768465130987175823
Content-Length: 279

----------------------------420820768465130987175823
Content-Disposition: form-data; name="chatType"

2
----------------------------420820768465130987175823
Content-Disposition: form-data; name="peerUid"
Content-Type: text/plain; charset=UTF-8

933286835
----------------------------420820768465130987175823--

result:

[2024-04-03 16:55:10.629] [info] [UploadFile] fields: { chatType: [ '2' ] }
[2024-04-03 16:55:10.629] [info] [UploadFile] files: {
  peerUid: [
    PersistentFile {
      _events: [Object: null prototype],
      _eventsCount: 1,
      _maxListeners: undefined,
      lastModifiedDate: 2024-04-03T08:55:10.629Z,
      filepath: 'D:\\GitHub\\Yukihana\\tmp\\storage\\7a8a74440325b47b92e55aa03',
      newFilename: '7a8a74440325b47b92e55aa03',
      originalFilename: null,
      mimetype: 'text/plain; charset=UTF-8',
      hashAlgorithm: false,
      size: 9,
      _writeStream: [WriteStream],
      hash: null,
      [Symbol(kCapture)]: false
    }
  ]
}

As you can see, when I set the contentType of field named peerUid(text/plain), it will be parsed as file.

Maybe we can just supprt the contentType text and file.

Do you have a new or modified API suggestion to solve the problem?

msojocs commented 2 months ago

https://github.com/node-formidable/formidable/issues/875

msojocs commented 2 months ago
const form = formidable({
        uploadDir: storagePath,
        createDirsFromUploads: true,
        keepExtensions: true,
    });
    form.onPart =  function (part) {
        log.info('part:', part)
        if (part.mimetype && !(part as any).headers['content-disposition']?.match(/filename="/)) {
            // we want it to be a "field" (cf https://github.com/node-formidable/formidable/issues/875 )
            part.mimetype = null
        }
        form._handlePart(part);
    }