• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1'use strict';
2const common = require('../common');
3if (!common.hasCrypto)
4  common.skip('missing crypto');
5
6const assert = require('assert');
7const http2 = require('http2');
8const net = require('net');
9
10// Verify that creating a number of invalid HTTP/2 streams will
11// result in the peer closing the session within maxSessionInvalidFrames
12// frames.
13
14const maxSessionInvalidFrames = 100;
15const server = http2.createServer({ maxSessionInvalidFrames });
16server.on('stream', (stream) => {
17  stream.respond({
18    'content-type': 'text/plain',
19    ':status': 200
20  });
21  stream.end('Hello, world!\n');
22});
23
24server.listen(0, () => {
25  const h2header = Buffer.alloc(9);
26  const conn = net.connect(server.address().port);
27
28  conn.write('PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n');
29
30  h2header[3] = 4;  // Send a settings frame.
31  conn.write(Buffer.from(h2header));
32
33  let inbuf = Buffer.alloc(0);
34  let state = 'settingsHeader';
35  let settingsFrameLength;
36  conn.on('data', (chunk) => {
37    inbuf = Buffer.concat([inbuf, chunk]);
38    switch (state) {
39      case 'settingsHeader':
40        if (inbuf.length < 9) return;
41        settingsFrameLength = inbuf.readIntBE(0, 3);
42        inbuf = inbuf.slice(9);
43        state = 'readingSettings';
44        // Fallthrough
45      case 'readingSettings':
46        if (inbuf.length < settingsFrameLength) return;
47        inbuf = inbuf.slice(settingsFrameLength);
48        h2header[3] = 4;  // Send a settings ACK.
49        h2header[4] = 1;
50        conn.write(Buffer.from(h2header));
51        state = 'ignoreInput';
52        writeRequests();
53    }
54  });
55
56  let gotError = false;
57  let streamId = 1;
58  let reqCount = 0;
59
60  function writeRequests() {
61    for (let i = 1; i < 10 && !gotError; i++) {
62      h2header[3] = 1;  // HEADERS
63      h2header[4] = 0x5;  // END_HEADERS|END_STREAM
64      h2header.writeIntBE(1, 0, 3);  // Length: 1
65      h2header.writeIntBE(streamId, 5, 4);  // Stream ID
66      streamId += 2;
67      // 0x88 = :status: 200
68      if (!conn.write(Buffer.concat([h2header, Buffer.from([0x88])]))) {
69        break;
70      }
71      reqCount++;
72    }
73    // Timeout requests to slow down the rate so we get more accurate reqCount.
74    if (!gotError)
75      setTimeout(writeRequests, 10);
76  }
77
78  conn.once('error', common.mustCall(() => {
79    gotError = true;
80    assert.ok(Math.abs(reqCount - maxSessionInvalidFrames) < 100,
81              `Request count (${reqCount}) must be around (±100)` +
82      ` maxSessionInvalidFrames option (${maxSessionInvalidFrames})`);
83    conn.destroy();
84    server.close();
85  }));
86});
87