formidable icon indicating copy to clipboard operation
formidable copied to clipboard

ContentType: text/plain not showing in fields

Open neronim1141 opened this issue 2 years ago • 16 comments

Support plan

  • Which support plan is this issue covered by? Community
  • Currently blocking your project/work? yes
  • Affecting a production system? yes

Context

  • Node.js version: 16.13.1
  • Release Line of Formidable (Legacy, Current, Next): Next
  • Formidable exact version: 3.2.4
  • Environment (node, browser, native, OS): node
  • Used with (popular names of modules): nextjs, next-connect

What are you trying to achieve or the steps to reproduce?

Im trying to make custom server functionality on nextjs api route, where i get some request data from game as "multipart/form-data;" but some of the data has "text/plain" content type.

router.post(async (req, res) => {

  const form = new IncomingForm();
  form.parse(req, (err, fields, files) => {
    console.log(fields);
    console.log(files);
  });

  res.end();
});

export const config = {
  api: {
    bodyParser: false,
  },
};

What was the result you got?

Only the files variable gets populated. As i needed to disable parser for nextjs i cant really use req.body. looping for 'text/plain' mimetype in files and parsing them manualy is not desired either

What result did you expect?

'text/plain' content type parsed into fields variable

neronim1141 avatar Aug 01 '22 13:08 neronim1141

If I understand correctly you want to access files sent as text/plain as if it was another field ?

GrosSacASac avatar Aug 01 '22 17:08 GrosSacASac

This line in the code separates fields from files: if (!part.mimetype) {

So if you don't have a mimetype it will appear as a field

GrosSacASac avatar Aug 01 '22 17:08 GrosSacASac

Yes, i managed to do it in an ugly way around

for (let [fileField, filesArray] of Object.entries(files)) {
          const file = (filesArray as File[])[0];
          switch (fileField) {
            case "id":
              id = await fileToString(file.filepath);
              fs.rm(file.filepath);
              break;
            case "extraData":
              extraData = JSON.parse(await fileToString(file.filepath));
              fs.rm(file.filepath);
              break;
            default:
              tile = file;
              break;
          }
        }

but i think as text/plain usually contain string, if they arent too big maybe they should convert to fileds also?

for disclaimer i cant really change how i receive data, and 'id','extradata' are bassically oneliners i remember that i used that API with multer some time ago and it was quite simple

neronim1141 avatar Aug 01 '22 21:08 neronim1141

Do you suggest to change formidable ?

GrosSacASac avatar Aug 02 '22 19:08 GrosSacASac

@GrosSacASac I would like to see this change as well, I missed this issue but I commented about running into the same problem in #495

ajmeese7 avatar Aug 03 '22 14:08 ajmeese7

What exactly should change ?

GrosSacASac avatar Aug 03 '22 22:08 GrosSacASac

if mimetype is text/plain it should be decoded into fields instead of file with provided charset, unless explicity specified, or allow us to exclude fields from converting to files

neronim1141 avatar Aug 05 '22 14:08 neronim1141

not automatically, and not default behavior

or allow us to exclude fields from converting to files

yep, through option.

tunnckoCore avatar Aug 09 '22 14:08 tunnckoCore

Formidable v1 used to put "a" in fields for:

Invoke-RestMethod -Uri '...' -Method Post -Form  @{ a = 'A'; file = Get-Item -Path '.\foo.txt' }

which sends:

Content-Type: text/plain; charset=utf-8
Content-Disposition: form-data; name="a"

Upgrading to Formidable v2 broke my app.

NB: curl does not send "Content-Type" for non-files.

prigaux avatar Nov 28 '22 14:11 prigaux

Workaround tested on v2:

form.onPart = function (part) {
    if (part.mimetype && !part.headers['content-disposition']?.match(/filename="/)) {
        // we want it to be a "field" (cf https://github.com/node-formidable/formidable/issues/875 )
        delete part.mimetype
    }
    form._handlePart(part);
}

prigaux avatar Nov 28 '22 14:11 prigaux

I have the same issue. My user is calling my API with a C# client. Their multipart/form implemtation always adds the text/plain mimetype. To solve the issue, I have to apply the solution from @prigaux above.

I think this should be fixed upstream in this library, no?

okcompute avatar Feb 25 '23 03:02 okcompute

That's why we even expose internals and allow overriding, so it can be extended. ;)

Converting text/plain to fields by passing some option, could be a good feature too.

Formidable v1 used to put "a" in fields for:

Really strange.. :D Never noticed that, or I forgot it. That's weird. And what happens when multiple? Multiple as or what? haha.

tunnckoCore avatar Mar 06 '23 21:03 tunnckoCore

I can confirm that there's no way to succesfully get fields data from submited forms using HttpClient on C# Had no previous issues using v1 @prigaux workaround works great!

CollapsedMetal avatar Apr 19 '23 21:04 CollapsedMetal

So, the code used to look at the existence of a filename and would consider it a field if a file name did not exist.

I've been tracing back the code and it used to be what I would consider correct: https://github.com/node-formidable/formidable/blob/15f174f2457684fbfb76197fced22ae0fa52e8b2/src/incoming_form.js#L195

But then was changed to look at mime type here: https://github.com/node-formidable/formidable/commit/621e72a4deac6acf5f47f84986648d908eb2ae89

I'm not really sure what the change fixed, but it's not correct. A field is a file if it contains a filename. Otherwise, it's a field. Right??

kkirby avatar Apr 21 '23 18:04 kkirby

As of now only workaround by @prigaux is working, Is there any fix in library? I am using Retrofit as client in Android app.

pankaj89 avatar Dec 28 '23 08:12 pankaj89

I am using this code:

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);
    }

After add 'onPart' function, the uploaded file can not open any more; if I comment them, the uploaded file can open again.

msojocs avatar Apr 03 '24 12:04 msojocs