Skip to content

Commit 248f83c

Browse files
committed
Added qhelp for UnhandledStreamPipe query
1 parent c6db32e commit 248f83c

File tree

4 files changed

+83
-0
lines changed

4 files changed

+83
-0
lines changed
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<!DOCTYPE qhelp PUBLIC
2+
"-//Semmle//qhelp//EN"
3+
"qhelp.dtd">
4+
<qhelp>
5+
6+
<overview>
7+
<p>
8+
In Node.js, calling the <code>pipe()</code> method on a stream without proper error handling can lead to silent failures, where errors are dropped and not propagated downstream. This can result in unexpected behavior and make debugging difficult. It is crucial to ensure that error handling is implemented when using stream pipes to maintain the reliability of the application.
9+
</p>
10+
</overview>
11+
12+
<recommendation>
13+
<p>
14+
Instead of using <code>pipe()</code> with manual error handling, prefer using the <code>pipeline</code> function from the Node.js stream module. The <code>pipeline</code> function automatically handles errors and ensures proper cleanup of resources. This approach is more robust and eliminates the risk of forgetting to handle errors.
15+
</p>
16+
<p>
17+
If you must use <code>pipe()</code>, always attach an error handler to the source stream using methods like <code>on('error', handler)</code> to ensure that any errors during the streaming process are properly handled.
18+
</p>
19+
</recommendation>
20+
21+
<example>
22+
<p>
23+
The following code snippet demonstrates a problematic usage of the <code>pipe()</code> method without error handling:
24+
</p>
25+
26+
<sample src="examples/UnhandledStreamPipe.js" />
27+
28+
<p>
29+
A better approach is to use the <code>pipeline</code> function, which automatically handles errors:
30+
</p>
31+
32+
<sample src="examples/UnhandledStreamPipeGood.js" />
33+
34+
<p>
35+
Alternatively, if you need to use <code>pipe()</code>, make sure to add error handling:
36+
</p>
37+
38+
<sample src="examples/UnhandledStreamPipeManualError.js" />
39+
</example>
40+
41+
<references>
42+
<li>Node.js Documentation: <a href="https://nodejs.org/api/stream.html#streampipelinestreams-callback">stream.pipeline()</a>.</li>
43+
</references>
44+
</qhelp>
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
const fs = require('fs');
2+
const source = fs.createReadStream('source.txt');
3+
const destination = fs.createWriteStream('destination.txt');
4+
5+
// Bad: No error handling
6+
source.pipe(destination);
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
const { pipeline } = require('stream');
2+
const fs = require('fs');
3+
const source = fs.createReadStream('source.txt');
4+
const destination = fs.createWriteStream('destination.txt');
5+
6+
// Good: Using pipeline for automatic error handling
7+
pipeline(
8+
source,
9+
destination,
10+
(err) => {
11+
if (err) {
12+
console.error('Pipeline failed:', err);
13+
} else {
14+
console.log('Pipeline succeeded');
15+
}
16+
}
17+
);
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
const fs = require('fs');
2+
const source = fs.createReadStream('source.txt');
3+
const destination = fs.createWriteStream('destination.txt');
4+
5+
// Alternative Good: Manual error handling with pipe()
6+
source.on('error', (err) => {
7+
console.error('Source stream error:', err);
8+
destination.destroy(err);
9+
});
10+
11+
destination.on('error', (err) => {
12+
console.error('Destination stream error:', err);
13+
source.destroy(err);
14+
});
15+
16+
source.pipe(destination);

0 commit comments

Comments
 (0)