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 c03cddb

Browse filesBrowse files
mitsos1osBethGriggs
authored andcommitted
test: http complete response after socket double end
PR-URL: #36633 Backport-PR-URL: #36940 Fixes: #36620 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com> Reviewed-By: Danielle Adams <adamzdanielle@gmail.com>
1 parent 2a1e4e9 commit c03cddb
Copy full SHA for c03cddb

File tree

Expand file treeCollapse file tree

2 files changed

+98
-0
lines changed
Open diff view settings
Filter options
Expand file treeCollapse file tree

2 files changed

+98
-0
lines changed
Open diff view settings
Collapse file
+95Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
'use strict';
2+
const common = require('../common');
3+
const assert = require('assert');
4+
const http = require('http');
5+
6+
const REQ_TIMEOUT = 500; // Set max ms of request time before abort
7+
8+
// Set total allowed test timeout to avoid infinite loop
9+
// that will hang test suite
10+
const TOTAL_TEST_TIMEOUT = 1000;
11+
12+
// Placeholder for sockets handled, to make sure that we
13+
// will reach a socket re-use case.
14+
const handledSockets = new Set();
15+
16+
let metReusedSocket = false; // Flag for request loop termination.
17+
18+
const doubleEndResponse = (res) => {
19+
// First end the request while sending some normal data
20+
res.end('regular end of request', 'utf8', common.mustCall());
21+
// Make sure the response socket is uncorked after first call of end
22+
assert.strictEqual(res.writableCorked, 0);
23+
res.end(); // Double end the response to prep for next socket re-use.
24+
};
25+
26+
const sendDrainNeedingData = (res) => {
27+
// Send data to socket more than the high watermark so that
28+
// it definitely needs drain
29+
const highWaterMark = res.socket.writableHighWaterMark;
30+
const bufferToSend = Buffer.alloc(highWaterMark + 100);
31+
const ret = res.write(bufferToSend); // Write the request data.
32+
// Make sure that we had back pressure on response stream.
33+
assert.strictEqual(ret, false);
34+
res.once('drain', () => res.end()); // End on drain.
35+
};
36+
37+
const server = http.createServer((req, res) => {
38+
const { socket: responseSocket } = res;
39+
if (handledSockets.has(responseSocket)) { // re-used socket, send big data!
40+
metReusedSocket = true; // stop request loop
41+
console.debug('FOUND REUSED SOCKET!');
42+
sendDrainNeedingData(res);
43+
} else { // not used again
44+
// add to make sure we recognise it when we meet socket again
45+
handledSockets.add(responseSocket);
46+
doubleEndResponse(res);
47+
}
48+
});
49+
50+
server.listen(0); // Start the server on a random port.
51+
52+
const sendRequest = (agent) => new Promise((resolve, reject) => {
53+
const timeout = setTimeout(common.mustNotCall(() => {
54+
reject(new Error('Request timed out'));
55+
}), REQ_TIMEOUT);
56+
http.get({
57+
port: server.address().port,
58+
path: '/',
59+
agent
60+
}, common.mustCall((res) => {
61+
const resData = [];
62+
res.on('data', (data) => resData.push(data));
63+
res.on('end', common.mustCall(() => {
64+
const totalData = resData.reduce((total, elem) => total + elem.length, 0);
65+
clearTimeout(timeout); // Cancel rejection timeout.
66+
resolve(totalData); // fulfill promise
67+
}));
68+
}));
69+
});
70+
71+
server.once('listening', async () => {
72+
const testTimeout = setTimeout(common.mustNotCall(() => {
73+
console.error('Test running for a while but could not met re-used socket');
74+
process.exit(1);
75+
}), TOTAL_TEST_TIMEOUT);
76+
// Explicitly start agent to force socket reuse.
77+
const agent = new http.Agent({ keepAlive: true });
78+
// Start the request loop
79+
let reqNo = 0;
80+
while (!metReusedSocket) {
81+
try {
82+
console.log(`Sending req no ${++reqNo}`);
83+
const totalData = await sendRequest(agent);
84+
console.log(`${totalData} bytes were received for request ${reqNo}`);
85+
} catch (err) {
86+
console.error(err);
87+
process.exit(1);
88+
}
89+
}
90+
// Successfully tested conditions and ended loop
91+
clearTimeout(testTimeout);
92+
console.log('Closing server');
93+
agent.destroy();
94+
server.close();
95+
});
Collapse file

‎test/parallel/test-http-outgoing-end-multiple.js‎

Copy file name to clipboardExpand all lines: test/parallel/test-http-outgoing-end-multiple.js
+3Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,15 @@ const http = require('http');
55

66
const server = http.createServer(common.mustCall(function(req, res) {
77
res.end('testing ended state', common.mustCall());
8+
assert.strictEqual(res.writableCorked, 0);
89
res.end(common.mustCall());
10+
assert.strictEqual(res.writableCorked, 0);
911
res.on('finish', common.mustCall(() => {
1012
res.end(common.mustCall((err) => {
1113
assert.strictEqual(err.code, 'ERR_STREAM_ALREADY_FINISHED');
1214
server.close();
1315
}));
16+
assert.strictEqual(res.writableCorked, 0);
1417
}));
1518
}));
1619

0 commit comments

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