diff options
Diffstat (limited to 'test/parallel/test-http2-max-invalid-frames.js')
-rw-r--r-- | test/parallel/test-http2-max-invalid-frames.js | 86 |
1 files changed, 86 insertions, 0 deletions
diff --git a/test/parallel/test-http2-max-invalid-frames.js b/test/parallel/test-http2-max-invalid-frames.js new file mode 100644 index 0000000000..597bd8e811 --- /dev/null +++ b/test/parallel/test-http2-max-invalid-frames.js @@ -0,0 +1,86 @@ +'use strict'; +const common = require('../common'); +if (!common.hasCrypto) + common.skip('missing crypto'); + +const assert = require('assert'); +const http2 = require('http2'); +const net = require('net'); + +// Verify that creating a number of invalid HTTP/2 streams will +// result in the peer closing the session within maxSessionInvalidFrames +// frames. + +const maxSessionInvalidFrames = 100; +const server = http2.createServer({ maxSessionInvalidFrames }); +server.on('stream', (stream) => { + stream.respond({ + 'content-type': 'text/plain', + ':status': 200 + }); + stream.end('Hello, world!\n'); +}); + +server.listen(0, () => { + const h2header = Buffer.alloc(9); + const conn = net.connect(server.address().port); + + conn.write('PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n'); + + h2header[3] = 4; // Send a settings frame. + conn.write(Buffer.from(h2header)); + + let inbuf = Buffer.alloc(0); + let state = 'settingsHeader'; + let settingsFrameLength; + conn.on('data', (chunk) => { + inbuf = Buffer.concat([inbuf, chunk]); + switch (state) { + case 'settingsHeader': + if (inbuf.length < 9) return; + settingsFrameLength = inbuf.readIntBE(0, 3); + inbuf = inbuf.slice(9); + state = 'readingSettings'; + // Fallthrough + case 'readingSettings': + if (inbuf.length < settingsFrameLength) return; + inbuf = inbuf.slice(settingsFrameLength); + h2header[3] = 4; // Send a settings ACK. + h2header[4] = 1; + conn.write(Buffer.from(h2header)); + state = 'ignoreInput'; + writeRequests(); + } + }); + + let gotError = false; + let streamId = 1; + let reqCount = 0; + + function writeRequests() { + for (let i = 1; i < 10 && !gotError; i++) { + h2header[3] = 1; // HEADERS + h2header[4] = 0x5; // END_HEADERS|END_STREAM + h2header.writeIntBE(1, 0, 3); // Length: 1 + h2header.writeIntBE(streamId, 5, 4); // Stream ID + streamId += 2; + // 0x88 = :status: 200 + if (!conn.write(Buffer.concat([h2header, Buffer.from([0x88])]))) { + break; + } + reqCount++; + } + // Timeout requests to slow down the rate so we get more accurate reqCount. + if (!gotError) + setTimeout(writeRequests, 10); + } + + conn.once('error', common.mustCall(() => { + gotError = true; + assert.ok(Math.abs(reqCount - maxSessionInvalidFrames) < 100, + `Request count (${reqCount}) must be around (±100)` + + ` maxSessionInvalidFrames option (${maxSessionInvalidFrames})`); + conn.destroy(); + server.close(); + })); +}); |