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'); 36process.on('beforeExit', () => fs.closeSync(fd)); 37 38const server = http2.createSecureServer({ 39 key: fixtures.readKey('agent1-key.pem'), 40 cert: fixtures.readKey('agent1-cert.pem') 41}); 42server.on('stream', common.mustCall((stream) => { 43 stream.respondWithFD(fd, { 44 'Content-Type': 'application/octet-stream', 45 'Content-Length': content.length.toString(), 46 'Vary': 'Accept-Encoding' 47 }); 48 stream.end(); 49})); 50server.setTimeout(serverTimeout); 51server.on('timeout', () => { 52 assert.ok(!didReceiveData, 'Should not timeout'); 53}); 54 55server.listen(0, common.mustCall(() => { 56 const client = http2.connect(`https://localhost:${server.address().port}`, 57 { rejectUnauthorized: false }); 58 59 const req = client.request({ ':path': '/' }); 60 req.end(); 61 62 const resume = () => req.resume(); 63 let receivedBufferLength = 0; 64 let firstReceivedAt; 65 req.on('data', common.mustCallAtLeast((buf) => { 66 if (receivedBufferLength === 0) { 67 didReceiveData = false; 68 firstReceivedAt = Date.now(); 69 } 70 receivedBufferLength += buf.length; 71 if (receivedBufferLength >= minReadSize && 72 receivedBufferLength < writeSize) { 73 didReceiveData = true; 74 receivedBufferLength = 0; 75 req.pause(); 76 setTimeout( 77 resume, 78 serverTimeout + offsetTimeout - (Date.now() - firstReceivedAt) 79 ); 80 offsetTimeout = 0; 81 } 82 }, 1)); 83 req.on('end', common.mustCall(() => { 84 client.close(); 85 server.close(); 86 })); 87})); 88