'use strict'; const common = require('../common'); if (!common.hasCrypto) common.skip('missing crypto'); const assert = require('assert'); const fixtures = require('../common/fixtures'); const fs = require('fs'); const http2 = require('http2'); const path = require('path'); const tmpdir = require('../common/tmpdir'); tmpdir.refresh(); // This test assesses whether long-running writes can complete // or timeout because the session or stream are not aware that the // backing stream is still writing. // To simulate a slow client, we write a really large chunk and // then proceed through the following cycle: // 1) Receive first 'data' event and record currently written size // 2) Once we've read up to currently written size recorded above, // we pause the stream and wait longer than the server timeout // 3) Socket.prototype._onTimeout triggers and should confirm // that the backing stream is still active and writing // 4) Our timer fires, we resume the socket and start at 1) const writeSize = 3000000; const minReadSize = 500000; const serverTimeout = common.platformTimeout(500); let offsetTimeout = common.platformTimeout(100); let didReceiveData = false; const content = Buffer.alloc(writeSize, 0x44); const filepath = path.join(tmpdir.path, 'http2-large-write.tmp'); fs.writeFileSync(filepath, content, 'binary'); const fd = fs.openSync(filepath, 'r'); const server = http2.createSecureServer({ key: fixtures.readKey('agent1-key.pem'), cert: fixtures.readKey('agent1-cert.pem') }); server.on('stream', common.mustCall((stream) => { stream.respondWithFD(fd, { 'Content-Type': 'application/octet-stream', 'Content-Length': content.length.toString(), 'Vary': 'Accept-Encoding' }); stream.end(); })); server.setTimeout(serverTimeout); server.on('timeout', () => { assert.ok(!didReceiveData, 'Should not timeout'); }); server.listen(0, common.mustCall(() => { const client = http2.connect(`https://localhost:${server.address().port}`, { rejectUnauthorized: false }); const req = client.request({ ':path': '/' }); req.end(); const resume = () => req.resume(); let receivedBufferLength = 0; let firstReceivedAt; req.on('data', common.mustCallAtLeast((buf) => { if (receivedBufferLength === 0) { didReceiveData = false; firstReceivedAt = Date.now(); } receivedBufferLength += buf.length; if (receivedBufferLength >= minReadSize && receivedBufferLength < writeSize) { didReceiveData = true; receivedBufferLength = 0; req.pause(); setTimeout( resume, serverTimeout + offsetTimeout - (Date.now() - firstReceivedAt) ); offsetTimeout = 0; } }, 1)); req.on('end', common.mustCall(() => { client.close(); server.close(); })); }));