Busboy : HTML form data parser
A module for parsing incoming HTML form data. It support Readable
stream for file.
User can use the following code to import the Busboy
module.
var Busboy = require('middleware').Busboy;
Support
The following shows Busboy
module APIs available for each permissions.
User Mode | Privilege Mode | |
---|---|---|
Busboy | ● | ● |
Busboy Class
Busboy
is Writable
stream.
Busboy(config)
config
{Object} Creates and returns a new Busboy instance. The constructor takes the following validconfig
settings:headers
{Object} These are the HTTP headers of the incoming request, which are used by individual parsers.highWaterMark
{Integer}highWaterMark
to use for thisBusboy
instance, default:WritableStream
.fileHwm
{Integer}highWaterMark
to use for file streams, default:ReadableStream
.defCharset
{String} Default character set to use when one isn't defined, default: 'utf8'.preservePath
{Boolean} If paths in the multipart 'filename' field shall be preserved. default: false.limits
{Object} Various limits on incoming data. Valid properties are:fieldNameSize
{Integer} Max field name size (in bytes) default: 100 bytes.fieldSize
{Integer} Max field value size (in bytes) default: 1MB.fields
{Integer} Max number of non-file fields default: Infinity.fileSize
{Integer} For multipart forms, the max file size (in bytes) default: Infinity.files
{Integer} For multipart forms, the max number of file fields default: Infinity.parts
{Integer} For multipart forms, the max number of parts (fields + files) default: Infinity.headerPairs
{Integer} For multipart forms, the max number of header key=>value pairs to parse default: 2000.
The constructor can throw errors:
Unsupported content type: $type
- TheContent-Type
isn't oneBusboy
can parse.Missing Content-Type
- The provided headers don't includeContent-Type
at all.
Events
file
Emitted for each new file form field found. Arguments:
fieldname
{String} Field name.stream
{ReadableStream} Rdadable stream of file data.filename
{String} original File name.transferEncoding
{String} Contains the 'Content-Transfer-Encoding' value for the file stream.mimeType
{String} Contains the 'Content-Type' value for the file stream.
If you listen for this event, you should always handle the stream
no matter if you care about the file contents or not (e.g. you can simply just do stream.resume();
if you want to discard the contents), otherwise the finish
event will never fire on the Busboy
instance. However, if you don't care about any incoming files, you can simply not listen for the file
event at all and any/all files will be automatically and safely discarded (these discarded files do still count towards files
and parts
limits).
If a configured file size limit was reached, stream
will both have a boolean property truncated
(best checked at the end of the stream) and emit a limit
event to notify you when this happens.
field
Emitted for each new non-file field found. Arguments:
fieldname
{String} Field name.fieldvalue
{String} Field value.fieldnameTruncated
{Boolean} If field name truncated.valueTruncated
{Boolean} If value truncated.transferEncoding
{String} Contains the 'Content-Transfer-Encoding' value for the field value.mimeType
{String} Contains the 'Content-Type' value for the field value.
partsLimit
Emitted when specified parts
limit has been reached. No more file
or field
events will be emitted.
filesLimit
Emitted when specified files
limit has been reached. No more file
events will be emitted.
fieldsLimit
Emitted when specified fields
limit has been reached. No more field
events will be emitted.
Example
- Parsing (multipart) with default options.
var socket = require('socket');
var WebApp = require('webapp');
var iosched = require('iosched');
var Busboy = require('middleware').Busboy;
// Create app.
var app = WebApp.create('app', 0, socket.sockaddr(socket.INADDR_ANY, 8000));
// Index.
app.get('/', (req, res) => {
var ctx =
`<html><head></head><body>\
<form action="/test1" method="POST" enctype="multipart/form-data">\
<input type="text" name="textfield"><br />\
<input type="file" name="filefield"><br />\
<input type="submit">\
</form>\
</body></html>`;
res.send(ctx);
});
// Handle form data.
app.post('/test1', (req, res, next) => {
var busboy = new Busboy({ headers: req.headers });
busboy.on('file', function (fieldname, file, filename, encoding, mimetype) {
console.log('File [' + fieldname + ']: filename: ' + filename + ', encoding: ' + encoding + ', mimetype: ' + mimetype);
file.on('data', function (data) {
console.log('File [' + fieldname + '] got ' + data.length + ' bytes');
});
file.on('end', function () {
console.log('File [' + fieldname + '] Finished');
});
});
busboy.on('field', function (fieldname, val, fieldnameTruncated, valTruncated, encoding, mimetype) {
console.log('Field [' + fieldname + ']: value: ' + val);
});
busboy.on('finish', function () {
console.log('Done parsing form!');
res.writeHead(303, { Connection: 'close', Location: '/' });
res.end();
});
req.pipe(busboy);
});
// Error handler.
app.use(function(err, req, res, next) {
if (res.headersSent) {
return next(err);
}
var status = err.status ? err.status : res.status();
status = status < 400 ? 500 : status;
res.status(status).json({status: status, msg: err.message});
});
// Start app.
app.start();
// Event loop.
iosched.forever();
- Save all incoming files to disk.
var fs = require('fs');
var path = require('path');
var socket = require('socket');
var WebApp = require('webapp');
var iosched = require('iosched');
var Busboy = require('middleware').Busboy;
// Create app.
var app = WebApp.create('app', 0, socket.sockaddr(socket.INADDR_ANY, 8000));
// Index.
app.get('/', (req, res) => {
var ctx =
`<html><head></head><body>\
<form action="/test2" method="POST" enctype="multipart/form-data">\
<input type="file" name="filefield"><br />\
<input type="submit">\
</form>\
</body></html>`;
res.send(ctx);
});
// Handle file.
app.post('/test2', function(req, res, next) {
var busboy = new Busboy({ headers: req.headers });
var error = undefined;
busboy.on('file', function(fieldname, file, filename, encoding, mimetype) {
var saveTo = path.join('./' + filename);
var outStream = fs.createWriteStream(saveTo);
file.pipe(outStream);
file.on('error', (err) => {
outStream.destroy();
error = err;
});
});
busboy.on('finish', function() {
if (error) {
next(error);
} else {
res.writeHead(200, { 'Connection': 'close' });
res.end("That's all folks!");
}
});
req.pipe(busboy);
});
// Error handler.
app.use(function(err, req, res, next) {
if (res.headersSent) {
return next(err);
}
var status = err.status ? err.status : res.status();
status = status < 400 ? 500 : status;
res.status(status).json({status: status, msg: err.message});
});
// Start app.
app.start();
// Event loop.
iosched.forever();