Skip to content

Commit 5ceab00

Browse files
committed
http: do not emit socket errors after complete response
Signed-off-by: Archkon <180910180+Archkon@users.noreply.github.com>
1 parent cc05d1c commit 5ceab00

2 files changed

Lines changed: 68 additions & 1 deletion

File tree

lib/_http_client.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -744,7 +744,12 @@ function socketErrorListener(err) {
744744
// For Safety. Some additional errors might fire later on
745745
// and we need to make sure we don't double-fire the error event.
746746
socket._hadError = true;
747-
emitErrorEvent(req, err);
747+
// If a response has already been received, the request succeeded at the
748+
// HTTP layer. Treat later socket errors as response/connection teardown,
749+
// not as errors for this ClientRequest.
750+
if (!req.res) {
751+
emitErrorEvent(req, err);
752+
}
748753
}
749754

750755
const parser = socket.parser;
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
'use strict';
2+
3+
const common = require('../common');
4+
const assert = require('assert');
5+
const http = require('http');
6+
7+
const MAX_BODY_LENGTH = 1024 * 1024;
8+
9+
const server = http.createServer(common.mustCall((request, response) => {
10+
let body = '';
11+
12+
request.setEncoding('utf8');
13+
request.on('data', function onData(chunk) {
14+
body += chunk;
15+
if (body.length > MAX_BODY_LENGTH) {
16+
response.writeHead(413, { 'content-length': 0 });
17+
response.end();
18+
request.off('data', onData);
19+
request.destroy();
20+
}
21+
});
22+
23+
request.on('end', common.mustNotCall());
24+
request.on('close', common.mustCall(() => {
25+
assert.strictEqual(request.complete, false);
26+
assert.ok(body.length > MAX_BODY_LENGTH);
27+
}));
28+
}));
29+
30+
server.listen(0, common.mustCall(() => {
31+
const body = JSON.stringify({
32+
a: 'x'.repeat(512 * 1024),
33+
b: 'x'.repeat(512 * 1024),
34+
c: 'x'.repeat(512 * 1024),
35+
d: 'x'.repeat(512 * 1024),
36+
}, null, '\t');
37+
38+
let response;
39+
const req = http.request({
40+
method: 'POST',
41+
port: server.address().port,
42+
headers: {
43+
'content-type': 'application/json',
44+
},
45+
}, common.mustCall((res) => {
46+
response = res;
47+
assert.strictEqual(res.statusCode, 413);
48+
// Deliberately do not consume the response body. A response that has
49+
// already been received should not be followed by a late ClientRequest
50+
// socket error.
51+
}));
52+
53+
req.on('error', common.mustNotCall());
54+
req.on('close', common.mustCall(() => {
55+
assert(response);
56+
assert.strictEqual(response.complete, true);
57+
server.close();
58+
}));
59+
60+
req.write(body);
61+
req.end();
62+
}));

0 commit comments

Comments
 (0)