1'use strict'; 2const common = require('../common'); 3if (!common.hasCrypto) 4 common.skip('missing crypto'); 5 6const http2 = require('http2'); 7const net = require('net'); 8const { Worker, parentPort } = require('worker_threads'); 9 10// Verify that creating a number of invalid HTTP/2 streams will eventually 11// result in the peer closing the session. 12// This test uses separate threads for client and server to avoid 13// the two event loops intermixing, as we are writing in a busy loop here. 14 15if (process.env.HAS_STARTED_WORKER) { 16 const server = http2.createServer({ maxSessionInvalidFrames: 100 }); 17 server.on('stream', (stream) => { 18 stream.respond({ 19 'content-type': 'text/plain', 20 ':status': 200 21 }); 22 stream.end('Hello, world!\n'); 23 }); 24 server.listen(0, () => parentPort.postMessage(server.address().port)); 25 return; 26} 27 28process.env.HAS_STARTED_WORKER = 1; 29const worker = new Worker(__filename).on('message', common.mustCall((port) => { 30 const h2header = Buffer.alloc(9); 31 const conn = net.connect({ port, allowHalfOpen: true }); 32 33 conn.write('PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n'); 34 35 h2header[3] = 4; // Send a settings frame. 36 conn.write(Buffer.from(h2header)); 37 38 let inbuf = Buffer.alloc(0); 39 let state = 'settingsHeader'; 40 let settingsFrameLength; 41 conn.on('data', (chunk) => { 42 inbuf = Buffer.concat([inbuf, chunk]); 43 switch (state) { 44 case 'settingsHeader': 45 if (inbuf.length < 9) return; 46 settingsFrameLength = inbuf.readIntBE(0, 3); 47 inbuf = inbuf.slice(9); 48 state = 'readingSettings'; 49 // Fallthrough 50 case 'readingSettings': 51 if (inbuf.length < settingsFrameLength) return; 52 inbuf = inbuf.slice(settingsFrameLength); 53 h2header[3] = 4; // Send a settings ACK. 54 h2header[4] = 1; 55 conn.write(Buffer.from(h2header)); 56 state = 'ignoreInput'; 57 writeRequests(); 58 } 59 }); 60 61 let gotError = false; 62 let streamId = 1; 63 64 function writeRequests() { 65 for (let i = 1; i < 10 && !gotError; i++) { 66 h2header[3] = 1; // HEADERS 67 h2header[4] = 0x5; // END_HEADERS|END_STREAM 68 h2header.writeIntBE(1, 0, 3); // Length: 1 69 h2header.writeIntBE(streamId, 5, 4); // Stream ID 70 streamId += 2; 71 // 0x88 = :status: 200 72 if (!conn.write(Buffer.concat([h2header, Buffer.from([0x88])]))) { 73 break; 74 } 75 } 76 if (!gotError) 77 setImmediate(writeRequests); 78 } 79 80 conn.once('error', common.mustCall(() => { 81 gotError = true; 82 worker.terminate(); 83 conn.destroy(); 84 })); 85})); 86