Content length calculation for streams and form data, providing both synchronous and asynchronous methods for determining total form size before transmission.
Calculates the total content length asynchronously, handling streams and unknown-length content.
/**
* Get content length asynchronously
* @param callback - Callback function receiving error and length
*/
getLength(callback: (err: Error | null, length: number) => void): void;Usage Examples:
const FormData = require('form-data');
const fs = require('fs');
const form = new FormData();
form.append('text', 'Hello World');
form.append('file', fs.createReadStream('document.pdf'));
// Calculate length before submission
form.getLength((err, length) => {
if (err) {
console.error('Cannot calculate length:', err.message);
return;
}
console.log('Total form size:', length, 'bytes');
// Use length for Content-Length header
const http = require('http');
const request = http.request({
method: 'POST',
host: 'example.com',
path: '/upload',
headers: {
...form.getHeaders(),
'Content-Length': length
}
});
form.pipe(request);
});Calculates content length synchronously for known-length content only.
/**
* Get content length synchronously (doesn't calculate streams)
* @returns Content length in bytes
* @throws Error if streams are present without knownLength
*/
getLengthSync(): number;Usage Examples:
const FormData = require('form-data');
// Form with only known-length content
const form = new FormData();
form.append('name', 'Alice');
form.append('age', '25');
form.append('buffer', Buffer.from('data'));
try {
const length = form.getLengthSync();
console.log('Form size:', length, 'bytes');
} catch (err) {
console.error('Cannot calculate sync:', err.message);
}
// Form with streams - use knownLength option
const form2 = new FormData();
form2.append('text', 'content');
form2.append('file', fs.createReadStream('file.txt'), {
knownLength: 1024 // Pre-known file size
});
const length = form2.getLengthSync(); // Works because stream has knownLengthChecks if all added values have known lengths for synchronous calculation.
/**
* Check if all added values have known lengths
* @returns True if synchronous length calculation is possible
*/
hasKnownLength(): boolean;Usage Examples:
const FormData = require('form-data');
const fs = require('fs');
const form = new FormData();
form.append('text', 'value');
console.log(form.hasKnownLength()); // true - strings have known length
// Add stream without knownLength
form.append('file', fs.createReadStream('file.txt'));
console.log(form.hasKnownLength()); // false - stream length unknown
// Add stream with knownLength
form.append('file2', fs.createReadStream('file2.txt'), {
knownLength: 2048
});
console.log(form.hasKnownLength()); // still false - first stream is unknown
// Use this to choose calculation method
if (form.hasKnownLength()) {
const length = form.getLengthSync();
console.log('Sync length:', length);
} else {
form.getLength((err, length) => {
if (err) return console.error(err);
console.log('Async length:', length);
});
}Form-Data calculates length by summing:
const FormData = require('form-data');
const form = new FormData();
form.append('field', 'value');
// Internal length tracking (not part of public API)
// form._overheadLength - headers and boundaries
// form._valueLength - content size
// form._lastBoundary().length - final boundary
form.getLength((err, totalLength) => {
console.log('Total includes:');
console.log('- Multipart headers and boundaries');
console.log('- Field content');
console.log('- Final boundary marker');
console.log('Total:', totalLength, 'bytes');
});Form-Data automatically detects length from various stream types:
const FormData = require('form-data');
const fs = require('fs');
const http = require('http');
const form = new FormData();
// File streams - reads fs.stat
form.append('file', fs.createReadStream('document.pdf'));
// HTTP response streams - uses Content-Length header
http.get('http://example.com/image.jpg', (response) => {
form.append('remote_file', response);
});
// Request streams - waits for response headers
const request = require('request');
form.append('api_data', request('http://api.example.com/data'));
// Custom streams - use knownLength option
const { Readable } = require('stream');
const customStream = new Readable({
read() {
this.push('data chunk');
this.push(null); // end
}
});
form.append('custom', customStream, {
knownLength: 10 // Specify length manually
});
form.getLength((err, length) => {
if (err) {
console.error('Length calculation failed:', err);
} else {
console.log('All streams measured:', length);
}
});Length calculation can fail in several scenarios:
const FormData = require('form-data');
const form = new FormData();
// Sync error - streams present
form.append('file', fs.createReadStream('file.txt'));
try {
form.getLengthSync();
} catch (err) {
console.error('Sync failed:', err.message);
// "Cannot calculate proper length in synchronous way."
}
// Async error - unknown stream type
const { Readable } = require('stream');
const unknownStream = new Readable({ read() {} });
form.append('unknown', unknownStream);
form.getLength((err, length) => {
if (err) {
console.error('Async failed:', err);
// "Unknown stream"
}
});// For best performance with large files:
// 1. Use knownLength when possible
form.append('largefile', stream, {
knownLength: fileSize // Avoid fs.stat() call
});
// 2. Check hasKnownLength() before choosing method
if (form.hasKnownLength()) {
const length = form.getLengthSync(); // Faster
} else {
form.getLength(callback); // Necessary for streams
}
// 3. For HTTP uploads, let submit() handle length automatically
form.submit(url, callback); // Calculates length internally