11cb0ef41Sopenharmony_ci'use strict';
21cb0ef41Sopenharmony_ciconst common = require('../common');
31cb0ef41Sopenharmony_ciif (!common.hasCrypto)
41cb0ef41Sopenharmony_ci  common.skip('missing crypto');
51cb0ef41Sopenharmony_ci
61cb0ef41Sopenharmony_ciconst assert = require('assert');
71cb0ef41Sopenharmony_ciconst http2 = require('http2');
81cb0ef41Sopenharmony_ciconst net = require('net');
91cb0ef41Sopenharmony_ci
101cb0ef41Sopenharmony_ci// Verify that creating a number of invalid HTTP/2 streams will
111cb0ef41Sopenharmony_ci// result in the peer closing the session within maxSessionInvalidFrames
121cb0ef41Sopenharmony_ci// frames.
131cb0ef41Sopenharmony_ci
141cb0ef41Sopenharmony_ciconst maxSessionInvalidFrames = 100;
151cb0ef41Sopenharmony_ciconst server = http2.createServer({ maxSessionInvalidFrames });
161cb0ef41Sopenharmony_ciserver.on('stream', (stream) => {
171cb0ef41Sopenharmony_ci  stream.respond({
181cb0ef41Sopenharmony_ci    'content-type': 'text/plain',
191cb0ef41Sopenharmony_ci    ':status': 200
201cb0ef41Sopenharmony_ci  });
211cb0ef41Sopenharmony_ci  stream.end('Hello, world!\n');
221cb0ef41Sopenharmony_ci});
231cb0ef41Sopenharmony_ci
241cb0ef41Sopenharmony_ciserver.listen(0, () => {
251cb0ef41Sopenharmony_ci  const h2header = Buffer.alloc(9);
261cb0ef41Sopenharmony_ci  const conn = net.connect({
271cb0ef41Sopenharmony_ci    port: server.address().port,
281cb0ef41Sopenharmony_ci    allowHalfOpen: true
291cb0ef41Sopenharmony_ci  });
301cb0ef41Sopenharmony_ci
311cb0ef41Sopenharmony_ci  conn.write('PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n');
321cb0ef41Sopenharmony_ci
331cb0ef41Sopenharmony_ci  h2header[3] = 4;  // Send a settings frame.
341cb0ef41Sopenharmony_ci  conn.write(Buffer.from(h2header));
351cb0ef41Sopenharmony_ci
361cb0ef41Sopenharmony_ci  let inbuf = Buffer.alloc(0);
371cb0ef41Sopenharmony_ci  let state = 'settingsHeader';
381cb0ef41Sopenharmony_ci  let settingsFrameLength;
391cb0ef41Sopenharmony_ci  conn.on('data', (chunk) => {
401cb0ef41Sopenharmony_ci    inbuf = Buffer.concat([inbuf, chunk]);
411cb0ef41Sopenharmony_ci    switch (state) {
421cb0ef41Sopenharmony_ci      case 'settingsHeader':
431cb0ef41Sopenharmony_ci        if (inbuf.length < 9) return;
441cb0ef41Sopenharmony_ci        settingsFrameLength = inbuf.readIntBE(0, 3);
451cb0ef41Sopenharmony_ci        inbuf = inbuf.slice(9);
461cb0ef41Sopenharmony_ci        state = 'readingSettings';
471cb0ef41Sopenharmony_ci        // Fallthrough
481cb0ef41Sopenharmony_ci      case 'readingSettings':
491cb0ef41Sopenharmony_ci        if (inbuf.length < settingsFrameLength) return;
501cb0ef41Sopenharmony_ci        inbuf = inbuf.slice(settingsFrameLength);
511cb0ef41Sopenharmony_ci        h2header[3] = 4;  // Send a settings ACK.
521cb0ef41Sopenharmony_ci        h2header[4] = 1;
531cb0ef41Sopenharmony_ci        conn.write(Buffer.from(h2header));
541cb0ef41Sopenharmony_ci        state = 'ignoreInput';
551cb0ef41Sopenharmony_ci        writeRequests();
561cb0ef41Sopenharmony_ci    }
571cb0ef41Sopenharmony_ci  });
581cb0ef41Sopenharmony_ci
591cb0ef41Sopenharmony_ci  let gotError = false;
601cb0ef41Sopenharmony_ci  let streamId = 1;
611cb0ef41Sopenharmony_ci  let reqCount = 0;
621cb0ef41Sopenharmony_ci
631cb0ef41Sopenharmony_ci  function writeRequests() {
641cb0ef41Sopenharmony_ci    for (let i = 1; i < 10 && !gotError; i++) {
651cb0ef41Sopenharmony_ci      h2header[3] = 1;  // HEADERS
661cb0ef41Sopenharmony_ci      h2header[4] = 0x5;  // END_HEADERS|END_STREAM
671cb0ef41Sopenharmony_ci      h2header.writeIntBE(1, 0, 3);  // Length: 1
681cb0ef41Sopenharmony_ci      h2header.writeIntBE(streamId, 5, 4);  // Stream ID
691cb0ef41Sopenharmony_ci      streamId += 2;
701cb0ef41Sopenharmony_ci      // 0x88 = :status: 200
711cb0ef41Sopenharmony_ci      if (!conn.write(Buffer.concat([h2header, Buffer.from([0x88])]))) {
721cb0ef41Sopenharmony_ci        break;
731cb0ef41Sopenharmony_ci      }
741cb0ef41Sopenharmony_ci      reqCount++;
751cb0ef41Sopenharmony_ci    }
761cb0ef41Sopenharmony_ci    // Timeout requests to slow down the rate so we get more accurate reqCount.
771cb0ef41Sopenharmony_ci    if (!gotError)
781cb0ef41Sopenharmony_ci      setTimeout(writeRequests, 10);
791cb0ef41Sopenharmony_ci  }
801cb0ef41Sopenharmony_ci
811cb0ef41Sopenharmony_ci  conn.once('error', common.mustCall(() => {
821cb0ef41Sopenharmony_ci    gotError = true;
831cb0ef41Sopenharmony_ci    assert.ok(Math.abs(reqCount - maxSessionInvalidFrames) < 100,
841cb0ef41Sopenharmony_ci              `Request count (${reqCount}) must be around100)` +
851cb0ef41Sopenharmony_ci      ` maxSessionInvalidFrames option (${maxSessionInvalidFrames})`);
861cb0ef41Sopenharmony_ci    conn.destroy();
871cb0ef41Sopenharmony_ci    server.close();
881cb0ef41Sopenharmony_ci  }));
891cb0ef41Sopenharmony_ci});
90