11cb0ef41Sopenharmony_ci'use strict';
21cb0ef41Sopenharmony_ci// Flags: --expose-internals
31cb0ef41Sopenharmony_ci
41cb0ef41Sopenharmony_ciconst common = require('../common');
51cb0ef41Sopenharmony_ciconst assert = require('assert');
61cb0ef41Sopenharmony_ci
71cb0ef41Sopenharmony_ciif (!common.hasCrypto)
81cb0ef41Sopenharmony_ci  common.skip('missing crypto');
91cb0ef41Sopenharmony_ci
101cb0ef41Sopenharmony_ciconst h2 = require('http2');
111cb0ef41Sopenharmony_ciconst net = require('net');
121cb0ef41Sopenharmony_ciconst { NghttpError } = require('internal/http2/util');
131cb0ef41Sopenharmony_ciconst h2test = require('../common/http2');
141cb0ef41Sopenharmony_cilet client;
151cb0ef41Sopenharmony_ci
161cb0ef41Sopenharmony_ciconst server = h2.createServer();
171cb0ef41Sopenharmony_cilet gotFirstStreamId1;
181cb0ef41Sopenharmony_ciserver.on('stream', common.mustCall((stream) => {
191cb0ef41Sopenharmony_ci  stream.respond();
201cb0ef41Sopenharmony_ci  stream.end('ok');
211cb0ef41Sopenharmony_ci
221cb0ef41Sopenharmony_ci  // Http2Server should be fast enough to respond to and close
231cb0ef41Sopenharmony_ci  // the first streams with ID 1 and ID 3 without errors.
241cb0ef41Sopenharmony_ci
251cb0ef41Sopenharmony_ci  // Test for errors in 'close' event to ensure no errors on some streams.
261cb0ef41Sopenharmony_ci  stream.on('error', () => {});
271cb0ef41Sopenharmony_ci  stream.on('close', (err) => {
281cb0ef41Sopenharmony_ci    if (stream.id === 1) {
291cb0ef41Sopenharmony_ci      if (gotFirstStreamId1) {
301cb0ef41Sopenharmony_ci        // We expect our outgoing frames to fail on Stream ID 1 the second time
311cb0ef41Sopenharmony_ci        // because a stream with ID 1 was already closed before.
321cb0ef41Sopenharmony_ci        common.expectsError({
331cb0ef41Sopenharmony_ci          constructor: NghttpError,
341cb0ef41Sopenharmony_ci          code: 'ERR_HTTP2_ERROR',
351cb0ef41Sopenharmony_ci          message: 'Stream was already closed or invalid'
361cb0ef41Sopenharmony_ci        });
371cb0ef41Sopenharmony_ci        return;
381cb0ef41Sopenharmony_ci      }
391cb0ef41Sopenharmony_ci      gotFirstStreamId1 = true;
401cb0ef41Sopenharmony_ci    }
411cb0ef41Sopenharmony_ci    assert.strictEqual(err, undefined);
421cb0ef41Sopenharmony_ci  });
431cb0ef41Sopenharmony_ci
441cb0ef41Sopenharmony_ci  // Stream ID 5 should never reach the server
451cb0ef41Sopenharmony_ci  assert.notStrictEqual(stream.id, 5);
461cb0ef41Sopenharmony_ci
471cb0ef41Sopenharmony_ci}, 2));
481cb0ef41Sopenharmony_ci
491cb0ef41Sopenharmony_ciserver.on('session', common.mustCall((session) => {
501cb0ef41Sopenharmony_ci  session.on('error', common.expectsError({
511cb0ef41Sopenharmony_ci    code: 'ERR_HTTP2_ERROR',
521cb0ef41Sopenharmony_ci    constructor: NghttpError,
531cb0ef41Sopenharmony_ci    message: 'Stream was already closed or invalid'
541cb0ef41Sopenharmony_ci  }));
551cb0ef41Sopenharmony_ci}));
561cb0ef41Sopenharmony_ci
571cb0ef41Sopenharmony_ciconst settings = new h2test.SettingsFrame();
581cb0ef41Sopenharmony_ciconst settingsAck = new h2test.SettingsFrame(true);
591cb0ef41Sopenharmony_ci// HeadersFrame(id, payload, padding, END_STREAM)
601cb0ef41Sopenharmony_ciconst id1 = new h2test.HeadersFrame(1, h2test.kFakeRequestHeaders, 0, true);
611cb0ef41Sopenharmony_ciconst id3 = new h2test.HeadersFrame(3, h2test.kFakeRequestHeaders, 0, true);
621cb0ef41Sopenharmony_ciconst id5 = new h2test.HeadersFrame(5, h2test.kFakeRequestHeaders, 0, true);
631cb0ef41Sopenharmony_ci
641cb0ef41Sopenharmony_ciserver.listen(0, () => {
651cb0ef41Sopenharmony_ci  client = net.connect(server.address().port, () => {
661cb0ef41Sopenharmony_ci    client.write(h2test.kClientMagic, () => {
671cb0ef41Sopenharmony_ci      client.write(settings.data, () => {
681cb0ef41Sopenharmony_ci        client.write(settingsAck.data);
691cb0ef41Sopenharmony_ci        // Stream ID 1 frame will make it OK.
701cb0ef41Sopenharmony_ci        client.write(id1.data, () => {
711cb0ef41Sopenharmony_ci          // Stream ID 3 frame will make it OK.
721cb0ef41Sopenharmony_ci          client.write(id3.data, () => {
731cb0ef41Sopenharmony_ci            // A second Stream ID 1 frame should fail.
741cb0ef41Sopenharmony_ci            // This will cause an error to occur because the client is
751cb0ef41Sopenharmony_ci            // attempting to reuse an already closed stream. This must
761cb0ef41Sopenharmony_ci            // cause the server session to be torn down.
771cb0ef41Sopenharmony_ci            client.write(id1.data, () => {
781cb0ef41Sopenharmony_ci              // This Stream ID 5 frame will never make it to the server
791cb0ef41Sopenharmony_ci              client.write(id5.data);
801cb0ef41Sopenharmony_ci            });
811cb0ef41Sopenharmony_ci          });
821cb0ef41Sopenharmony_ci        });
831cb0ef41Sopenharmony_ci      });
841cb0ef41Sopenharmony_ci    });
851cb0ef41Sopenharmony_ci  });
861cb0ef41Sopenharmony_ci
871cb0ef41Sopenharmony_ci  // An error may or may not be emitted on the client side, we don't care
881cb0ef41Sopenharmony_ci  // either way if it is, but we don't want to die if it is.
891cb0ef41Sopenharmony_ci  client.on('error', () => {});
901cb0ef41Sopenharmony_ci  client.on('close', common.mustCall(() => server.close()));
911cb0ef41Sopenharmony_ci  client.resume();
921cb0ef41Sopenharmony_ci});
93