octet-stream / form-data

Spec-compliant FormData implementation for Node.js
https://www.npmjs.com/package/formdata-node
MIT License
142 stars 17 forks source link

Append part of file only, not the whole file #56

Closed leopucci closed 2 years ago

leopucci commented 2 years ago

Hey there! Nice work so far!

formData.set('file', fileFromPathSync(filePath),0,1024);//just first 1024 bytes

Do you know how could I append to the form only some part of the file without buffering on the heap?

jimmywarting commented 2 years ago

fileFromPathSync returns a standard web File class (aka blob) you don't actually read anything into memory by using it - you only stat the file size and last modified date and making a references point to where it can read from/to.

// nothing is held in memory (just a references point)
const file = fileFromPathSync(path)

// nothing is held in memory (just a references point \w a offset to where to start reading from and stopping)
const blobSlice = file.slice(0, 1024, file.type)

formData.set('file', chunk, file.name)
octet-stream commented 2 years ago

The fileFromPath function creates regular File, so you can slice it like that:

const file = fileFromPathSync(filePath) // This will create a reference to file on disk and not actually read that.

form.set("file", file.slice(0, 1024), file.name) // .slice() will return Blob, so don't forget to provide a name in a third argument, if you want to keep it
leopucci commented 2 years ago

Thank you @jimmywarting and @octet-stream!

jimmywarting commented 2 years ago

no problem fyi, the only time it will actually read the blob/file content into memory is when the formdata is being serialized into a multipart payload and it needs to be read in order encode it

nothing is read into memory by just only appending some blob or file to the formdata instances.

http libraries iterates over all fields on the formdata, and when it encounters a file, then it will call file.stream() that starts reading the content from the drive in a streaming method

leopucci commented 2 years ago

Cool. Seems to be the best way to do it. Thanks @jimmywarting !

leopucci commented 2 years ago

He @jimmywarting and @octet-stream. File slice is working ok and I am being able to send part of a file on a stream.

But I am having trouble with accentuation çéáíó

I was using

const file = fileFromPathSync(filePath) 
form.set("file", file.slice(0, 1024), file.name) 

So i changed some chars to try to get this properly.

formData.set(
              'file',
              file.slice(0,1024),
              Buffer.from(file.name, 'utf-8').toString()
            );

Either way I am not getting the name correctly at the server side. Do you guys think on something about it? The strange thing is that on the other formData fields i am sending the same names but they arrive on the server correctly

I´m starting to think that this is not a form-data problem but on server side

leopucci commented 2 years ago

I´m having this behavior even with postman app, so it does not seems to be the form-data field that is messing with the server.

leopucci commented 2 years ago

Solved! It was at the other side. For some reason parameters was utf8 but for filenames the charset was latin1. Have a nice week @jimmywarting and @octet-stream