11cb0ef41Sopenharmony_ci'use strict'; 21cb0ef41Sopenharmony_ciconst common = require('../common'); 31cb0ef41Sopenharmony_ciconst assert = require('assert'); 41cb0ef41Sopenharmony_ciconst http = require('http'); 51cb0ef41Sopenharmony_ci 61cb0ef41Sopenharmony_ciconst REQ_TIMEOUT = 500; // Set max ms of request time before abort 71cb0ef41Sopenharmony_ci 81cb0ef41Sopenharmony_ci// Set total allowed test timeout to avoid infinite loop 91cb0ef41Sopenharmony_ci// that will hang test suite 101cb0ef41Sopenharmony_ciconst TOTAL_TEST_TIMEOUT = 1000; 111cb0ef41Sopenharmony_ci 121cb0ef41Sopenharmony_ci// Placeholder for sockets handled, to make sure that we 131cb0ef41Sopenharmony_ci// will reach a socket re-use case. 141cb0ef41Sopenharmony_ciconst handledSockets = new Set(); 151cb0ef41Sopenharmony_ci 161cb0ef41Sopenharmony_cilet metReusedSocket = false; // Flag for request loop termination. 171cb0ef41Sopenharmony_ci 181cb0ef41Sopenharmony_ciconst doubleEndResponse = (res) => { 191cb0ef41Sopenharmony_ci // First end the request while sending some normal data 201cb0ef41Sopenharmony_ci res.end('regular end of request', 'utf8', common.mustCall()); 211cb0ef41Sopenharmony_ci // Make sure the response socket is uncorked after first call of end 221cb0ef41Sopenharmony_ci assert.strictEqual(res.writableCorked, 0); 231cb0ef41Sopenharmony_ci res.end(); // Double end the response to prep for next socket re-use. 241cb0ef41Sopenharmony_ci}; 251cb0ef41Sopenharmony_ci 261cb0ef41Sopenharmony_ciconst sendDrainNeedingData = (res) => { 271cb0ef41Sopenharmony_ci // Send data to socket more than the high watermark so that 281cb0ef41Sopenharmony_ci // it definitely needs drain 291cb0ef41Sopenharmony_ci const highWaterMark = res.socket.writableHighWaterMark; 301cb0ef41Sopenharmony_ci const bufferToSend = Buffer.alloc(highWaterMark + 100); 311cb0ef41Sopenharmony_ci const ret = res.write(bufferToSend); // Write the request data. 321cb0ef41Sopenharmony_ci // Make sure that we had back pressure on response stream. 331cb0ef41Sopenharmony_ci assert.strictEqual(ret, false); 341cb0ef41Sopenharmony_ci res.once('drain', () => res.end()); // End on drain. 351cb0ef41Sopenharmony_ci}; 361cb0ef41Sopenharmony_ci 371cb0ef41Sopenharmony_ciconst server = http.createServer((req, res) => { 381cb0ef41Sopenharmony_ci const { socket: responseSocket } = res; 391cb0ef41Sopenharmony_ci if (handledSockets.has(responseSocket)) { // re-used socket, send big data! 401cb0ef41Sopenharmony_ci metReusedSocket = true; // stop request loop 411cb0ef41Sopenharmony_ci console.debug('FOUND REUSED SOCKET!'); 421cb0ef41Sopenharmony_ci sendDrainNeedingData(res); 431cb0ef41Sopenharmony_ci } else { // not used again 441cb0ef41Sopenharmony_ci // add to make sure we recognise it when we meet socket again 451cb0ef41Sopenharmony_ci handledSockets.add(responseSocket); 461cb0ef41Sopenharmony_ci doubleEndResponse(res); 471cb0ef41Sopenharmony_ci } 481cb0ef41Sopenharmony_ci}); 491cb0ef41Sopenharmony_ci 501cb0ef41Sopenharmony_ciserver.listen(0); // Start the server on a random port. 511cb0ef41Sopenharmony_ci 521cb0ef41Sopenharmony_ciconst sendRequest = (agent) => new Promise((resolve, reject) => { 531cb0ef41Sopenharmony_ci const timeout = setTimeout(common.mustNotCall(() => { 541cb0ef41Sopenharmony_ci reject(new Error('Request timed out')); 551cb0ef41Sopenharmony_ci }), REQ_TIMEOUT); 561cb0ef41Sopenharmony_ci http.get({ 571cb0ef41Sopenharmony_ci port: server.address().port, 581cb0ef41Sopenharmony_ci path: '/', 591cb0ef41Sopenharmony_ci agent 601cb0ef41Sopenharmony_ci }, common.mustCall((res) => { 611cb0ef41Sopenharmony_ci const resData = []; 621cb0ef41Sopenharmony_ci res.on('data', (data) => resData.push(data)); 631cb0ef41Sopenharmony_ci res.on('end', common.mustCall(() => { 641cb0ef41Sopenharmony_ci const totalData = resData.reduce((total, elem) => total + elem.length, 0); 651cb0ef41Sopenharmony_ci clearTimeout(timeout); // Cancel rejection timeout. 661cb0ef41Sopenharmony_ci resolve(totalData); // fulfill promise 671cb0ef41Sopenharmony_ci })); 681cb0ef41Sopenharmony_ci })); 691cb0ef41Sopenharmony_ci}); 701cb0ef41Sopenharmony_ci 711cb0ef41Sopenharmony_ciserver.once('listening', async () => { 721cb0ef41Sopenharmony_ci const testTimeout = setTimeout(common.mustNotCall(() => { 731cb0ef41Sopenharmony_ci console.error('Test running for a while but could not met re-used socket'); 741cb0ef41Sopenharmony_ci process.exit(1); 751cb0ef41Sopenharmony_ci }), TOTAL_TEST_TIMEOUT); 761cb0ef41Sopenharmony_ci // Explicitly start agent to force socket reuse. 771cb0ef41Sopenharmony_ci const agent = new http.Agent({ keepAlive: true }); 781cb0ef41Sopenharmony_ci // Start the request loop 791cb0ef41Sopenharmony_ci let reqNo = 0; 801cb0ef41Sopenharmony_ci while (!metReusedSocket) { 811cb0ef41Sopenharmony_ci try { 821cb0ef41Sopenharmony_ci console.log(`Sending req no ${++reqNo}`); 831cb0ef41Sopenharmony_ci const totalData = await sendRequest(agent); 841cb0ef41Sopenharmony_ci console.log(`${totalData} bytes were received for request ${reqNo}`); 851cb0ef41Sopenharmony_ci } catch (err) { 861cb0ef41Sopenharmony_ci console.error(err); 871cb0ef41Sopenharmony_ci process.exit(1); 881cb0ef41Sopenharmony_ci } 891cb0ef41Sopenharmony_ci } 901cb0ef41Sopenharmony_ci // Successfully tested conditions and ended loop 911cb0ef41Sopenharmony_ci clearTimeout(testTimeout); 921cb0ef41Sopenharmony_ci console.log('Closing server'); 931cb0ef41Sopenharmony_ci agent.destroy(); 941cb0ef41Sopenharmony_ci server.close(); 951cb0ef41Sopenharmony_ci}); 96