Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reading multipartform-data stream correctly (NodeJS)

I'm trying to receive a multipartform-data stream which might include various files and fields and to write the files to a directory (uWebsockets.js server). I have this code:

    let boundary = null;
    let fields = [];
    let streams = [];
    let keep = false;
    res.onData((chunk, isLast) => {
        const buff = Buffer.concat([Buffer.from(chunk)]).toString('binary').split('\r\n');
        if (!boundary) {
            boundary = buff[0];
        }
        for (let i = 0; i < buff.length; i++) {

            const line = buff[i];
            if (i > 0 && i < buff.length - 1 && line == '') {
                keep = true;
                continue;
            }
            if (line == boundary || line == boundary + '--') {
                keep = false;
                if (streams[fields.length - 1]) {
                    streams[fields.length - 1].end();
                }
            }
            if (line == boundary) {
                fields[fields.length] = {};
            }

            if (line.includes('Content-Disposition')) {
                if (line.includes('filename="')) {
                    fields[fields.length - 1].filename = getFilename(line);
                    fields[fields.length - 1].type = 'file';
                    fields[fields.length - 1].path = path.resolve(options.uploadPath + fields[fields.length - 1].filename);
                    streams[fields.length - 1] = fs.createWriteStream(
                        path.resolve(options.uploadPath + fields[fields.length - 1].filename)
                    );
                } else {
                    fields[fields.length - 1].type = 'field';
                }
                fields[fields.length - 1].name = getField(line);
            }
            if (line.includes('Content-Type')) {
                fields[fields.length - 1].contentType = line.split('Content-Type: ')[1];
            }

            if (keep == true) {
                if (fields[fields.length - 1].filename) {
                    streams[streams.length - 1].write(Buffer.from(line + "\r\n", 'binary'));
                } else {
                    fields[fields.length - 1].value += line;
                }
            }
        }

        if (isLast) {
            console.log(fields);
        }
    });

It works except that uploaded images are corrupted and are cut in randomly (Not the same in every image, some are totally corrupted and some are perfectly fine). Could someone point out what is wrong with it?

Thanks in advance :)

like image 568
Daniel Shlomo Avatar asked Oct 27 '25 10:10

Daniel Shlomo


2 Answers

same situation here, i am using uwebsocket.js for uploading mp4 file, i try your code to upload mp4, it's uploaded but cannot be play. then i try to compare original file with uploaded file, the file size has change a litle bit.

then i realize in your code :

streams[streams.length - 1].write(Buffer.from(line + "\r\n", 'binary'));

when split by "\r\n" last of array should not have "\r\n" than i add some condition below :

if (i==buff.length-1)
   streams[streams.length - 1].write(Buffer.from(line, 'binary'));
else {
   if (i+1<buff.length) {
      if (buff[i+1]==boundary + '--')
         streams[streams.length - 1].write(Buffer.from(line, 'binary'));
      else
         streams[streams.length - 1].write(Buffer.from(line + "\r\n", 'binary'));
   }
}

and now my uploaded mp4 play well.

thanks....

sorry for my bad english

like image 143
sehari3kali Avatar answered Oct 28 '25 23:10

sehari3kali


probability problem is max length. change this value on uwebsocket.js. best way is form data for upload file.

change this:

maxPayloadLength: 512

more detail: https://unetworking.github.io/uWebSockets.js/generated/interfaces/websocketbehavior.html#maxpayloadlength

like image 38
eay Avatar answered Oct 28 '25 22:10

eay



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!