1'use strict'; 2const common = require('../common'); 3if (!common.hasCrypto) 4 common.skip('missing crypto'); 5const assert = require('assert'); 6const fixtures = require('../common/fixtures'); 7const fs = require('fs'); 8const http2 = require('http2'); 9const path = require('path'); 10 11const tmpdir = require('../common/tmpdir'); 12tmpdir.refresh(); 13 14// This test assesses whether long-running writes can complete 15// or timeout because the session or stream are not aware that the 16// backing stream is still writing. 17// To simulate a slow client, we write a really large chunk and 18// then proceed through the following cycle: 19// 1) Receive first 'data' event and record currently written size 20// 2) Once we've read up to currently written size recorded above, 21// we pause the stream and wait longer than the server timeout 22// 3) Socket.prototype._onTimeout triggers and should confirm 23// that the backing stream is still active and writing 24// 4) Our timer fires, we resume the socket and start at 1) 25 26const writeSize = 3000000; 27const minReadSize = 500000; 28const serverTimeout = common.platformTimeout(500); 29let offsetTimeout = common.platformTimeout(100); 30let didReceiveData = false; 31 32const content = Buffer.alloc(writeSize, 0x44); 33const filepath = path.join(tmpdir.path, 'http2-large-write.tmp'); 34fs.writeFileSync(filepath, content, 'binary'); 35const fd = fs.openSync(filepath, 'r'); 36 37const server = http2.createSecureServer({ 38 key: fixtures.readKey('agent1-key.pem'), 39 cert: fixtures.readKey('agent1-cert.pem') 40}); 41server.on('stream', common.mustCall((stream) => { 42 stream.respondWithFD(fd, { 43 'Content-Type': 'application/octet-stream', 44 'Content-Length': content.length.toString(), 45 'Vary': 'Accept-Encoding' 46 }); 47 stream.end(); 48})); 49server.setTimeout(serverTimeout); 50server.on('timeout', () => { 51 assert.ok(!didReceiveData, 'Should not timeout'); 52}); 53 54server.listen(0, common.mustCall(() => { 55 const client = http2.connect(`https://localhost:${server.address().port}`, 56 { rejectUnauthorized: false }); 57 58 const req = client.request({ ':path': '/' }); 59 req.end(); 60 61 const resume = () => req.resume(); 62 let receivedBufferLength = 0; 63 let firstReceivedAt; 64 req.on('data', common.mustCallAtLeast((buf) => { 65 if (receivedBufferLength === 0) { 66 didReceiveData = false; 67 firstReceivedAt = Date.now(); 68 } 69 receivedBufferLength += buf.length; 70 if (receivedBufferLength >= minReadSize && 71 receivedBufferLength < writeSize) { 72 didReceiveData = true; 73 receivedBufferLength = 0; 74 req.pause(); 75 setTimeout( 76 resume, 77 serverTimeout + offsetTimeout - (Date.now() - firstReceivedAt) 78 ); 79 offsetTimeout = 0; 80 } 81 }, 1)); 82 req.on('end', common.mustCall(() => { 83 client.close(); 84 server.close(); 85 })); 86})); 87