bpms_site/.svn/pristine/06/06468a4e3e747adcf668d40e26fd621d1a708150.svn-base
2025-11-02 16:38:49 +03:30

1054 lines
29 KiB
Plaintext

'use strict';
const assert = require('assert');
const { inspect } = require('util');
const busboy = require('..');
const active = new Map();
const tests = [
{ source: [
['-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
'Content-Disposition: form-data; name="file_name_0"',
'',
'super alpha file',
'-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
'Content-Disposition: form-data; name="file_name_1"',
'',
'super beta file',
'-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
'Content-Disposition: form-data; '
+ 'name="upload_file_0"; filename="1k_a.dat"',
'Content-Type: application/octet-stream',
'',
'A'.repeat(1023),
'-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
'Content-Disposition: form-data; '
+ 'name="upload_file_1"; filename="1k_b.dat"',
'Content-Type: application/octet-stream',
'',
'B'.repeat(1023),
'-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k--'
].join('\r\n')
],
boundary: '---------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
expected: [
{ type: 'field',
name: 'file_name_0',
val: 'super alpha file',
info: {
nameTruncated: false,
valueTruncated: false,
encoding: '7bit',
mimeType: 'text/plain',
},
},
{ type: 'field',
name: 'file_name_1',
val: 'super beta file',
info: {
nameTruncated: false,
valueTruncated: false,
encoding: '7bit',
mimeType: 'text/plain',
},
},
{ type: 'file',
name: 'upload_file_0',
data: Buffer.from('A'.repeat(1023)),
info: {
filename: '1k_a.dat',
encoding: '7bit',
mimeType: 'application/octet-stream',
},
limited: false,
},
{ type: 'file',
name: 'upload_file_1',
data: Buffer.from('B'.repeat(1023)),
info: {
filename: '1k_b.dat',
encoding: '7bit',
mimeType: 'application/octet-stream',
},
limited: false,
},
],
what: 'Fields and files'
},
{ source: [
['------WebKitFormBoundaryTB2MiQ36fnSJlrhY',
'Content-Disposition: form-data; name="cont"',
'',
'some random content',
'------WebKitFormBoundaryTB2MiQ36fnSJlrhY',
'Content-Disposition: form-data; name="pass"',
'',
'some random pass',
'------WebKitFormBoundaryTB2MiQ36fnSJlrhY',
'Content-Disposition: form-data; name=bit',
'',
'2',
'------WebKitFormBoundaryTB2MiQ36fnSJlrhY--'
].join('\r\n')
],
boundary: '----WebKitFormBoundaryTB2MiQ36fnSJlrhY',
expected: [
{ type: 'field',
name: 'cont',
val: 'some random content',
info: {
nameTruncated: false,
valueTruncated: false,
encoding: '7bit',
mimeType: 'text/plain',
},
},
{ type: 'field',
name: 'pass',
val: 'some random pass',
info: {
nameTruncated: false,
valueTruncated: false,
encoding: '7bit',
mimeType: 'text/plain',
},
},
{ type: 'field',
name: 'bit',
val: '2',
info: {
nameTruncated: false,
valueTruncated: false,
encoding: '7bit',
mimeType: 'text/plain',
},
},
],
what: 'Fields only'
},
{ source: [
''
],
boundary: '----WebKitFormBoundaryTB2MiQ36fnSJlrhY',
expected: [
{ error: 'Unexpected end of form' },
],
what: 'No fields and no files'
},
{ source: [
['-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
'Content-Disposition: form-data; name="file_name_0"',
'',
'super alpha file',
'-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
'Content-Disposition: form-data; '
+ 'name="upload_file_0"; filename="1k_a.dat"',
'Content-Type: application/octet-stream',
'',
'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
'-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k--'
].join('\r\n')
],
boundary: '---------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
limits: {
fileSize: 13,
fieldSize: 5
},
expected: [
{ type: 'field',
name: 'file_name_0',
val: 'super',
info: {
nameTruncated: false,
valueTruncated: true,
encoding: '7bit',
mimeType: 'text/plain',
},
},
{ type: 'file',
name: 'upload_file_0',
data: Buffer.from('ABCDEFGHIJKLM'),
info: {
filename: '1k_a.dat',
encoding: '7bit',
mimeType: 'application/octet-stream',
},
limited: true,
},
],
what: 'Fields and files (limits)'
},
{ source: [
['-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
'Content-Disposition: form-data; name="file_name_0"',
'',
'super alpha file',
'-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
'Content-Disposition: form-data; '
+ 'name="upload_file_0"; filename="1k_a.dat"',
'Content-Type: application/octet-stream',
'',
'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
'-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k--'
].join('\r\n')
],
boundary: '---------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
limits: {
files: 0
},
expected: [
{ type: 'field',
name: 'file_name_0',
val: 'super alpha file',
info: {
nameTruncated: false,
valueTruncated: false,
encoding: '7bit',
mimeType: 'text/plain',
},
},
'filesLimit',
],
what: 'Fields and files (limits: 0 files)'
},
{ source: [
['-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
'Content-Disposition: form-data; name="file_name_0"',
'',
'super alpha file',
'-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
'Content-Disposition: form-data; name="file_name_1"',
'',
'super beta file',
'-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
'Content-Disposition: form-data; '
+ 'name="upload_file_0"; filename="1k_a.dat"',
'Content-Type: application/octet-stream',
'',
'A'.repeat(1023),
'-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
'Content-Disposition: form-data; '
+ 'name="upload_file_1"; filename="1k_b.dat"',
'Content-Type: application/octet-stream',
'',
'B'.repeat(1023),
'-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k--'
].join('\r\n')
],
boundary: '---------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
expected: [
{ type: 'field',
name: 'file_name_0',
val: 'super alpha file',
info: {
nameTruncated: false,
valueTruncated: false,
encoding: '7bit',
mimeType: 'text/plain',
},
},
{ type: 'field',
name: 'file_name_1',
val: 'super beta file',
info: {
nameTruncated: false,
valueTruncated: false,
encoding: '7bit',
mimeType: 'text/plain',
},
},
],
events: ['field'],
what: 'Fields and (ignored) files'
},
{ source: [
['-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
'Content-Disposition: form-data; '
+ 'name="upload_file_0"; filename="/tmp/1k_a.dat"',
'Content-Type: application/octet-stream',
'',
'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
'-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
'Content-Disposition: form-data; '
+ 'name="upload_file_1"; filename="C:\\files\\1k_b.dat"',
'Content-Type: application/octet-stream',
'',
'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
'-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
'Content-Disposition: form-data; '
+ 'name="upload_file_2"; filename="relative/1k_c.dat"',
'Content-Type: application/octet-stream',
'',
'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
'-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k--'
].join('\r\n')
],
boundary: '---------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
expected: [
{ type: 'file',
name: 'upload_file_0',
data: Buffer.from('ABCDEFGHIJKLMNOPQRSTUVWXYZ'),
info: {
filename: '1k_a.dat',
encoding: '7bit',
mimeType: 'application/octet-stream',
},
limited: false,
},
{ type: 'file',
name: 'upload_file_1',
data: Buffer.from('ABCDEFGHIJKLMNOPQRSTUVWXYZ'),
info: {
filename: '1k_b.dat',
encoding: '7bit',
mimeType: 'application/octet-stream',
},
limited: false,
},
{ type: 'file',
name: 'upload_file_2',
data: Buffer.from('ABCDEFGHIJKLMNOPQRSTUVWXYZ'),
info: {
filename: '1k_c.dat',
encoding: '7bit',
mimeType: 'application/octet-stream',
},
limited: false,
},
],
what: 'Files with filenames containing paths'
},
{ source: [
['-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
'Content-Disposition: form-data; '
+ 'name="upload_file_0"; filename="/absolute/1k_a.dat"',
'Content-Type: application/octet-stream',
'',
'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
'-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
'Content-Disposition: form-data; '
+ 'name="upload_file_1"; filename="C:\\absolute\\1k_b.dat"',
'Content-Type: application/octet-stream',
'',
'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
'-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
'Content-Disposition: form-data; '
+ 'name="upload_file_2"; filename="relative/1k_c.dat"',
'Content-Type: application/octet-stream',
'',
'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
'-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k--'
].join('\r\n')
],
boundary: '---------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
preservePath: true,
expected: [
{ type: 'file',
name: 'upload_file_0',
data: Buffer.from('ABCDEFGHIJKLMNOPQRSTUVWXYZ'),
info: {
filename: '/absolute/1k_a.dat',
encoding: '7bit',
mimeType: 'application/octet-stream',
},
limited: false,
},
{ type: 'file',
name: 'upload_file_1',
data: Buffer.from('ABCDEFGHIJKLMNOPQRSTUVWXYZ'),
info: {
filename: 'C:\\absolute\\1k_b.dat',
encoding: '7bit',
mimeType: 'application/octet-stream',
},
limited: false,
},
{ type: 'file',
name: 'upload_file_2',
data: Buffer.from('ABCDEFGHIJKLMNOPQRSTUVWXYZ'),
info: {
filename: 'relative/1k_c.dat',
encoding: '7bit',
mimeType: 'application/octet-stream',
},
limited: false,
},
],
what: 'Paths to be preserved through the preservePath option'
},
{ source: [
['------WebKitFormBoundaryTB2MiQ36fnSJlrhY',
'Content-Disposition: form-data; name="cont"',
'Content-Type: ',
'',
'some random content',
'------WebKitFormBoundaryTB2MiQ36fnSJlrhY',
'Content-Disposition: ',
'',
'some random pass',
'------WebKitFormBoundaryTB2MiQ36fnSJlrhY--'
].join('\r\n')
],
boundary: '----WebKitFormBoundaryTB2MiQ36fnSJlrhY',
expected: [
{ type: 'field',
name: 'cont',
val: 'some random content',
info: {
nameTruncated: false,
valueTruncated: false,
encoding: '7bit',
mimeType: 'text/plain',
},
},
],
what: 'Empty content-type and empty content-disposition'
},
{ source: [
['-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
'Content-Disposition: form-data; '
+ 'name="file"; filename*=utf-8\'\'n%C3%A4me.txt',
'Content-Type: application/octet-stream',
'',
'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
'-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k--'
].join('\r\n')
],
boundary: '---------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
expected: [
{ type: 'file',
name: 'file',
data: Buffer.from('ABCDEFGHIJKLMNOPQRSTUVWXYZ'),
info: {
filename: 'näme.txt',
encoding: '7bit',
mimeType: 'application/octet-stream',
},
limited: false,
},
],
what: 'Unicode filenames'
},
{ source: [
['--asdasdasdasd\r\n',
'Content-Type: text/plain\r\n',
'Content-Disposition: form-data; name="foo"\r\n',
'\r\n',
'asd\r\n',
'--asdasdasdasd--'
].join(':)')
],
boundary: 'asdasdasdasd',
expected: [
{ error: 'Malformed part header' },
{ error: 'Unexpected end of form' },
],
what: 'Stopped mid-header'
},
{ source: [
['------WebKitFormBoundaryTB2MiQ36fnSJlrhY',
'Content-Disposition: form-data; name="cont"',
'Content-Type: application/json',
'',
'{}',
'------WebKitFormBoundaryTB2MiQ36fnSJlrhY--',
].join('\r\n')
],
boundary: '----WebKitFormBoundaryTB2MiQ36fnSJlrhY',
expected: [
{ type: 'field',
name: 'cont',
val: '{}',
info: {
nameTruncated: false,
valueTruncated: false,
encoding: '7bit',
mimeType: 'application/json',
},
},
],
what: 'content-type for fields'
},
{ source: [
'------WebKitFormBoundaryTB2MiQ36fnSJlrhY--',
],
boundary: '----WebKitFormBoundaryTB2MiQ36fnSJlrhY',
expected: [],
what: 'empty form'
},
{ source: [
['-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
'Content-Disposition: form-data; '
+ 'name=upload_file_0; filename="1k_a.dat"',
'Content-Type: application/octet-stream',
'Content-Transfer-Encoding: binary',
'',
'',
].join('\r\n')
],
boundary: '---------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
expected: [
{ type: 'file',
name: 'upload_file_0',
data: Buffer.alloc(0),
info: {
filename: '1k_a.dat',
encoding: 'binary',
mimeType: 'application/octet-stream',
},
limited: false,
err: 'Unexpected end of form',
},
{ error: 'Unexpected end of form' },
],
what: 'Stopped mid-file #1'
},
{ source: [
['-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
'Content-Disposition: form-data; '
+ 'name=upload_file_0; filename="1k_a.dat"',
'Content-Type: application/octet-stream',
'',
'a',
].join('\r\n')
],
boundary: '---------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
expected: [
{ type: 'file',
name: 'upload_file_0',
data: Buffer.from('a'),
info: {
filename: '1k_a.dat',
encoding: '7bit',
mimeType: 'application/octet-stream',
},
limited: false,
err: 'Unexpected end of form',
},
{ error: 'Unexpected end of form' },
],
what: 'Stopped mid-file #2'
},
{ source: [
['-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
'Content-Disposition: form-data; '
+ 'name="upload_file_0"; filename="notes.txt"',
'Content-Type: text/plain; charset=utf8',
'',
'a',
'-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k--',
].join('\r\n')
],
boundary: '---------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
expected: [
{ type: 'file',
name: 'upload_file_0',
data: Buffer.from('a'),
info: {
filename: 'notes.txt',
encoding: '7bit',
mimeType: 'text/plain',
},
limited: false,
},
],
what: 'Text file with charset'
},
{ source: [
['-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
'Content-Disposition: form-data; '
+ 'name="upload_file_0"; filename="notes.txt"',
'Content-Type: ',
' text/plain; charset=utf8',
'',
'a',
'-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k--',
].join('\r\n')
],
boundary: '---------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
expected: [
{ type: 'file',
name: 'upload_file_0',
data: Buffer.from('a'),
info: {
filename: 'notes.txt',
encoding: '7bit',
mimeType: 'text/plain',
},
limited: false,
},
],
what: 'Folded header value'
},
{ source: [
['-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
'Content-Type: text/plain; charset=utf8',
'',
'a',
'-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k--',
].join('\r\n')
],
boundary: '---------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
expected: [],
what: 'No Content-Disposition'
},
{ source: [
['-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
'Content-Disposition: form-data; name="file_name_0"',
'',
'a'.repeat(64 * 1024),
'-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
'Content-Disposition: form-data; '
+ 'name="upload_file_0"; filename="notes.txt"',
'Content-Type: ',
' text/plain; charset=utf8',
'',
'bc',
'-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k--',
].join('\r\n')
],
boundary: '---------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
limits: {
fieldSize: Infinity,
},
expected: [
{ type: 'file',
name: 'upload_file_0',
data: Buffer.from('bc'),
info: {
filename: 'notes.txt',
encoding: '7bit',
mimeType: 'text/plain',
},
limited: false,
},
],
events: [ 'file' ],
what: 'Skip field parts if no listener'
},
{ source: [
['-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
'Content-Disposition: form-data; name="file_name_0"',
'',
'a',
'-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
'Content-Disposition: form-data; '
+ 'name="upload_file_0"; filename="notes.txt"',
'Content-Type: ',
' text/plain; charset=utf8',
'',
'bc',
'-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k--',
].join('\r\n')
],
boundary: '---------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
limits: {
parts: 1,
},
expected: [
{ type: 'field',
name: 'file_name_0',
val: 'a',
info: {
nameTruncated: false,
valueTruncated: false,
encoding: '7bit',
mimeType: 'text/plain',
},
},
'partsLimit',
],
what: 'Parts limit'
},
{ source: [
['-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
'Content-Disposition: form-data; name="file_name_0"',
'',
'a',
'-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
'Content-Disposition: form-data; name="file_name_1"',
'',
'b',
'-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k--',
].join('\r\n')
],
boundary: '---------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
limits: {
fields: 1,
},
expected: [
{ type: 'field',
name: 'file_name_0',
val: 'a',
info: {
nameTruncated: false,
valueTruncated: false,
encoding: '7bit',
mimeType: 'text/plain',
},
},
'fieldsLimit',
],
what: 'Fields limit'
},
{ source: [
['-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
'Content-Disposition: form-data; '
+ 'name="upload_file_0"; filename="notes.txt"',
'Content-Type: text/plain; charset=utf8',
'',
'ab',
'-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
'Content-Disposition: form-data; '
+ 'name="upload_file_1"; filename="notes2.txt"',
'Content-Type: text/plain; charset=utf8',
'',
'cd',
'-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k--',
].join('\r\n')
],
boundary: '---------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
limits: {
files: 1,
},
expected: [
{ type: 'file',
name: 'upload_file_0',
data: Buffer.from('ab'),
info: {
filename: 'notes.txt',
encoding: '7bit',
mimeType: 'text/plain',
},
limited: false,
},
'filesLimit',
],
what: 'Files limit'
},
{ source: [
['-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
'Content-Disposition: form-data; '
+ `name="upload_file_0"; filename="${'a'.repeat(64 * 1024)}.txt"`,
'Content-Type: text/plain; charset=utf8',
'',
'ab',
'-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
'Content-Disposition: form-data; '
+ 'name="upload_file_1"; filename="notes2.txt"',
'Content-Type: text/plain; charset=utf8',
'',
'cd',
'-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k--',
].join('\r\n')
],
boundary: '---------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
expected: [
{ error: 'Malformed part header' },
{ type: 'file',
name: 'upload_file_1',
data: Buffer.from('cd'),
info: {
filename: 'notes2.txt',
encoding: '7bit',
mimeType: 'text/plain',
},
limited: false,
},
],
what: 'Oversized part header'
},
{ source: [
['-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
'Content-Disposition: form-data; '
+ 'name="upload_file_0"; filename="notes.txt"',
'Content-Type: text/plain; charset=utf8',
'',
'a'.repeat(31) + '\r',
].join('\r\n'),
'b'.repeat(40),
'\r\n-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k--',
],
boundary: '---------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
fileHwm: 32,
expected: [
{ type: 'file',
name: 'upload_file_0',
data: Buffer.from('a'.repeat(31) + '\r' + 'b'.repeat(40)),
info: {
filename: 'notes.txt',
encoding: '7bit',
mimeType: 'text/plain',
},
limited: false,
},
],
what: 'Lookbehind data should not stall file streams'
},
{ source: [
['-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
'Content-Disposition: form-data; '
+ `name="upload_file_0"; filename="${'a'.repeat(8 * 1024)}.txt"`,
'Content-Type: text/plain; charset=utf8',
'',
'ab',
'-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
'Content-Disposition: form-data; '
+ `name="upload_file_1"; filename="${'b'.repeat(8 * 1024)}.txt"`,
'Content-Type: text/plain; charset=utf8',
'',
'cd',
'-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
'Content-Disposition: form-data; '
+ `name="upload_file_2"; filename="${'c'.repeat(8 * 1024)}.txt"`,
'Content-Type: text/plain; charset=utf8',
'',
'ef',
'-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k--',
].join('\r\n')
],
boundary: '---------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
expected: [
{ type: 'file',
name: 'upload_file_0',
data: Buffer.from('ab'),
info: {
filename: `${'a'.repeat(8 * 1024)}.txt`,
encoding: '7bit',
mimeType: 'text/plain',
},
limited: false,
},
{ type: 'file',
name: 'upload_file_1',
data: Buffer.from('cd'),
info: {
filename: `${'b'.repeat(8 * 1024)}.txt`,
encoding: '7bit',
mimeType: 'text/plain',
},
limited: false,
},
{ type: 'file',
name: 'upload_file_2',
data: Buffer.from('ef'),
info: {
filename: `${'c'.repeat(8 * 1024)}.txt`,
encoding: '7bit',
mimeType: 'text/plain',
},
limited: false,
},
],
what: 'Header size limit should be per part'
},
{ source: [
'\r\n--d1bf46b3-aa33-4061-b28d-6c5ced8b08ee\r\n',
'Content-Type: application/gzip\r\n'
+ 'Content-Encoding: gzip\r\n'
+ 'Content-Disposition: form-data; name=batch-1; filename=batch-1'
+ '\r\n\r\n',
'\r\n--d1bf46b3-aa33-4061-b28d-6c5ced8b08ee--',
],
boundary: 'd1bf46b3-aa33-4061-b28d-6c5ced8b08ee',
expected: [
{ type: 'file',
name: 'batch-1',
data: Buffer.alloc(0),
info: {
filename: 'batch-1',
encoding: '7bit',
mimeType: 'application/gzip',
},
limited: false,
},
],
what: 'Empty part'
},
];
for (const test of tests) {
active.set(test, 1);
const { what, boundary, events, limits, preservePath, fileHwm } = test;
const bb = busboy({
fileHwm,
limits,
preservePath,
headers: {
'content-type': `multipart/form-data; boundary=${boundary}`,
}
});
const results = [];
if (events === undefined || events.includes('field')) {
bb.on('field', (name, val, info) => {
results.push({ type: 'field', name, val, info });
});
}
if (events === undefined || events.includes('file')) {
bb.on('file', (name, stream, info) => {
const data = [];
let nb = 0;
const file = {
type: 'file',
name,
data: null,
info,
limited: false,
};
results.push(file);
stream.on('data', (d) => {
data.push(d);
nb += d.length;
}).on('limit', () => {
file.limited = true;
}).on('close', () => {
file.data = Buffer.concat(data, nb);
assert.strictEqual(stream.truncated, file.limited);
}).once('error', (err) => {
file.err = err.message;
});
});
}
bb.on('error', (err) => {
results.push({ error: err.message });
});
bb.on('partsLimit', () => {
results.push('partsLimit');
});
bb.on('filesLimit', () => {
results.push('filesLimit');
});
bb.on('fieldsLimit', () => {
results.push('fieldsLimit');
});
bb.on('close', () => {
active.delete(test);
assert.deepStrictEqual(
results,
test.expected,
`[${what}] Results mismatch.\n`
+ `Parsed: ${inspect(results)}\n`
+ `Expected: ${inspect(test.expected)}`
);
});
for (const src of test.source) {
const buf = (typeof src === 'string' ? Buffer.from(src, 'utf8') : src);
bb.write(buf);
}
bb.end();
}
// Byte-by-byte versions
for (let test of tests) {
test = { ...test };
test.what += ' (byte-by-byte)';
active.set(test, 1);
const { what, boundary, events, limits, preservePath, fileHwm } = test;
const bb = busboy({
fileHwm,
limits,
preservePath,
headers: {
'content-type': `multipart/form-data; boundary=${boundary}`,
}
});
const results = [];
if (events === undefined || events.includes('field')) {
bb.on('field', (name, val, info) => {
results.push({ type: 'field', name, val, info });
});
}
if (events === undefined || events.includes('file')) {
bb.on('file', (name, stream, info) => {
const data = [];
let nb = 0;
const file = {
type: 'file',
name,
data: null,
info,
limited: false,
};
results.push(file);
stream.on('data', (d) => {
data.push(d);
nb += d.length;
}).on('limit', () => {
file.limited = true;
}).on('close', () => {
file.data = Buffer.concat(data, nb);
assert.strictEqual(stream.truncated, file.limited);
}).once('error', (err) => {
file.err = err.message;
});
});
}
bb.on('error', (err) => {
results.push({ error: err.message });
});
bb.on('partsLimit', () => {
results.push('partsLimit');
});
bb.on('filesLimit', () => {
results.push('filesLimit');
});
bb.on('fieldsLimit', () => {
results.push('fieldsLimit');
});
bb.on('close', () => {
active.delete(test);
assert.deepStrictEqual(
results,
test.expected,
`[${what}] Results mismatch.\n`
+ `Parsed: ${inspect(results)}\n`
+ `Expected: ${inspect(test.expected)}`
);
});
for (const src of test.source) {
const buf = (typeof src === 'string' ? Buffer.from(src, 'utf8') : src);
for (let i = 0; i < buf.length; ++i)
bb.write(buf.slice(i, i + 1));
}
bb.end();
}
{
let exception = false;
process.once('uncaughtException', (ex) => {
exception = true;
throw ex;
});
process.on('exit', () => {
if (exception || active.size === 0)
return;
process.exitCode = 1;
console.error('==========================');
console.error(`${active.size} test(s) did not finish:`);
console.error('==========================');
console.error(Array.from(active.keys()).map((v) => v.what).join('\n'));
});
}