uNetworking / uWebSockets.js

μWebSockets for Node.js back-ends :metal:
Apache License 2.0
7.76k stars 563 forks source link

multipart/form-data corrupted #928

Closed gabrielcursino closed 1 year ago

gabrielcursino commented 1 year ago

I have these code below:

private async getBody(res: UHttpResponse): Promise<string> {
    let body = '';

    return new Promise(resolve => res.onData((ab, isLast) => {
      const chunk = Buffer.from(ab);
      body += chunk.toString();

      if (isLast) resolve(body);
    }));
  }
private parseBody(body: string, contentType: string) {
    if (!body) return {};

    if (contentType === 'application/json') return JSON.parse(body);
    if (contentType === 'application/x-www-form-urlencoded') return parseQuery(body);
    if (contentType.startsWith('multipart/form-data')) return getParts(body, contentType)?.reduce((all, p) => {
      all[p.name] = p;

      return all;
    }, {} as any);

    return body;
  }

they, works fine for application/json and application/x-www-form-urlencoded, but for multipart/form-data the result seems wrong

For example, for multipart/form-data i have this output:

Content-Length: 56741
Body length: 53663

{
  um: {
    data: ArrayBuffer { [Uint8Contents]: <64 6f 69 73>, byteLength: 4 },
    name: 'um'
  },
  file: {
    data: ArrayBuffer {
      [Uint8Contents]: <ef bf bd 50 4e 47 0d 0a 1a 0a 00 00 00 0d 49 48 44 52 00 00 04 38 00 00 04 38 08 06 00 00 00 ef bf bd 10 6c ef bf bd 00 00 00 09 70 48 59 73 00 00 0e ef bf bd 00 00 0e ef bf bd 01 ef bf bd 2b 0e 1b 00 00 00 3b 74 45 58 74 43 6f 6d 6d 65 6e 74 00 78 72 3a 64 3a 44 41 46 6d 64 56 33 41 64 74 30 3a 33 ... 97758 more bytes>,
      byteLength: 97858
    },
    name: 'file',
    filename: 'Insight - 40.png',
    type: 'image/png'
  },
  'três': {
    data: ArrayBuffer { [Uint8Contents]: <71 75 61 74 72 6f>, byteLength: 6 },
    name: 'três'
  }
}

Content-Length and body length are different, and when i try to upload the file array buffer, i get a corrupted test.png file

const upload = (ab: ArrayBuffer): Promise<{ name: string, type: string}> => {
  return new Promise(async (resolve, reject) => {
    const filename = `test.png`;

    writeFile(`${filename}`, Buffer.from(ab), e => {
      if (e) return reject(e);

      resolve({ name: filename, type: 'image/png' });
    });
  });
}

Am i doing something wrong?

For more detailed code see @ionited/fiber

e3dio commented 1 year ago

body += chunk.toString();

Images are binary data, you are taking chunks of binary and converting to utf-8 string which cannot represent binary data, then you give bad string to getParts function

gabrielcursino commented 1 year ago

Thanks for the clarification @e3dio!

It is working fine now!