Best Practices for Handling Unrar in Node.js
Extracting RAR archives in Node.js typically involves interacting
with external CLI utilities or WebAssembly-based wrappers, both of which
require robust output management. This guide covers the essential
practices for handling unrar output effectively, focusing
on stream management, accurate error detection, progress tracking, and
security measures to ensure stable archive extraction in production
environments.
Prefer
spawn Over exec for CLI Execution
When running the system unrar binary via the
child_process module, always use spawn rather
than exec. The exec method buffers all
standard output (stdout) and standard error
(stderr) into memory up to a default limit (typically 1
MB). If an archive contains thousands of files, unrar will
exceed this buffer, causing the process to crash with an
ERR_CHILD_PROCESS_STDIO_MAXBUFFER error.
Using spawn streams the output chunk-by-chunk:
const { spawn } = require('child_process');
const unrar = spawn('unrar', ['x', '-y', 'archive.rar', 'destination/']);
unrar.stdout.on('data', (chunk) => {
// Handle streaming output incrementally
});Parse Streams Line-by-Line
stdout chunks emitted by a Node.js stream do not always
correspond to single lines of text; a chunk might cut off mid-word or
contain multiple lines. To reliably parse output for file names,
percentage updates, or status messages, pipe the stream through the
built-in readline module:
const readline = require('readline');
const rl = readline.createInterface({
input: unrar.stdout,
terminal: false
});
rl.on('line', (line) => {
if (line.startsWith('Extracting ')) {
const filename = line.replace('Extracting ', '').trim();
// Track extracted file
}
});Rely on Exit
Codes Instead of stderr for Errors
CLI tools often write diagnostic information, notices, or warnings to
stderr even when an operation succeeds. Do not assume an
extraction failed simply because stderr received data.
Instead, monitor the process close or exit
event to evaluate the numeric exit code.
Common unrar exit codes include:
- 0: Successful operation.
- 1: Non-fatal error (such as minor warnings).
- 2: Fatal error (corrupt archive, read error).
- 3: CRC error (checksum verification failed).
- 4: Attempted to modify a locked archive.
- 5: Write error (disk full or permission denied).
- 6: File open error.
- 7: Wrong command-line syntax.
- 8: Memory error.
Capture stderr in a variable during runtime, but only
log or throw it if the process exits with a non-zero status code:
let errorOutput = '';
unrar.stderr.on('data', (data) => {
errorOutput += data.toString();
});
unrar.on('close', (code) => {
if (code !== 0) {
throw new Error(`Unrar failed with code ${code}: ${errorOutput}`);
}
});Defend Against Path Traversal (Zip Slip)
Maliciously crafted RAR files may contain filenames with relative
directory paths (such as ../../etc/passwd) designed to
write files outside the intended destination directory. If you are
handling output or manually extracting entries using libraries like
node-unrar-js:
- Resolve the absolute path of the target extraction folder.
- Resolve the absolute path of each incoming file path.
- Verify that the file's target path begins strictly with the extraction directory's base path before allowing the write operation.
Consider In-Memory WebAssembly Alternatives
If installing the native unrar CLI binary on your
deployment environment is impractical or restricted, use
WebAssembly-compiled alternatives such as node-unrar-js.
When using WebAssembly libraries, output is handled via JavaScript
promises and typed arrays rather than standard OS streams:
- Extract metadata first using non-extracting methods to inspect archive contents before unpacking.
- Process file entries sequentially to avoid consuming excessive heap memory when dealing with large archives.
- Explicitly release memory buffers once an entry has been written to disk to allow the Node.js garbage collector to reclaim heap space.