Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 8c256d4

Browse filesBrowse files
theanarkhaduh95
authored andcommitted
http: fix http client leaky with double response
PR-URL: #60062 Fixes: #60025 Reviewed-By: Tim Perry <pimterry@gmail.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
1 parent 5aea1a4 commit 8c256d4
Copy full SHA for 8c256d4

File tree

Expand file treeCollapse file tree

3 files changed

+57
-3
lines changed
Open diff view settings
Filter options
Expand file treeCollapse file tree

3 files changed

+57
-3
lines changed
Open diff view settings
Collapse file

‎lib/_http_client.js‎

Copy file name to clipboardExpand all lines: lib/_http_client.js
+9-1Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ const {
4747
HTTPParser,
4848
isLenient,
4949
prepareError,
50+
kSkipPendingData,
5051
} = require('_http_common');
5152
const {
5253
kUniqueHeaders,
@@ -692,7 +693,14 @@ function parserOnIncomingClient(res, shouldKeepAlive) {
692693
// We already have a response object, this means the server
693694
// sent a double response.
694695
socket.destroy();
695-
return 0; // No special treatment.
696+
if (socket.parser) {
697+
// https://github.com/nodejs/node/issues/60025
698+
// Now, parser.incoming is pointed to the new IncomingMessage,
699+
// we need to rewrite it to the first one and skip all the pending IncomingMessage
700+
socket.parser.incoming = req.res;
701+
socket.parser.incoming[kSkipPendingData] = true;
702+
}
703+
return 0;
696704
}
697705
req.res = res;
698706

Collapse file

‎lib/_http_common.js‎

Copy file name to clipboardExpand all lines: lib/_http_common.js
+4-2Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ const {
4141
} = incoming;
4242

4343
const kIncomingMessage = Symbol('IncomingMessage');
44+
const kSkipPendingData = Symbol('SkipPendingData');
4445
const kOnMessageBegin = HTTPParser.kOnMessageBegin | 0;
4546
const kOnHeaders = HTTPParser.kOnHeaders | 0;
4647
const kOnHeadersComplete = HTTPParser.kOnHeadersComplete | 0;
@@ -126,7 +127,7 @@ function parserOnBody(b) {
126127
const stream = this.incoming;
127128

128129
// If the stream has already been removed, then drop it.
129-
if (stream === null)
130+
if (stream === null || stream[kSkipPendingData])
130131
return;
131132

132133
// Pretend this was the result of a stream._read call.
@@ -141,7 +142,7 @@ function parserOnMessageComplete() {
141142
const parser = this;
142143
const stream = parser.incoming;
143144

144-
if (stream !== null) {
145+
if (stream !== null && !stream[kSkipPendingData]) {
145146
stream.complete = true;
146147
// Emit any trailing headers.
147148
const headers = parser._headers;
@@ -310,4 +311,5 @@ module.exports = {
310311
HTTPParser,
311312
isLenient,
312313
prepareError,
314+
kSkipPendingData,
313315
};
Collapse file
+44Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
'use strict';
2+
// Flags: --expose-gc
3+
const common = require('../common');
4+
const http = require('http');
5+
const assert = require('assert');
6+
const { onGC } = require('../common/gc');
7+
8+
function createServer() {
9+
const server = http.createServer(common.mustCall((req, res) => {
10+
res.setHeader('Content-Type', 'application/json');
11+
res.end(JSON.stringify({ hello: 'world' }));
12+
req.socket.write('HTTP/1.1 400 Bad Request\r\n\r\n');
13+
}));
14+
15+
return new Promise((resolve) => {
16+
server.listen(0, common.mustCall(() => {
17+
resolve(server);
18+
}));
19+
});
20+
}
21+
22+
async function main() {
23+
const server = await createServer();
24+
const req = http.get({
25+
port: server.address().port,
26+
}, common.mustCall((res) => {
27+
const chunks = [];
28+
res.on('data', common.mustCallAtLeast((c) => chunks.push(c), 1));
29+
res.on('end', common.mustCall(() => {
30+
const body = Buffer.concat(chunks).toString('utf8');
31+
const data = JSON.parse(body);
32+
assert.strictEqual(data.hello, 'world');
33+
}));
34+
}));
35+
const timer = setInterval(global.gc, 300);
36+
onGC(req, {
37+
ongc: common.mustCall(() => {
38+
clearInterval(timer);
39+
server.close();
40+
})
41+
});
42+
}
43+
44+
main();

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.