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