busboy

repository·master·Indexed 23 days ago

https://github.com/mscdex/busboy

A high-performance streaming parser for HTML form data in Node.js, specifically supporting multipart/form-data and application/x-www-form-urlencoded. Version 1.6.0 provides a Writable form parser stream that emits events for files and fields, with configurable limits for field size, file size, and the number of parts.

Tokens
2.6K
Snippets
5
Records
9
Agent score
34%

What's inside busboy

  1. Example: Parse multipart form data with default options

    master

    This example demonstrates how to set up a basic HTTP server that uses busboy to listen for POST requests containing multipart form data, logging both files and text fields.

    const http = require('http');
    const busboy = require('busboy');
    
    http.createServer((req, res) => {
      if (req.method === 'POST') {
        console.log('POST request');
        const bb = busboy({ headers: req.headers });
        bb.on('file', (name, file, info) => {
          const { filename, encoding, mimeType } = info;
          console.log(
            `File [${name}]: filename: %j, encoding: %j, mimeType: %j`,
            filename,
            encoding,
            mimeType
          );
          file.on('data', (data) => {
            console.log(`File [${name}] got ${data.length} bytes`);
          }).on('close', () => {
            console.log(`File [${name}] done`);
          });
        });
        bb.on('field', (name, val, info) => {
          console.log(`Field [${name}]: value: %j`, val);
        });
        bb.on('close', () => {
          console.log('Done parsing form!');
          res.writeHead(303, { Connection: 'close', Location: '/' });
          res.end();
        });
        req.pipe(bb);
      } else if (req.method === 'GET') {
        res.writeHead(200, { Connection: 'close' });
        res.end(`
          <html
            <head></head>
            <body
              <form method="POST" enctype="multipart/form-data">
                <input type="file" name="filefield"><br />
                <input type="text" name="textfield"><br />
                <input type="submit">
              </form>
            </body>
          </html>
        `);
      }
    }).listen(8000, () => {
      console.log('Listening for requests');
    });
  2. Example: Save all incoming files to disk

    master

    This example demonstrates how to pipe incoming file streams directly to a write stream on the local filesystem using fs.createWriteStream.

    const { randomFillSync } = require('crypto');
    const fs = require('fs');
    const http = require('http');
    const os = require('os');
    const path = require('path');
    
    const busboy = require('busboy');
    
    const random = (() => {
      const buf = Buffer.alloc(16);
      return () => randomFillSync(buf).toString('hex');
    })();
    
    http.createServer((req, res) => {
      if (req.method === 'POST') {
        const bb = busboy({ headers: req.headers });
        bb.on('file', (name, file, info) => {
          const saveTo = path.join(os.tmpdir(), `busboy-upload-${random()}`);
          file.pipe(fs.createWriteStream(saveTo));
        });
        bb.on('close', () => {
          res.writeHead(200, { 'Connection': 'close' });
          res.end(`That's all folks!`);
        });
        req.pipe(bb);
        return;
      }
      res.writeHead(404);
      res.end();
    }).listen(8000, () => {
      console.log('Listening for requests');
    });
  3. Initialize the busboy parser stream

    master

    The busboy function creates and returns a new Writable form parser stream. It requires a configuration object. Note that if the headers in the config are missing a supported Content-Type or a boundary for multipart/form-data, the function will throw an exception.

    Configuration Options:

    PropertyTypeDescription
    headersobjectThe HTTP headers of the incoming request.
    highWaterMarkintegerHigh water mark for the parser stream. (Default: node's stream.Writable default)
    fileHwmintegerHigh water mark for individual file streams. (Default: node's stream.Readable default)
    defCharsetstringDefault character set if none is defined. (Default: 'utf8')
    defParamCharsetstringDefault character set for multipart form part header parameters. (Default: 'latin1')
    preservePathbooleanWhether to preserve paths in filenames from file parts. (Default: false)
    limitsobjectObject containing data limits (see Limits)

    Limits Configuration (limits object):

    PropertyTypeDescription
    fieldNameSizeintegerMax field name size in bytes. (Default: 100)
    fieldSizeintegerMax field value size in bytes. (Default: 1048576 / 1MB)
    fieldsintegerMax number of non-file fields. (Default: Infinity)
    fileSizeintegerMax file size in bytes for multipart forms. (Default: Infinity)
    filesintegerMax number of file fields. (Default: Infinity)
    partsintegerMax number of parts (fields + files). (Default: Infinity)
    headerPairsintegerMax number of header key-value pairs to parse. (Default: 2000)
    const busboy = require('busboy');
    const bb = busboy({ headers: req.headers });
  4. Handle parser limit events

    master

    Busboy emits specific events when configured limits are reached. Once these limits are hit, no further 'file' or 'field' events will be emitted.

    • partsLimit(): Emitted when limits.parts is reached.
    • filesLimit(): Emitted when limits.files is reached. No more 'file' events will be emitted.
    • fieldsLimit(): Emitted when limits.fields is reached. No more 'field' events will be emitted.
  5. Initialize the Busboy parser

    master

    The main export of busboy is a function that initializes a parser instance based on the provided Content-Type header. You must provide a configuration object containing a headers object with a valid content-type string.

    Supported content types are automatically detected (e.g., multipart/form-data or application/x-www-form-urlencoded).

    Available configuration options in the cfg object:

    • headers: (Required) An object containing request headers. Must include content-type.
    • limits: Configuration for parsing limits.
    • highWaterMark: Internal buffer size for the parser.
    • fileHwm: Internal buffer size for files.
    • defCharset: Default character set.
    • defParamCharset: Default character set for parameters.
    • preservePath: Boolean to determine if file paths should be preserved.
  6. Error handling when initializing Busboy

    master

    The Busboy initialization function throws errors in the following scenarios:

    1. Missing Content-Type: If cfg.headers is not an object, is null, or if cfg.headers['content-type'] is not a string.
      • Error: Missing Content-Type
    2. Malformed Content Type: If the content-type header cannot be parsed.
      • Error: Malformed content type
    3. Unsupported Content Type: If the content-type does not match any supported types (like multipart or urlencoded).
      • Error: Unsupported content type: <header-value>
  7. Handle field upload events

    master

    The field event is emitted for each new non-file field found in the form.

    Arguments:

    • name (string): The form field name.
    • value (string): The string value of the field.
    • info (object): Contains metadata:
      • nameTruncated (boolean): Whether name was truncated due to limits.fieldNameSize.
      • valueTruncated (boolean): Whether value was truncated due to limits.fieldSize.
      • encoding (string): The 'Content-Transfer-Encoding' value.
      • mimeType (string): The 'Content-Type' value.
    bb.on('field', (name, val, info) => {
      console.log(`Field [${name}]: value: %j`, val);
    });
  8. Handle file upload events

    master

    The file event is emitted for each new file found in the form.

    Arguments:

    • name (string): The form field name.
    • stream (Readable): A stream containing the file's raw data (no transformations like base64 are applied).
    • info (object): Contains metadata:
      • filename (string): The file's filename. WARNING: Do not use this value directly for file paths as it may contain malicious input. Generate your own safe filenames.
      • encoding (string): The 'Content-Transfer-Encoding' value.
      • mimeType (string): The 'Content-Type' value.

    Important Notes:

    • Always consume the stream: You must consume the stream (e.g., via .pipe() or stream.resume()) regardless of whether you need the data. If you do not, the 'finish'/'close' events on the parser stream will never fire.
    • File Size Limits: If limits.fileSize is exceeded, the stream will have a truncated: true property and the parser will emit a 'limit' event.