11cb0ef41Sopenharmony_ci'use strict';
21cb0ef41Sopenharmony_ci
31cb0ef41Sopenharmony_ciconst common = require('../common');
41cb0ef41Sopenharmony_ciconst fixtures = require('../common/fixtures');
51cb0ef41Sopenharmony_ci
61cb0ef41Sopenharmony_ciif (!common.hasCrypto)
71cb0ef41Sopenharmony_ci  common.skip('missing crypto');
81cb0ef41Sopenharmony_ci
91cb0ef41Sopenharmony_ciconst { strictEqual, ok } = require('assert');
101cb0ef41Sopenharmony_ciconst { createSecureContext } = require('tls');
111cb0ef41Sopenharmony_ciconst { createSecureServer, connect } = require('http2');
121cb0ef41Sopenharmony_ciconst { get } = require('https');
131cb0ef41Sopenharmony_ciconst { parse } = require('url');
141cb0ef41Sopenharmony_ciconst { connect: tls } = require('tls');
151cb0ef41Sopenharmony_ciconst { Duplex } = require('stream');
161cb0ef41Sopenharmony_ci
171cb0ef41Sopenharmony_ciconst countdown = (count, done) => () => --count === 0 && done();
181cb0ef41Sopenharmony_ci
191cb0ef41Sopenharmony_ciconst key = fixtures.readKey('agent8-key.pem');
201cb0ef41Sopenharmony_ciconst cert = fixtures.readKey('agent8-cert.pem');
211cb0ef41Sopenharmony_ciconst ca = fixtures.readKey('fake-startcom-root-cert.pem');
221cb0ef41Sopenharmony_ci
231cb0ef41Sopenharmony_ciconst clientOptions = { secureContext: createSecureContext({ ca }) };
241cb0ef41Sopenharmony_ci
251cb0ef41Sopenharmony_cifunction onRequest(request, response) {
261cb0ef41Sopenharmony_ci  const { socket: { alpnProtocol } } = request.httpVersion === '2.0' ?
271cb0ef41Sopenharmony_ci    request.stream.session : request;
281cb0ef41Sopenharmony_ci  response.writeHead(200, { 'content-type': 'application/json' });
291cb0ef41Sopenharmony_ci  response.end(JSON.stringify({
301cb0ef41Sopenharmony_ci    alpnProtocol,
311cb0ef41Sopenharmony_ci    httpVersion: request.httpVersion
321cb0ef41Sopenharmony_ci  }));
331cb0ef41Sopenharmony_ci}
341cb0ef41Sopenharmony_ci
351cb0ef41Sopenharmony_cifunction onSession(session, next) {
361cb0ef41Sopenharmony_ci  const headers = {
371cb0ef41Sopenharmony_ci    ':path': '/',
381cb0ef41Sopenharmony_ci    ':method': 'GET',
391cb0ef41Sopenharmony_ci    ':scheme': 'https',
401cb0ef41Sopenharmony_ci    ':authority': `localhost:${this.server.address().port}`
411cb0ef41Sopenharmony_ci  };
421cb0ef41Sopenharmony_ci
431cb0ef41Sopenharmony_ci  const request = session.request(headers);
441cb0ef41Sopenharmony_ci  request.on('response', common.mustCall((headers) => {
451cb0ef41Sopenharmony_ci    strictEqual(headers[':status'], 200);
461cb0ef41Sopenharmony_ci    strictEqual(headers['content-type'], 'application/json');
471cb0ef41Sopenharmony_ci  }));
481cb0ef41Sopenharmony_ci  request.setEncoding('utf8');
491cb0ef41Sopenharmony_ci  let raw = '';
501cb0ef41Sopenharmony_ci  request.on('data', (chunk) => { raw += chunk; });
511cb0ef41Sopenharmony_ci  request.on('end', common.mustCall(() => {
521cb0ef41Sopenharmony_ci    const { alpnProtocol, httpVersion } = JSON.parse(raw);
531cb0ef41Sopenharmony_ci    strictEqual(alpnProtocol, 'h2');
541cb0ef41Sopenharmony_ci    strictEqual(httpVersion, '2.0');
551cb0ef41Sopenharmony_ci
561cb0ef41Sopenharmony_ci    session.close();
571cb0ef41Sopenharmony_ci    this.cleanup();
581cb0ef41Sopenharmony_ci
591cb0ef41Sopenharmony_ci    if (typeof next === 'function') {
601cb0ef41Sopenharmony_ci      next();
611cb0ef41Sopenharmony_ci    }
621cb0ef41Sopenharmony_ci  }));
631cb0ef41Sopenharmony_ci  request.end();
641cb0ef41Sopenharmony_ci}
651cb0ef41Sopenharmony_ci
661cb0ef41Sopenharmony_ci// HTTP/2 & HTTP/1.1 server
671cb0ef41Sopenharmony_ci{
681cb0ef41Sopenharmony_ci  const server = createSecureServer(
691cb0ef41Sopenharmony_ci    { cert, key, allowHTTP1: true },
701cb0ef41Sopenharmony_ci    common.mustCall(onRequest, 2)
711cb0ef41Sopenharmony_ci  );
721cb0ef41Sopenharmony_ci
731cb0ef41Sopenharmony_ci  server.listen(0);
741cb0ef41Sopenharmony_ci
751cb0ef41Sopenharmony_ci  server.on('listening', common.mustCall(() => {
761cb0ef41Sopenharmony_ci    const { port } = server.address();
771cb0ef41Sopenharmony_ci    const origin = `https://localhost:${port}`;
781cb0ef41Sopenharmony_ci
791cb0ef41Sopenharmony_ci    const cleanup = countdown(2, () => server.close());
801cb0ef41Sopenharmony_ci
811cb0ef41Sopenharmony_ci    // HTTP/2 client
821cb0ef41Sopenharmony_ci    connect(
831cb0ef41Sopenharmony_ci      origin,
841cb0ef41Sopenharmony_ci      clientOptions,
851cb0ef41Sopenharmony_ci      common.mustCall(onSession.bind({ cleanup, server }))
861cb0ef41Sopenharmony_ci    );
871cb0ef41Sopenharmony_ci
881cb0ef41Sopenharmony_ci    // HTTP/1.1 client
891cb0ef41Sopenharmony_ci    get(
901cb0ef41Sopenharmony_ci      Object.assign(parse(origin), clientOptions),
911cb0ef41Sopenharmony_ci      common.mustCall((response) => {
921cb0ef41Sopenharmony_ci        strictEqual(response.statusCode, 200);
931cb0ef41Sopenharmony_ci        strictEqual(response.statusMessage, 'OK');
941cb0ef41Sopenharmony_ci        strictEqual(response.headers['content-type'], 'application/json');
951cb0ef41Sopenharmony_ci
961cb0ef41Sopenharmony_ci        response.setEncoding('utf8');
971cb0ef41Sopenharmony_ci        let raw = '';
981cb0ef41Sopenharmony_ci        response.on('data', (chunk) => { raw += chunk; });
991cb0ef41Sopenharmony_ci        response.on('end', common.mustCall(() => {
1001cb0ef41Sopenharmony_ci          const { alpnProtocol, httpVersion } = JSON.parse(raw);
1011cb0ef41Sopenharmony_ci          strictEqual(alpnProtocol, false);
1021cb0ef41Sopenharmony_ci          strictEqual(httpVersion, '1.1');
1031cb0ef41Sopenharmony_ci
1041cb0ef41Sopenharmony_ci          cleanup();
1051cb0ef41Sopenharmony_ci        }));
1061cb0ef41Sopenharmony_ci      })
1071cb0ef41Sopenharmony_ci    );
1081cb0ef41Sopenharmony_ci  }));
1091cb0ef41Sopenharmony_ci}
1101cb0ef41Sopenharmony_ci
1111cb0ef41Sopenharmony_ci// HTTP/2-only server
1121cb0ef41Sopenharmony_ci{
1131cb0ef41Sopenharmony_ci  const server = createSecureServer(
1141cb0ef41Sopenharmony_ci    { cert, key },
1151cb0ef41Sopenharmony_ci    common.mustCall(onRequest)
1161cb0ef41Sopenharmony_ci  );
1171cb0ef41Sopenharmony_ci
1181cb0ef41Sopenharmony_ci  server.once('unknownProtocol', common.mustCall((socket) => {
1191cb0ef41Sopenharmony_ci    strictEqual(socket instanceof Duplex, true);
1201cb0ef41Sopenharmony_ci    socket.destroy();
1211cb0ef41Sopenharmony_ci  }));
1221cb0ef41Sopenharmony_ci
1231cb0ef41Sopenharmony_ci  server.listen(0);
1241cb0ef41Sopenharmony_ci
1251cb0ef41Sopenharmony_ci  server.on('listening', common.mustCall(() => {
1261cb0ef41Sopenharmony_ci    const { port } = server.address();
1271cb0ef41Sopenharmony_ci    const origin = `https://localhost:${port}`;
1281cb0ef41Sopenharmony_ci
1291cb0ef41Sopenharmony_ci    const cleanup = countdown(3, () => server.close());
1301cb0ef41Sopenharmony_ci
1311cb0ef41Sopenharmony_ci    // HTTP/2 client
1321cb0ef41Sopenharmony_ci    connect(
1331cb0ef41Sopenharmony_ci      origin,
1341cb0ef41Sopenharmony_ci      clientOptions,
1351cb0ef41Sopenharmony_ci      common.mustCall(function(session) {
1361cb0ef41Sopenharmony_ci        onSession.call({ cleanup, server },
1371cb0ef41Sopenharmony_ci                       session,
1381cb0ef41Sopenharmony_ci                       common.mustCall(testNoTls));
1391cb0ef41Sopenharmony_ci      })
1401cb0ef41Sopenharmony_ci    );
1411cb0ef41Sopenharmony_ci
1421cb0ef41Sopenharmony_ci    function testNoTls() {
1431cb0ef41Sopenharmony_ci      // HTTP/1.1 client
1441cb0ef41Sopenharmony_ci      get(Object.assign(parse(origin), clientOptions), common.mustNotCall())
1451cb0ef41Sopenharmony_ci        .on('error', common.mustCall(cleanup))
1461cb0ef41Sopenharmony_ci        .on('error', common.mustCall(testWrongALPN))
1471cb0ef41Sopenharmony_ci        .end();
1481cb0ef41Sopenharmony_ci    }
1491cb0ef41Sopenharmony_ci
1501cb0ef41Sopenharmony_ci    function testWrongALPN() {
1511cb0ef41Sopenharmony_ci      // Incompatible ALPN TLS client
1521cb0ef41Sopenharmony_ci      let text = '';
1531cb0ef41Sopenharmony_ci      tls(Object.assign({ port, ALPNProtocols: ['fake'] }, clientOptions))
1541cb0ef41Sopenharmony_ci        .setEncoding('utf8')
1551cb0ef41Sopenharmony_ci        .on('data', (chunk) => text += chunk)
1561cb0ef41Sopenharmony_ci        .on('end', common.mustCall(() => {
1571cb0ef41Sopenharmony_ci          ok(/Unknown ALPN Protocol, expected `h2` to be available/.test(text));
1581cb0ef41Sopenharmony_ci          cleanup();
1591cb0ef41Sopenharmony_ci        }));
1601cb0ef41Sopenharmony_ci    }
1611cb0ef41Sopenharmony_ci  }));
1621cb0ef41Sopenharmony_ci}
163